medusajs/medusa · error · MedusaError
The identity provider did not return an ID token; ensure the
Error message
The identity provider did not return an ID token; ensure the 'openid' scope is requested
What it means
After a successful token exchange, the engine requires an ID token (tokenSet.id_token) to extract claims. Without the openid scope the provider returns only access/refresh tokens and claims() would throw an unhelpful TypeError, so the engine fails fast with UNAUTHORIZED and an explicit hint.
Source
Thrown at packages/modules/providers/auth-oidc/src/engine/engine.ts:178
// Forward every authorization-response parameter so
// openid-client can enforce all applicable checks. The `checks` argument
// carries the values we stored ourselves (PKCE verifier, nonce, state).
tokenSet = await client.callback(redirectUri, params, {
code_verifier: input.codeVerifier,
nonce: input.nonce,
state: input.state,
})
} catch (error) {
throw new MedusaError(
MedusaError.Types.UNAUTHORIZED,
`Could not validate the identity provider's response: ${error.message}`
)
}
// Without the `openid` scope, the token endpoint returns no ID token and
// `tokenSet.claims()` would throw an unhelpful TypeError.
if (!tokenSet.id_token) {
throw new MedusaError(
MedusaError.Types.UNAUTHORIZED,
"The identity provider did not return an ID token; ensure the 'openid' scope is requested"
)
}
const claims = tokenSet.claims()
return {
claims: { ...claims },
tokens: {
id_token: tokenSet.id_token,
access_token: tokenSet.access_token,
refresh_token: tokenSet.refresh_token,
expires_at: tokenSet.expires_at,
token_type: tokenSet.token_type,
scope: tokenSet.scope,
},
}View on GitHub (pinned to 5e06e544a2)
Solutions
- Add 'openid' to the authentication scope configuration for the provider (e.g. scope: "openid email profile").
- Verify in the IdP console that the client is allowed to request the openid scope.
- If the provider is plain OAuth2 (no ID tokens), it cannot be used with this OIDC engine — use a dedicated OAuth2 strategy.
Example fix
// before
options: { issuer: "...", client_id: "...", callback_url: "...", scope: "email profile" }
// after
options: { issuer: "...", client_id: "...", callback_url: "...", scope: "openid email profile" } Defensive patterns
Strategy: validation
Validate before calling
const scopes = (options.scope ?? "openid").split(" ")
if (!scopes.includes("openid")) {
throw new Error("OIDC scope must include 'openid' to receive an ID token")
} Type guard
const requestsOpenidScope = (scope?: string): boolean =>
(scope ?? "openid").split(/\s+/).includes("openid") Try / catch
try { await engine.exchangeCode(input) } catch (e) { if (e instanceof MedusaError && /'openid' scope/.test(e.message)) { /* fix scope config, then restart flow */ } throw e } Prevention
- Default scope strings should always start with 'openid'.
- Only use OIDC-capable providers with this engine.
- Add a startup assertion on the configured scope.
When it happens
Trigger: The provider was configured with a scope list that omits 'openid' (e.g. only 'email profile'), or the IdP app registration does not expose the openid scope, so the token endpoint returns no id_token.
Common situations: A custom scope string like "profile email" in medusa-config.js; using a non-OIDC OAuth2 provider (plain OAuth has no ID tokens); the IdP admin toggled off OpenID Connect for the client.
Related errors
- OIDC engine requires a 'callback_url' option
- The identity provider's ID token is missing the '${entityIdC
- OIDC provider requires an 'issuer' option
- OIDC provider requires a 'client_id' option
- OIDC provider requires a 'callback_url' option
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/ffaa35be2a36f363.
Report an issue: GitHub.