danny-avila/LibreChat · error · Error

auth_failed

auth_failed

Error message

auth_failed

What it means

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`.

Source

Thrown at api/strategies/openidStrategy.js:602

    logger.error(
      `[OpenID Strategy] Authentication blocked - email domain not allowed [Identifier: ${email}]`,
    );
    throw new Error('Email domain not allowed');
  }

  const result = await findOpenIDUser({
    findUser,
    email: email,
    openidId: claims.sub || userinfo.sub,
    openidIssuer,
    idOnTheSource: claims.oid || userinfo.oid,
    strategyName: 'openidStrategy',
  });
  let user = result.user;
  const error = result.error;

  if (error) {
    throw new Error(ErrorTypes.AUTH_FAILED);
  }

  const appConfig = user?.tenantId ? await resolveAppConfigForUser(getAppConfig, user) : baseConfig;

  if (!isEmailDomainAllowed(email, appConfig?.registration?.allowedDomains)) {
    logger.error(
      `[OpenID Strategy] Authentication blocked - email domain not allowed [Identifier: ${email}]`,
    );
    throw new Error('Email domain not allowed');
  }

  const fullName = getFullName(userinfo);

  const requiredRole = process.env.OPENID_REQUIRED_ROLE;
  let resolvedOverageGroups = null;

  if (requiredRole) {
    const requiredRoles = requiredRole

View on GitHub (pinned to 5ff282f900)

Solutions

  1. 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).
  2. 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.
  3. 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.
  4. 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`.
Defensive patterns

Strategy: try-catch

Try / catch

// Surface the specific AUTH_FAILED reason in the callback wrapper
try {
  const user = await processOpenIDAuth(tokenset, existingUsersOnly);
  done(null, user);
} catch (err) {
  if (err.message === ErrorTypes.AUTH_FAILED) {
    return done(null, false, { message: err.message }); // user sees /login?error=auth_failed
  }
  done(err);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/fa0339b63173616c. Report an issue: GitHub.