Worldcoin

Further Reading

OIDC Explainer

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

A diagram showcasing the main authentication flow

Registration

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
  • logo_url: Optional, the logo 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 "id_token"
    • code: 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: Recommended for most applications. 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. localhost can be used on staging apps for testing, but will not work on production apps.

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

Flows

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

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:

https://id.worldcoin.org/authorize?client_id={app_id}&response_type={code|token|id_token}&redirect_uri={encoded_redirect_url}&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: https%3A%2F%2Fapp.example.com%2Flogin).
  • state: unique value used to track a user's session (example: session_102030405060708090).
  • nonce: random value to prevent replay attacks (example: z-dkEmoy_ujfk7B8uTiQpp).

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!

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 JWT.io, but one example method could be:

import * as jose from 'jose'

const verifyJwt = (token: string) => {
	const JWKS = jose.createRemoteJWKSet(new URL('https://id.worldcoin.org/jwks.json'))

	const { payload, header } = await jose.jwtVerify(token, JWKS, {
		issuer: 'https://id.worldcoin.org',
		aud: 'app_lshSNnaJfdt6Sohu6YAA',
	})

	return payload
}

verifyJwt('eyJhbGciOiJSUzI1NiIsInR5cCI6Ikp.eyAs.XVCJ9...')