Choose this when
Use this path when your product or identity middleware needs a standards-based OpenID Connect integration with Lamba.
Use OIDC if you are configuring:
- a web app with Authorization Code + PKCE
- a backend callback that exchanges authorization codes
- an identity middleware that reads discovery metadata
- token validation and JWKS caching
- branded issuer domains later
Before you start
Create an App Client for the Project and environment you are integrating. Public clients must use PKCE. Confidential clients can exchange tokens server-side with a client secret.
Public hosts:
| Environment | Issuer / auth host | Customer API host |
|---|---|---|
| Sandbox | https://test.id.uselamba.com | https://test.api.uselamba.com |
| Production | https://id.uselamba.com | https://api.uselamba.com |
Get credentials from Console
| Value | Console source | Env var | Used for |
|---|---|---|---|
| Issuer | Environment badge plus auth host | LAMBA_OIDC_ISSUER | Discovery, token validation, and redirect construction |
| Client ID | Integration > App Clients > Client ID | LAMBA_CLIENT_ID | OIDC audience and OAuth client identifier |
| Client secretSecret | Integration > App Clients > Create or Rotate secret | LAMBA_CLIENT_SECRET | Confidential server-side token exchange only |
| Redirect URI | Integration > App Clients > Edit > Redirect URIs | LAMBA_REDIRECT_URI | Exact callback URL registered for the client |
| Workspace and Project IDs | Top Workspace / Project selector | LAMBA_WORKSPACE_ID and LAMBA_PROJECT_ID | Customer API session exchange after OIDC login |
Configure environment variables
LAMBA_OIDC_ISSUER=https://test.id.uselamba.com
LAMBA_CUSTOMER_API_BASE=https://test.api.uselamba.com
LAMBA_CLIENT_ID=<app-client-id>
LAMBA_CLIENT_SECRET=<confidential-client-secret-if-used>
LAMBA_REDIRECT_URI=http://localhost:3000/auth/callback
LAMBA_WORKSPACE_ID=<workspace-id>
LAMBA_PROJECT_ID=<project-id>
LAMBA_ENV=test
Make the first request
Start with discovery. Your OIDC library should read this document and use its endpoint values instead of hardcoding token and JWKS URLs.
https://test.id.uselamba.com/.well-known/openid-configuration- Auth
- None
- Used for
- Finds issuer, authorize, token, userinfo, and JWKS endpoints
curl -s https://test.id.uselamba.com/.well-known/openid-configuration
The public token endpoint is /connect/token, and public JWKS is exposed at /.well-known/jwks.json through the discovery document.
Then send users through Authorization Code + PKCE.
GET https://test.id.uselamba.com/connect/authorize
?response_type=code
&client_id=<app-client-id>
&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fcallback
&scope=openid%20profile%20email
&code_challenge=<base64url-sha256>
&code_challenge_method=S256
&state=<opaque-state>
&nonce=<opaque-nonce>
Exchange the code:
await fetch(`${process.env.LAMBA_OIDC_ISSUER}/connect/token`, {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: process.env.LAMBA_CLIENT_ID!,
code,
redirect_uri: process.env.LAMBA_REDIRECT_URI!,
code_verifier,
}),
});Request fields
Discovery has no request body. Authorization and token exchange use these fields:
| Field | Type | Required | Meaning | Notes |
|---|---|---|---|---|
client_id | string | Required | App Client ID from the selected Project. | - |
redirect_uri | URI | Required | Callback URL registered on the App Client. | No wildcards. Must match exactly. |
scope | space-separated string | Required | OIDC claims and access requested by the app. | Start with `openid profile email`. |
state | string | Required | CSRF protection value bound to the local browser session. | - |
nonce | string | Required | Replay protection value validated against the ID token. | - |
code_verifier | string | Required | Original PKCE verifier sent only to `/connect/token`. | Do not send this in the authorize URL. |
client_secret | string | Conditional | Confidential client secret for server-side exchange. | Never ship to browser or mobile public clients. |
Response fields
Discovery response fields:
| Field | Type | Required | Meaning | Notes |
|---|---|---|---|---|
issuer | URI | Required | Expected issuer for tokens from this environment or branded auth domain. | - |
authorization_endpoint | URI | Required | Where browser login starts. | - |
token_endpoint | URI | Required | Where authorization codes and refresh tokens are exchanged. | - |
userinfo_endpoint | URI | Required | OIDC user info endpoint when used by your middleware. | - |
jwks_uri | URI | Required | Public signing keys for token validation. | Cache by `kid` and refresh on unknown key once. |
Token response fields:
| Field | Type | Required | Meaning | Notes |
|---|---|---|---|---|
access_token | string | Required | Bearer token returned by the auth host. | - |
id_token | JWT | Conditional | OIDC identity token containing claims for the login. | - |
refresh_token | string | Conditional | Credential for rotating the session when issued. | - |
expires_in | number | Required | Access token lifetime in seconds. | - |
token_type | string | Required | Bearer token type. | - |
Validate tokens
Validate:
issequals the discovery issuer exactlyaudcontains your Client IDexpandnbfare valid with bounded clock skewnoncematches the original browser auth request- JWT signature validates against the discovery
jwks_uri
For branded auth domains, the expected issuer is the branded host returned by discovery, not id.uselamba.com.
Enter Customer API context
OIDC signs the user in on the auth host. The Customer API should receive a scoped customer session token after context switch.
curl -X POST "$LAMBA_OIDC_ISSUER/v1/sessions/switch-context" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"workspaceId": "<workspace-id>",
"projectId": "<project-id>",
"environment": "test"
}'
Then call:
curl "$LAMBA_CUSTOMER_API_BASE/v1/me/context" \
-H "Authorization: Bearer $CUSTOMER_SESSION_TOKEN"
Done when
Done when
- Discovery returns endpoints from the same issuer your app uses.
- Authorize requests include state, nonce, and PKCE.
- Token exchange succeeds with the matching redirect URI and verifier.
- Your app validates issuer, audience, expiry, nonce, and signature.
- Customer API calls use a scoped session returned by switch-context.
Troubleshooting
| Error | Meaning | Action |
|---|---|---|
invalid_grant | Code/verifier invalid, expired, or reused | Restart login and create a new verifier |
redirect_uri_mismatch | Redirect URI mismatch | Fix Integration > App Clients > Edit > Redirect URIs |
invalid_client | Client auth failed | Confirm Project/environment and rotate secret if needed |
| Signature validation failure | Token signature invalid | Refresh JWKS once, then fail closed |
Unknown kid | Signing key was rotated or cache is stale | Refresh jwks_uri and retry validation once |
Related docs
- Hosted Auth Integration:
/docs/quickstart/hosted-auth - OAuth/OIDC Security:
/docs/reference/oauth-oidc-security - Auth and Session Contracts:
/docs/reference/auth-session-contracts - Customer API request and response contract:
/docs/quickstart/customer-api