{"record":{"id":"fa0339b63173616c","repo":"danny-avila/LibreChat","slug":"auth-failed","errorCode":"auth_failed","errorMessage":"auth_failed","messagePattern":"auth_failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"api/strategies/openidStrategy.js","lineNumber":602,"sourceCode":"    logger.error(\n      `[OpenID Strategy] Authentication blocked - email domain not allowed [Identifier: ${email}]`,\n    );\n    throw new Error('Email domain not allowed');\n  }\n\n  const result = await findOpenIDUser({\n    findUser,\n    email: email,\n    openidId: claims.sub || userinfo.sub,\n    openidIssuer,\n    idOnTheSource: claims.oid || userinfo.oid,\n    strategyName: 'openidStrategy',\n  });\n  let user = result.user;\n  const error = result.error;\n\n  if (error) {\n    throw new Error(ErrorTypes.AUTH_FAILED);\n  }\n\n  const appConfig = user?.tenantId ? await resolveAppConfigForUser(getAppConfig, user) : baseConfig;\n\n  if (!isEmailDomainAllowed(email, appConfig?.registration?.allowedDomains)) {\n    logger.error(\n      `[OpenID Strategy] Authentication blocked - email domain not allowed [Identifier: ${email}]`,\n    );\n    throw new Error('Email domain not allowed');\n  }\n\n  const fullName = getFullName(userinfo);\n\n  const requiredRole = process.env.OPENID_REQUIRED_ROLE;\n  let resolvedOverageGroups = null;\n\n  if (requiredRole) {\n    const requiredRoles = requiredRole","sourceCodeStart":584,"sourceCodeEnd":620,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/strategies/openidStrategy.js#L584-L620","documentation":"Thrown when `findOpenIDUser` returns a truthy `error` field. That helper sets `error` to `ErrorTypes.AUTH_FAILED` (value `'auth_failed'`) in exactly three cases: (A) the resolved user has an `openidId` whose stored `openidIssuer` does not match the token's issuer; (B) an email-based fallback match found a user registered with a different `provider` (e.g. a local/google account sharing that email); (C) an email-fallback match found a user whose stored `openidId` differs from the token's `sub`. The callback wrapper maps this to `done(null, false, { message })` → 302 to `/login?error=auth_failed`.","triggerScenarios":"Same person re-authenticating after the IdP issuer URL changed (e.g. Azure AD tenant rename, or `OPENID_ISSUER` env drift); an email address reused across providers (user signed up with email/password, then tried OpenID); or a token `sub` that differs from the stored `openidId` because the IdP rotated subject identifiers or a different client_id is in use.","commonSituations":"Migrating IdP issuer URLs without updating stored `openidIssuer` on existing users; switching the `OPENID_CLIENT_ID` so Azure issues a different `sub`; users who originally registered via Google/local and now try SSO; multi-tenant IdP where the same email exists under two tenants.","solutions":["Inspect server logs for the preceding `[openidStrategy] Rejected ...` / `Attempted OpenID login ...` warn lines — they name the exact sub-case (issuer mismatch, provider mismatch, or sub mismatch).","For issuer mismatch: confirm `OPENID_ISSUER` matches the IdP's actual issuer, and if the stored value on the user document is stale, update `user.openidIssuer` to the current normalized issuer.","For provider mismatch: the user must either sign in with their original provider, or an admin unlinks/re-registers the account so OpenID can claim it.","For `openidId` mismatch on email fallback: verify the same `OPENID_CLIENT_ID`/tenant is being used consistently; if the IdP rotated subjects, migrate the stored `openidId` to the new `sub`."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Surface the specific AUTH_FAILED reason in the callback wrapper\ntry {\n  const user = await processOpenIDAuth(tokenset, existingUsersOnly);\n  done(null, user);\n} catch (err) {\n  if (err.message === ErrorTypes.AUTH_FAILED) {\n    return done(null, false, { message: err.message }); // user sees /login?error=auth_failed\n  }\n  done(err);\n}","preventionTips":["Keep the IdP issuer stable; if it must change, migrate stored user.openidIssuer atomically for all affected users.","Avoid email reuse across providers — when migrating a user to OpenID, clear the conflicting provider linkage first.","Monitor the `[openidStrategy] Rejected ...` / `Attempted OpenID login ...` warn logs; they identify the exact AUTH_FAILED sub-case.","Pin OPENID_CLIENT_ID/tenant so the IdP issues stable `sub` values across logins."],"tags":["authentication","openid","account-linking","issuer","security"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}