Skip to main content
NoResponse assesses each new account for abuse. It returns the current risk score of the account, from 0 to 100, where a higher score means more risk. It also returns a decision: allow, step_up, review or block. WorkOS already knows facts that make the score more accurate. Examples are whether the user verified the email and the ages of the account and the session. auth_context is the part of the assessment request that carries these facts. fromWorkOS is the WorkOS adapter in each NoResponse SDK. It builds auth_context from the AuthKit access token claims that you verified, and you add the facts from the WorkOS user and session records. Your backend does five things:
  1. Verifies the access token: the signature against the JWKS of your client.
  2. getUser: gets the account age and the verified email.
  3. Lists the sessions of the user: gets the session age.
  4. fromWorkOS: turns the claims and the records into auth_context.
  5. assessments.create: NoResponse returns the assessment.

What WorkOS can supply

What WorkOS cannot supply

  • A verified phone number. AuthKit users have no phone number, so phone_verified stays empty.
  • A recent second factor. The access token and the session record do not say whether the user passed MFA, or when. Leave mfa out unless a record of your own proves it.
  • The time of the last login. The access token has no auth_time. Its iat changes on every refresh, so it is not the age of the session either. session_created_at carries that age.
  • An assurance level. WorkOS has no equivalent of assurance_level.

Install

TypeScript
The samples use @workos-inc/node 11, workos 10 for Python and workos-go 4. Set three variables in the environment of your backend:
  • WORKOS_API_KEY and WORKOS_CLIENT_ID, from the API keys page of the WorkOS Dashboard.
  • NORESPONSE_API_KEY, a NoResponse key with the assess scope.
The TypeScript and Python NoResponse clients read NORESPONSE_API_KEY themselves. The Go client takes it as an argument. The quickstart tells you how to get a key.

Assess the new account

Assess each new account once. Do it on the first authenticated request for a WorkOS user that your database does not know yet. Do it before you create your own records for the account or give it access. The API answers within 3 seconds. The access token is the accessToken that AuthKit returns:
  • authenticateWithCode returns it at login.
  • loadSealedSession(...).authenticate() returns it from the session cookie.
  • withAuth() returns it in Next.js.
The samples verify the token in the same way as the WorkOS SDKs. They verify the signature against the JWKS that WorkOS publishes for your client ID, and they test the expiry. They do not test the audience or the issuer. WorkOS publishes these signing keys for your client ID only, so a valid signature already ties the token to your application.
TypeScript
ip is the public address of the client. Behind a load balancer, read it from the header that the load balancer sets, such as the last address that it appended to X-Forwarded-For. Never read it from a value that the client controls. The WorkOS user id is the account_id. It is stable, and the WorkOS API takes it when you act on the result later. The flow is account creation, so NoResponse waits up to 3000 ms for its full set of sources. To wait only for the sources that answer within 500 ms, send depth: "quick". The other sources still finish later, and their results reach you through the webhook.
Verified claims, never the tokenThe adapter takes the claims that verification gave you. It never takes the token string. It sets verified: true and transport: "backend" to say that your backend did the verification. The API refuses an auth_context that holds a token.

Act on the answer

The answer starts with assessment.account, the one current risk of the account. Your code acts on assessment.account.risk.decision, the decision for the flow that you sent:
  • allow: let the account in.
  • step_up: ask for more proof first, such as a second factor.
  • review: hold the account until your team looks at it.
  • block: refuse the account. NoResponse answers block after you set a block threshold and the score reaches it.
  • Any other value: treat it as review.
assessment.account.risk.score and assessment.account.risk.reasons tell you why. assessment.detail holds the facts of this assessment, such as its status, the sources that did not answer and the summary facts.
  • assessment.account is absent while the first assessment of the account is still pending. Apply your fallback. Then take the final assessment from the webhook when it arrives.
  • If the call fails or times out, apply the same fallback.
Turn an assessment into a decision gives a full rule set to copy.

What the adapter sends

This is the auth_context for a new user in an organization, with a verified email:
auth_context for a new user
That context fires three reasons. account.risk.reasons lists each one with its weight:
  • auth_new_session and auth_new_account raise the score for any new account.
  • auth_email_verified lowers it. It makes this account different from one with nothing verified.

Next steps

Turn an assessment into a decision

Rules for allow, step_up, review and block.

Pending, retries and idempotency

What a pending answer carries and how retries work.

Pass your auth session

Every auth_context field and the six auth reason codes.