World ID

Sign In with Worldcoin

To better serve all classes of applications, World ID can now be used as an OpenID Connect Provider (Identity Provider, IdP, OP). We support many of the same integrations that developers are already familiar with (Auth0, Cloudflare, etc.). The following diagram outlines the general authentication flow for an integrating app:

A diagram showcasing the main authentication flow

If your app already supports OIDC, simply add our discovery document as an authentication option. You can read more about our implementation under the /authorize and /token headings.

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 "code"

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. Request details can be found below.

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...')

Custom Sign In

Since all technologies associated with World ID are open source, you can implement your own hosted version of IDKit to redirect your users to. Advanced API details for this implementation can be found below.

OpenID Connect discovery

GET/.well-known/openid-configuration

Fetches the OpenID Connect discovery document.

Common Errors

  • method_not_allowed: HTTP method is not allowed. Only GET and OPTIONS may be used

Request

GET
/.well-known/openid-configuration
curl https://id.worldcoin.org/.well-known/openid-configuration

Response

{
    "issuer": "https://id.worldcoin.org",
    "authorization_endpoint": "https://id.worldcoin.org/authorize",
    "token_endpoint": "https://id.worldcoin.org/token",
    "userinfo_endpoint": "https://id.worldcoin.org/userinfo",
    "registration_endpoint": "https://id.worldcoin.org/register",
    "jwks_uri": "https://id.worldcoin.org/jwks",
    "scopes_supported": ["openid", "email", "profile"],
    "response_types_supported": ["code", "id_token", "id_token token", "code id_token"],
    "grant_types_supported": ["authorization_code", "implicit"],
    "subject_types_supported": ["pairwise"],
    "id_token_signing_alg_values_supported": ["RSA"]
}

Register App

POST/register

Registers a new application for use with Sign In with World ID.

Required attributes

  • Name
    redirect_uris
    Type
    string
    Description

    URLs the user will be redirected to after authentication. Must be HTTPS, and can always be updated in the Developer Portal.

Optional attributes

  • Name
    client_name
    Type
    string
    Description

    Name of the application. This is displayed to the user during authentication.

  • Name
    logo_uri
    Type
    string
    Description

    URL to the application's logo. This is displayed to the user during authentication.

  • Name
    application_type
    Type
    string
    Description

    Type of application. Can be either web or mobile. Defaults to web.

  • Name
    grant_types
    Type
    string
    Description

    Grant types the application is allowed to use. Can be either authorization_code, implicit, hybrid. Defaults to authorization_code.

Common Errors

  • method_not_allowed: HTTP method is not allowed. Only POST and OPTIONS may be used
  • required: A necessary attribute was not set. Required attributes are: redirect_uris
  • invalid_redirect_uri: The provided redirect URI is invalid, either HTTPS was not used or the URL was malformed

Request

POST
/register
curl -X POST https://id.worldcoin.org/register \
    -H "Content-Type: application/json" \
    -d '{
        "client_name": "Example Application",
        "logo_uri": "https://app.example.com/logo.svg",
        "redirect_uris": ["https://app.example.com/callback", "https://app.example.com/redirect"],
        "application_type": "web",
        "grant_types": "authorization_code",
        "response_types": "code"
    }'

Response

{
    "application_type": "web",
    "client_id": "app_staging_7550e829082fc558e112e0620c1c7a59",
    "client_id_issued_at": "2023-03-09T00:58:52.5011+00:00",
    "client_name": "Example Application",
    "client_secret": "sk_6a2ff697607b77d641fbb10101b7636f3e6c750f2aac3652",
    "client_secret_expires_at": 0,
    "grant_types": "authorization_code",
    "logo_uri": "https://app.example.com/logo.svg",
    "response_types": "code"
}

Generate Credentials

POST/authorize

Generate credentials from a World ID zero-knowledge proof (for use with IDKit).

Required attributes

  • Name
    app_id
    Type
    string
    Description

    The application ID of the application requesting credentials.

  • Name
    response_type
    Type
    string
    Description

    The type of response to return. Can be any combination of code, token, and id_token.

  • Name
    scope
    Type
    string
    Description

    Comma-separated list of scopes to request. Only openid is supported, but profile and email are available for legacy reasons.

  • Name
    nonce
    Type
    string
    Description

    A random string used to prevent replay attacks.

  • Name
    nullifier_hash
    Type
    string
    Description

    The unique user identifier (also the sub). Unique for each app. As returned by IDKit.

  • Name
    proof
    Type
    string
    Description

    The Zero-Knowledge proof (ZKP), as returned by IDKit.

  • Name
    merkle_root
    Type
    string
    Description

    Part of the ZKP, as returned by IDKit.

  • Name
    credential_type
    Type
    string
    Description

    The type of credential this proof is for. Can be either orb or phone.

Common Errors

  • method_not_allowed: HTTP method is not allowed. Only POST and OPTIONS may be used
  • required: A necessary attribute was not set. Required attributes are: proof, nullifier_hash, merkle_root, credential_type, and app_id
  • invalid - credential_type: The provided credential type is invalid, only orb and phone are supported
  • invalid - response_type: The provided response type is invalid, may use any combination of code, token, and id_token
  • error - app_id: There was an error fetching the given app_id, try checking the value
  • invalid_proof: The returned identity proof was invalid, please wait before trying again

Request

POST
/authorize
curl -X POST https://id.worldcoin.org/authorize \
  -H "Content-Type: application/json" \
  -d '{
    "app_id": "app_staging_7550e829082fc558e112e0620c1c7a59",
    "response_type": "code id_token",
    "scope": "openid email profile",
    "nonce": "1234567890",
    "nullifier_hash": "0x2ae86d6d747702b3b2c81811cd2b39875e8fa6b780ee4a207bdc203a7860b535",
    "proof": "0x051df7bb69be13ca1f6406e39c02bf5c8ddf710bd91aba675bf70e28f188e1092b5659...",
    "merkle_root": "0x09c2cc6add86f7f38a8f5b1ce0046c7d28bd54588054f37f9904561453aaab51",
    "credential_type": "orb"
  }'

Response

{
	"code": "23e5edda0f731dfdddace390",
	"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Imp3a18yZmViZjY3MDc3N2UyY2NlNzY5YzUxOGM3..."
}

Exchange Code

POST/token

Exchanges an authorization code for an id_token for the given user.

Required attributes

  • Name
    code
    Type
    string
    Description

    The authorization code to exchange.

  • Name
    grant_type
    Type
    string
    Description

    The type of grant to exchange. Must be authorization_code.

Common Errors

  • method_not_allowed: HTTP method is not allowed. Only POST and OPTIONS may be used
  • invalid_content_type: The provided content type is invalid, only application/x-www-form-urlencoded is supported
  • unauthenticated: The provided authorization token is invalid, try checking your credentials
  • invalid_grant_type: The provided grant type is invalid, only authorization_code is supported
  • required: A necessary attribute was not set. Required attributes are: code
  • invalid_grant: The authorization code was invalid, and may be expired. Try generating a new code via /authorize

Request

POST
/token
curl -X POST https://id.worldcoin.org/token \
     -H "Authorization: Basic YXBwXzU1MGU4MjkwODJmYzU1OGUxMTJlMDYyMGMxYzdhNT..." \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "code=23e5edda0f731dfdddace390&grant_type=authorization_code"

Response

{
	"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Imp3a1.ey8yZmVi.ZjY3MDc3N2UyY2NlNzY5YzUxOG...",
	"token_type": "Bearer",
	"expires_in": 3600,
	"scope": "openid",
	"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6Imp3a1.ey8yZmVi.ZjY3MDc3N2UyY2NlNzY5YzUxOG..."
}

Introspect

POST/introspect

Validates the given access token is active for the user.

For introspect, Basic Authentication is used. The Authorization header contains the word "Basic ", followed by a base64 encoding of the "client_id:client_secret" values returned from the /register endpoint.

Required attributes

  • Name
    token
    Type
    string
    Description

    The access token to validate.

Common Errors

  • method_not_allowed: HTTP method is not allowed. Only POST may be used
  • invalid_content_type: The provided content type is invalid, only application/x-www-form-urlencoded is supported
  • required: A necessary attribute was not set. Required attributes are: token
  • unauthenticated: The authorization header is missing, please pass the Bearer authorization token
  • invalid_token: The authorization token was invalid, and may be expired. Try generating a new token via /token

Request

POST
/introspect
curl -X POST https://id.worldcoin.org/introspect \
  -H "Authorization: Basic YXBwXzU1MGU4MjkwODJmYzU1OGUxMTJlMDYyMGMxYzdhNT..." \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "token=eyJhbGciOiJSUzI1NiIsImtpZCI6Imp3a18yZmViZjY3MDc3N2UyY2NlNzY5YzUxOGM3MDNkNTNjMStN..."

Response

{
	"active": true,
	"client_id": "app_staging_7550e829082fc558e112e0620c1c7a59",
	"exp": 1678330528,
	"sub": "0x2ae86d6d747702b3b2c81811cd2b39875e8fa6b780ee4a207bdc203a7860b535"
}

Get User Info

POST/userinfo

Retrieves all user information, based on the approved scopes, with the given access token.

For userinfo, Bearer Authentication is used. The Authorization header contains the word "Bearer ", followed by the access token returned from the /token endpoint.

Common Errors

  • method_not_allowed: HTTP method is not allowed. Only GET, POST, and OPTIONS may be used
  • unauthenticated: The authorization header is missing, please pass the Bearer authorization token
  • invalid_token: The authorization token was invalid, and may be expired. Try generating a new token via /token

Request

POST
/userinfo
curl -X POST https://id.worldcoin.org/userinfo \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZ.eyCI6I.mp3a18yZmViZjY3MDc3N2UyY2NlN..."

Response

{
	"sub": "0x2ae86d6d747702b3b2c81811cd2b39875e8fa6b780ee4a207bdc203a7860b535",
	"https://id.worldcoin.org/beta": {
		"likely_human": "strong",
		"credential_type": "orb"
	},
	"email": "0x2ae86d6d747702b3b2c81811cd2b39875e8fa6b780ee4a207bdc203a7860b535@id.worldcoin.org",
	"name": "World ID User",
	"given_name": "World ID",
	"family_name": "User"
}