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:
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:
- Create a new application on the Developer Portal
- 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 userslogo_url
: Optional, the logo of the application that's displayed to usersapplication_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 tokenstate
: 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
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
Fetches the OpenID Connect discovery document.
Common Errors
method_not_allowed
: HTTP method is not allowed. Only GET and OPTIONS may be used
Request
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
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
ormobile
. Defaults toweb
.
- Name
grant_types
- Type
- string
- Description
Grant types the application is allowed to use. Can be either
authorization_code
,implicit
,hybrid
. Defaults toauthorization_code
.
Common Errors
method_not_allowed
: HTTP method is not allowed. Only POST and OPTIONS may be usedrequired
: 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
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
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
, andid_token
.
- Name
scope
- Type
- string
- Description
Comma-separated list of scopes to request. Only
openid
is supported, butprofile
andemail
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
orphone
.
Common Errors
method_not_allowed
: HTTP method is not allowed. Only POST and OPTIONS may be usedrequired
: A necessary attribute was not set. Required attributes are:proof
,nullifier_hash
,merkle_root
,credential_type
, andapp_id
invalid - credential_type
: The provided credential type is invalid, onlyorb
andphone
are supportedinvalid - response_type
: The provided response type is invalid, may use any combination ofcode
,token
, andid_token
error - app_id
: There was an error fetching the givenapp_id
, try checking the valueinvalid_proof
: The returned identity proof was invalid, please wait before trying again
Request
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
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 usedinvalid_content_type
: The provided content type is invalid, onlyapplication/x-www-form-urlencoded
is supportedunauthenticated
: The provided authorization token is invalid, try checking your credentialsinvalid_grant_type
: The provided grant type is invalid, onlyauthorization_code
is supportedrequired
: 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
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
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 usedinvalid_content_type
: The provided content type is invalid, onlyapplication/x-www-form-urlencoded
is supportedrequired
: A necessary attribute was not set. Required attributes are:token
unauthenticated
: The authorization header is missing, please pass the Bearer authorization tokeninvalid_token
: The authorization token was invalid, and may be expired. Try generating a new token via/token
Request
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
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 usedunauthenticated
: The authorization header is missing, please pass the Bearer authorization tokeninvalid_token
: The authorization token was invalid, and may be expired. Try generating a new token via/token
Request
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"
}