Decide who may authorize the operation
Bind each attempt to its initiating session, target account, and exact operation or resource before authentication. If the account already has a linked World ID, require the validated(iss, sub) to match. If the account is unlinked, enroll
the validated identity only when the saved attempt explicitly permits enrollment.
Some operations may accept any qualifying human or a user with a specific role.
Define the required assurance and eligibility, and whether a different identity
is allowed. Test both acceptance and rejection against that authorization policy.
Implement step-up
-
Save the pending operation. Record the current application account,
its linked World ID
(iss, sub)if present, whether this attempt may enroll an identity, the required authentication age and class, and the pending operation in server-side state. Bind a fresh OAuthstate,nonce, and PKCE verifier to this attempt. Keep the operation pending until all checks pass. -
Request fresh authentication. Redirect to the authorization endpoint with the
usual browser authentication
parameters plus
max_age=0for fresh authentication, or a positivemax_agefor a maximum authentication age. For example, these additional decoded query fields require fresh Orb-class authentication:A successful result has the Orb class. The person can authenticate with an Orb proof or an enrolled passkey for an Orb-verified account. Validate the returnedacragainst the requested class. To require a fresh proof with Face Auth, use the essential Face Auth request withmax_age=0. -
Validate the result. Validate the callback
state, redeem the code once, and validate the ID token, including its nonce. Reconfirm that the initiating session and target account match the saved attempt. For a linked account, require the returned(iss, sub)to match. For an unlinked account, continue only when the attempt explicitly permits enrollment and the identity is not linked elsewhere. Defer storing the pair until the remaining checks pass. -
Check freshness and assurance. Validate
acr,amr, andauth_timeagainst the saved policy. Formax_age=N, check the authentication age when the operation runs, allowing only a small, explicit clock tolerance and rejecting implausibly future timestamps. Formax_age=0, check that authentication belongs to the newly initiated attempt (using its start time, nonce, and bounded lifetime); do not require its age to remain literally zero during the browser round trip. -
Allow the operation. After all checks pass, atomically save the validated
(iss, sub)for enrollment if needed, but only while the target account is still unlinked and the identity is still unassigned. Then update your trusted session or grant’s assurance, recheck permissions and any transaction-specific approval, and allow the intended operation. Cancellation, expiry, changed binding, identity mismatch, unsupported assurance, and dependency failure leave the operation unauthorized.
Request parameters
Validate the returnedacr, amr, and auth_time against the saved policy.
See class and method definitions
for the values and their guarantees.
Step-up uses the same registered client, scope=openid, state, and S256 PKCE
requirements as browser authentication,
at the authorization endpoint from the
OIDC discovery document. The
protocol permits omitting nonce; the step-up procedure above uses it to bind the
result to the attempt.
Omit
prompt for normal interactive fallback. The supported values are login,
none, and consent, supplied individually. consent forces the interactive
authorization page. select_account and prompt combinations are rejected.
Use an interactive request when you require fresh authentication.
Accept Orb or Selfie Check
To require Orb or Selfie Check verification, add theclaims query parameter
to your OIDC authorization request. Set its value to the following JSON and have
your OIDC library URL-encode it:
claims.id_token.acr request takes precedence over acr_values.
After validating the ID token, require its acr to match one of your saved
acceptable values exactly. Essential requests treat each class as a distinct
value. List every class you accept, including any -face variants.
These baseline classes can also be satisfied by a passkey on a verified account.
They do not require a new credential proof or face check. Add max_age=0 for
fresh authentication and check amr for the method used. To require a face
check with either credential, use the same essential request with
https://world.org/oidc/acr/orb-face and
https://world.org/oidc/acr/selfie-face, plus max_age=0.
See Credentials and authentication classes
for the differences in assurance. Omitting a class request uses the client’s
accepted accounts. Any account also admits accounts
without Orb or Selfie Check, so use explicit classes when verification is required.
Require Face Auth
To require Face Auth in the World ID app, send this JSON as the URL-encodedclaims parameter:
max_age=0 for a check during this browser authentication attempt. Without a
freshness requirement, a qualifying Face Auth session can be reused.
https://world.org/oidc/acr/selfie-face requires the same check on a Selfie Check
proof and follows the same rules.
acr_values=https://world.org/oidc/acr/orb-face requests Face Auth whenever a
new proof is created. Unlike an essential claims request, it permits reuse of
a baseline browser session and acceptance of a baseline result. When listing
multiple acr_values, put your preferred class first; the first supported class
determines whether a new proof requires Face Auth.
If none of the requested essential classes is supported, the request fails with
unmet_authentication_requirements. The RP must still validate the returned acr.
When passkeys are enabled, requests offer authentication with an enrolled passkey
first unless their first supported class is https://world.org/oidc/acr/orb-face or
https://world.org/oidc/acr/selfie-face. A passkey login reports the account’s class,
https://world.org/oidc/acr/orb or, for a Selfie Check account,
https://world.org/oidc/acr/selfie, but never a face check class. Check
amr to see whether a World ID proof or a passkey authenticated the person. Add
max_age=0 when authentication must be fresh for this browser attempt.
The device authorization endpoint accepts the same acr_values and claims
parameters as extensions to its RFC 8628 profile. Device authentication always
requires fresh authentication; prompt and max_age do not control this grant. If the
mobile response cannot satisfy an essential requirement, token polling returns
access_denied, never a downgraded token.
A requested claims.id_token.sub value must match the authenticating account.
A mismatch ends the request with access_denied, including device token polling.
Reference: OIDC ACR requests.
Accepted accounts
A request with neitheracr_values nor an acr claim request uses the
client’s registered classes as its acr_values. This is useful when your OIDC
library or identity broker cannot add acr_values.
Choose the accepted accounts when you create an application in the
developer portal. To change them, open the application and go
to Settings → Authenticate → Default accepted accounts:
- Orb: accounts verified at an Orb.
- Selfie Check: accounts verified with Selfie Check or at an Orb. The login offers Selfie Check first.
- Any account: every World ID account. Accounts with Orb or Selfie Check
verification still receive their class in
acr; ID tokens for accounts without either omitacr.
acr claim request accepts only the classes it lists.
To accept any account for one request, including accounts without Orb or Selfie
Check verification, send this decoded claims parameter:
acr when available. Tokens
for accounts without verification still omit acr. An empty acr_values uses
the client’s defaults.
Ask for Face Auth adds a face check in the World ID app to each new proof.
It adds a step for people, and they can’t authenticate with a passkey. It is a
preference: an eligible browser session can still be reused. To require Face
Auth, send an essential acr claim.
Human checkpoints
Pause the agent workflow, complete the step-up procedure, and resume only after your backend accepts the authentication, checks permissions, and confirms any action approval required by your policy. This works with your existing sign-in or World ID as your primary sign-in.Optional: collect action approval in your application
Save the exact action, version, destination, owning account, and expiry, bound to the authentication attempt. After validating the account and assurance, show the saved action to the user and record their approval or denial. At execution, recheck permissions, expiry, freshness, and approval, and authorize only that version. Changes require new approval. Denial, cancellation, failed validation, or expiry leaves the action blocked. Apply the one-use and retry rules. Formax_age=0, authentication belongs to the newly initiated attempt. Enforce
your application’s freshness window when the action runs, including time spent
reviewing it.
For headless clients, follow the Device Authorization Grant.
Your backend issues their API or MCP credentials. Where supported, use the
challenge and retry flow.
Prevent stale or duplicate operations
- Save what the user is approving. When authentication starts, save the operation, target account, authentication requirements, and expiry. Do not change them. If the operation or target changes, start again. Checking status or retrying must not extend the expiry.
- Check again before acting. Verify that the session, account, World ID, and permissions still match the saved attempt. Reject an attempt that is outdated, cancelled, or expired.
- Use an approval once. Mark the approval as used in the same database transaction that authorizes or reserves the operation. A cancellation blocks the operation only if it is saved first; it cannot undo an operation that already happened.
- Revoke access in your application. Check expiry and revocation before each use. Ending World IdP’s browser session, deleting the OIDC client, rotating credentials, revoking an MCP grant, or closing a browser tab does not revoke access stored by your application.
- Reconcile external requests before retrying. Give each external operation a stable ID. After a timeout or lost response, ask the external service whether it completed the operation. Retry with the same ID only if the service guarantees that duplicates cannot run twice. If you cannot determine the result, keep the operation blocked and investigate.
Through your auth server
The chain is: application or agent → your auth server → World IdP → your auth server → your protected operation. Each layer must preserve the requirement.- Start a new upstream request. Your auth server must start a new OIDC authorization request with World IdP for each attempt. Its existing session must not bypass the upstream freshness check.
- Forward the parameters. Pass
max_ageand any requestedprompt=login,acr_values, andclaimsparameters tohttps://auth.world.org/api/v1/authorize. A setting on only the outer login request is insufficient if the connector drops it. - Keep World IdP’s result. Your auth server must validate and retain
World IdP’s
auth_time,acr,amr, and account binding. Convey the result to the resource through trusted server state or your own signed token claims. A login, password or MFA event at your auth server, MCP consent, OAuth refresh, or new downstream token does not prove a fresh World ID authentication. - Enforce at the resource. If your auth server cannot propagate or validate the requirement, this integration cannot provide World ID step-up.
auth_time, and remain blocked when the
human cancels or uses the wrong account.