OIDC Provider
Passport implements OpenID Connect 1.0 on top of OAuth 2.0 — publish a standard discovery document, register clients, and issue signed JWTs for modern web and mobile applications.
OIDC Discovery Document
Any OIDC-compliant library can auto-configure itself from Passport's discovery endpoint. This is the recommended way to integrate — the document provides all endpoints, supported scopes, signing algorithms, and claims.
GET /passport/.well-known/openid-configuration
Content-Type: application/json
{
"issuer": "https://passport.bizfirst.ai",
"authorization_endpoint": "https://passport.bizfirst.ai/passport/authorize",
"token_endpoint": "https://passport.bizfirst.ai/passport/token",
"userinfo_endpoint": "https://passport.bizfirst.ai/passport/userinfo",
"jwks_uri": "https://passport.bizfirst.ai/passport/.well-known/jwks.json",
"end_session_endpoint": "https://passport.bizfirst.ai/passport/logout",
"response_types_supported": ["code", "token", "id_token"],
"grant_types_supported": [
"authorization_code",
"refresh_token",
"client_credentials"
],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": ["RS256"],
"scopes_supported": ["openid", "profile", "email", "roles", "tenant"],
"claims_supported": [
"sub", "iss", "aud", "exp", "iat",
"email", "name", "given_name", "family_name",
"roles", "tenant_id", "permissions"
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post",
"private_key_jwt"
],
"code_challenge_methods_supported": ["S256"]
}
Client Registration
Each application that connects to Passport as an OIDC client must be registered. Registration is performed by a Passport administrator via the Admin API or the Passport Admin UI.
POST /passport/admin/clients
Authorization: Bearer {admin-token}
Content-Type: application/json
{
"clientId": "myapp-prod",
"clientName": "My Application (Production)",
"clientSecret": "generated-by-passport",
"redirectUris": [
"https://myapp.example.com/auth/callback",
"https://myapp.example.com/auth/silent-callback"
],
"postLogoutRedirectUris": [
"https://myapp.example.com/logged-out"
],
"allowedScopes": ["openid", "profile", "email", "roles"],
"grantTypes": ["authorization_code", "refresh_token"],
"requirePkce": true,
"accessTokenLifetime": 900,
"refreshTokenLifetime": 604800,
"tenantId": "tenant-abc"
}
Supported Scopes and Claims
| Scope | Claims Included | Notes |
|---|---|---|
openid | sub, iss, aud, exp, iat | Required — establishes the OIDC context |
profile | name, given_name, family_name, picture | Basic profile info |
email | email, email_verified | User's email address and verification status |
roles | roles (array) | Passport roles assigned to the user in this tenant |
tenant | tenant_id, tenant_name | Tenant context — required for multi-tenant apps |
Authorization Code Flow with PKCE
This is the recommended flow for web applications and SPAs. PKCE (Proof Key for Code Exchange) prevents authorization code interception attacks.
Generate PKCE Parameters
// Client generates code_verifier + code_challenge
const code_verifier = crypto.randomBytes(64).toString('base64url');
const code_challenge = crypto.createHash('sha256')
.update(code_verifier).digest('base64url');
Authorization Request
GET /passport/authorize
?response_type=code
&client_id=myapp-prod
&redirect_uri=https://myapp.example.com/auth/callback
&scope=openid%20profile%20email%20roles%20tenant
&state=random-csrf-state
&code_challenge=S256-hashed-verifier
&code_challenge_method=S256
User Authenticates
Passport presents the login UI. User enters credentials (or uses an existing SSO session). MFA is triggered if required by the client's policy.
Callback with Authorization Code
GET https://myapp.example.com/auth/callback
?code=authorization-code-short-lived
&state=random-csrf-state
Token Exchange
POST /passport/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=authorization-code-short-lived
&redirect_uri=https://myapp.example.com/auth/callback
&client_id=myapp-prod
&code_verifier=original-code-verifier
Token Response
{
"access_token": "eyJhbGciOiJSUzI1NiJ9...",
"id_token": "eyJhbGciOiJSUzI1NiJ9...",
"refresh_token": "opaque-refresh-token",
"token_type": "Bearer",
"expires_in": 900,
"scope": "openid profile email roles tenant"
}
id_token Structure
The id_token is a signed JWT containing the authenticated user's identity. Verify the signature using Passport's JWKS before trusting the claims.
// Header
{
"alg": "RS256",
"kid": "signing-key-id-2026",
"typ": "JWT"
}
// Payload
{
"iss": "https://passport.bizfirst.ai",
"sub": "user-guid-here",
"aud": "myapp-prod",
"exp": 1748120400,
"iat": 1748119500,
"nonce": "random-nonce-from-auth-request",
"email": "jane.smith@example.com",
"email_verified": true,
"name": "Jane Smith",
"given_name": "Jane",
"family_name": "Smith",
"roles": ["manager", "finance-user"],
"tenant_id": "tenant-abc",
"tenant_name": "Acme Corp"
}
Client Credentials Flow
For service-to-service calls (no user involved), use the client credentials grant. This is how managed identities and background services authenticate.
POST /passport/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(clientId:clientSecret)
grant_type=client_credentials
&scope=openid%20roles
// Response
{
"access_token": "eyJhbGciOiJSUzI1NiJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
Access tokens are short-lived (15 minutes by default). Refresh tokens are valid for 7 days and are rotated on each use — storing the new refresh token after each refresh is mandatory. Configure these values per client registration to match your security requirements.