OAuth API Reference

Complete reference for all OAuth 2.0 / OIDC endpoints at api.xident.io.


GET /oauth/authorize

Authorization endpoint. Redirects the user to the Xident consent screen.

Query Parameters

ParameterRequiredDescription
response_typeYesMust be code
client_idYesYour OAuth client ID (xoc_...)
redirect_uriYesMust exactly match a registered redirect URI
scopeYesSpace-separated scopes (e.g. openid profile age_verification)
stateRecommendedCSRF protection — random string returned in callback
nonceOptionalIncluded in ID token for replay protection
code_challengeYesPKCE S256 challenge: BASE64URL(SHA256(code_verifier))
code_challenge_methodYesMust be S256

Success Response

Redirects (302) to the consent screen, then to your redirect_uri:

GET https://yoursite.com/callback?code=xoac_...&state=your_state

Error Response

If the user denies consent:

GET https://yoursite.com/callback?error=access_denied&error_description=The+user+denied+the+request&state=your_state

POST /oauth/token

Token endpoint. Exchanges authorization codes for tokens or refreshes tokens.

Authorization Code Grant

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=xoac_abc123...
&redirect_uri=https://yoursite.com/callback
&client_id=xoc_your_client_id
&client_secret=xocs_your_secret
&code_verifier=your_pkce_verifier

Refresh Token Grant

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=xort_old_token...
&client_id=xoc_your_client_id
&client_secret=xocs_your_secret

Client Authentication

Two methods are supported:

  • client_secret_post — Include client_id and client_secret in the request body
  • client_secret_basic — Use HTTP Basic auth: Authorization: Basic base64(client_id:client_secret)

Success Response (200)

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "xort_new_token...",
  "id_token": "eyJhbGciOiJSUzI1NiIs...",
  "scope": "openid profile age_verification"
}

Error Response

{
  "error": "invalid_grant",
  "error_description": "authorization code has expired"
}

GET /oauth/userinfo

Returns claims about the authenticated user based on granted scopes.

Request

GET /oauth/userinfo
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...

Response (200)

{
  "sub": "account-uuid",
  "display_name": "Jane Doe",
  "email": "jane@example.com",
  "email_verified": true,
  "age_verified": true,
  "verified_brackets": ["+12", "+15", "+18"],
  "meets_threshold": {
    "12": true,
    "15": true,
    "18": true,
    "21": false,
    "25": false
  },
  "connected_sites_count": 5
}

Note: Only claims matching the granted scopes are returned. For example, if email scope was not granted, the email and email_verified fields are omitted.


POST /oauth/revoke

Revokes a token (RFC 7009). Always returns 200 even if the token is already invalid.

Request

POST /oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=xort_refresh_token...
&token_type_hint=refresh_token

Response (200)

{
  "status": "ok"
}

POST /oauth/introspect

Token introspection (RFC 7662). Requires client authentication.

Request

POST /oauth/introspect
Content-Type: application/x-www-form-urlencoded

token=eyJhbGciOiJSUzI1NiIs...
&client_id=xoc_your_client_id
&client_secret=xocs_your_secret

Active Token Response (200)

{
  "active": true,
  "scope": "openid profile",
  "client_id": "xoc_abc123",
  "sub": "account-uuid",
  "exp": 1710100000,
  "iat": 1710096400,
  "iss": "https://api.xident.io",
  "token_type": "Bearer"
}

Inactive Token Response (200)

{
  "active": false
}

GET /.well-known/openid-configuration

OIDC Discovery document. Returns metadata about the OAuth/OIDC provider.

Response (200)

{
  "issuer": "https://api.xident.io",
  "authorization_endpoint": "https://api.xident.io/oauth/authorize",
  "token_endpoint": "https://api.xident.io/oauth/token",
  "userinfo_endpoint": "https://api.xident.io/oauth/userinfo",
  "revocation_endpoint": "https://api.xident.io/oauth/revoke",
  "introspection_endpoint": "https://api.xident.io/oauth/introspect",
  "jwks_uri": "https://api.xident.io/.well-known/jwks.json",
  "scopes_supported": ["openid", "profile", "email", "age_verification", "connections"],
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_methods_supported": ["client_secret_post", "client_secret_basic"],
  "subject_types_supported": ["public"],
  "id_token_signing_alg_values_supported": ["RS256"],
  "code_challenge_methods_supported": ["S256"],
  "claims_supported": [
    "sub", "iss", "aud", "exp", "iat", "auth_time", "nonce",
    "display_name", "email", "email_verified",
    "age_verified", "verified_brackets", "meets_threshold",
    "connected_sites_count"
  ]
}

GET /.well-known/jwks.json

JSON Web Key Set containing RSA public keys for token verification. Cached for 1 hour.

Response (200)

{
  "keys": [
    {
      "kty": "RSA",
      "use": "sig",
      "alg": "RS256",
      "kid": "key-uuid-1",
      "n": "base64url-encoded-modulus...",
      "e": "AQAB"
    }
  ]
}

Returns consent session data for the portal consent screen. Used internally by the Xident portal.

Query Parameters

ParameterRequiredDescription
sessionYesConsent session ID from the authorize redirect

Response (200)

{
  "success": true,
  "data": {
    "client_name": "ExampleSite",
    "client_logo": "https://example.com/logo.png",
    "scopes": ["openid", "profile", "age_verification"],
    "redirect_uri": "https://example.com/callback"
  }
}

Error Codes

ErrorDescription
invalid_requestMissing or invalid parameter
invalid_clientClient authentication failed
invalid_grantAuthorization code or refresh token is invalid/expired
unsupported_grant_typeOnly authorization_code and refresh_token are supported
invalid_tokenAccess token is invalid or expired (UserInfo endpoint)
access_deniedUser denied consent

Rate Limits

The token endpoint (/oauth/token) is rate limited to prevent brute-force attacks against client secrets. Other OAuth endpoints use the standard API rate limits.

Need help?

Check the Getting Started guide for a step-by-step integration walkthrough, or the Security guide for best practices.