Further Reading

OIDC Explainer

The following diagram outlines the general authentication flow for an integrating app:

A diagram showcasing the main authentication flow


Before OIDC authentication can take place, developers must register their applications with Worldcoin. This is a one-time action. There are two ways to accomplish this:

  1. Create a new application on the Developer Portal.
  2. Use the /register endpoint, request body details can be found here.

During registration, you will need to provide the following values:

  • redirect_uris: Required, list of approved websites the user can be redirected to after successful authentication.
  • client_name: Optional, the name of the application that's displayed to users
  • application_type: Optional, one of "web" or "mobile". Defaults to "web"
  • grant_types: Optional, the type of flows this application will use. Can include "authorization_code", "implicit", or "hybrid". Defaults to "authorization_code"
  • response_type: Optional, the response type expected by the application. Can include any of "code", "token", or "id_token". Defaults to "code"
    • code: Recommended for most applications. The /authorize endpoint will include an authorization code that can be exchanged for an access token and/or ID token on the /token endpoint. Best suited for web/mobile applications with dedicated backends, where security is the highest priority.
    • token: The /authorize endpoint will include an access token, which can be used to fetch user information from the /userinfo and /introspect endpoints. Best suited for low-risk applications, and client-only/SPAs where a client_secret cannot be concealed.
    • id_token: The /authorize endpoint will include a signed JWT containing information about the user, including the unique sub claim (otherwise known as the nullifier hash). Provides simple user authentication, while keeping the amount of user data shared to a minimum. Best for privacy-conscious apps.

All redirect URIs must be over HTTPS, and contain no port numbers or URL fragments. For example, is valid, but is not. Similarly, is not valid, but is.

After registration is complete, you will have a valid app_id that will be needed for every other step in the authentication process. This value is equivalent to client_id from the OIDC specification


World ID supports the authorization code, implicit, and hybrid flows from the OIDC spec. Applications can use any one of these flows to authenticate users.

Generally, applications should implement the authorization code flow, as it is more secure than the implicit flow. Applications without backend servers (that may be running purely client-side) are more suited to implicit authentication.


Authentication begins with a request to the /authorize endpoint.

When using the native Sign In with Worldcoin page, most of the OIDC process is handled for you. You can begin the authentication cycle by redirecting your users to:{app_id}&response_type={code|token|id_token}&redirect_uri={encoded_redirect_url}&scope={scope}&state={state_value}&nonce={nonce_value}

Example values could be:

  • client_id: obtained from the Developer Portal or /register endpoint (example: app_lshSNnaJfdt6Sohu6YAA).
  • response_type: response type as specified in OIDC spec, remember to URL encode (example: code%20id_token).
  • redirect_uri: where the user is redirected upon successful authentication. Must be on the approved redirect URI list which can always be updated in the Developer Portal (example:
  • scope: space-separated list of scopes to request. Defaults to openid if not provided. (example: openid%20profile%20email).
  • state: unique value used to track a user's session (example: session_102030405060708090).
  • nonce: random value to prevent replay attacks (example: z-dkEmoy_ujfk7B8uTiQpp). Required when using the id_token response type.

The user will then authenticate with their World ID via the World app. Once successfully authorized, the user is redirected back to your application. The redirect URL will contain a number of values, depending on the flow you are using.

Redirect Responses

If using the default authorization code flow, the redirect URL will contain the following params:

  • code: An authorization code that can be exchanged for an ID token
  • state: The optional state value passed to the /authorize endpoint

If you received a response containing an authorization code, you must exchange it for an ID token on the /token endpoint. Request details can be seen here.

If using implicit flow, the redirect URL will contain the following params:

  • id_token: A signed JWT identifying the user, and any requested scope information
ID tokens must always be verified, and should not be blindly accepted! Additionally, you must validate that the nonce within the ID token matches the nonce you provided.

To verify an ID token, fetch the public key from the /jwks endpoint. You can read more about this process at the Auth0 blog or, but one example method could be:

import * as jose from 'jose'

const verifyJwt = (token: string) => {
	const JWKS = jose.createRemoteJWKSet(new URL(''))

	const { payload, header } = await jose.jwtVerify(token, JWKS, {
		issuer: '',
		aud: 'app_lshSNnaJfdt6Sohu6YAA',

	return payload