danny-avila/LibreChat · error · Error
You must have ${rolesList} role to log in.
Error message
You must have ${rolesList} role to log in. What it means
Thrown inside the `OPENID_REQUIRED_ROLE` enforcement block when the configured role claim is entirely absent or the wrong type. The strategy locates the claim at `requiredRoleParameterPath` inside the token identified by `requiredRoleTokenKind` (id_token or access_token). If the result `roles` is falsy, or is neither an array nor a string, the strategy logs that the path was not found and throws. The message lists the required role(s). Mapped by the callback to `done(null, false, { message })` → `auth_failed` redirect.
Source
Thrown at api/strategies/openidStrategy.js:659
decodedToken &&
hasOverage
) {
const overageGroups = await resolveGroupsFromOverage(tokenset.access_token, claims.sub);
if (overageGroups) {
roles = overageGroups;
resolvedOverageGroups = overageGroups;
}
}
if (!roles || (!Array.isArray(roles) && typeof roles !== 'string')) {
logger.error(
`[openidStrategy] Key '${requiredRoleParameterPath}' not found in ${requiredRoleTokenKind} token!`,
);
const rolesList =
requiredRoles.length === 1
? `"${requiredRoles[0]}"`
: `one of: ${requiredRoles.map((r) => `"${r}"`).join(', ')}`;
throw new Error(`You must have ${rolesList} role to log in.`);
}
const roleValues = Array.isArray(roles) ? roles : roles.split(/[\s,]+/).filter(Boolean);
if (!requiredRoles.some((role) => roleValues.includes(role))) {
const rolesList =
requiredRoles.length === 1
? `"${requiredRoles[0]}"`
: `one of: ${requiredRoles.map((r) => `"${r}"`).join(', ')}`;
throw new Error(`You must have ${rolesList} role to log in.`);
}
}
let username = '';
if (process.env.OPENID_USERNAME_CLAIM) {
username = userinfo[process.env.OPENID_USERNAME_CLAIM];
} else {
username = convertToUsername(View on GitHub (pinned to 5ff282f900)
Solutions
- Decode the id_token and access_token (e.g. jwt.io) for the failing user and confirm which token actually carries the role claim and its exact JSON path.
- Set `OPENID_REQUIRED_ROLE_TOKEN_KIND` to the token (`id_token` or `access_token`) that contains the claim, and `OPENID_REQUIRED_ROLE_PARAMETER_PATH` to the exact key.
- On the IdP side, ensure the user/group is assigned the app role that emits the claim (Azure AD: app roles + user/group assignment).
- If the claim legitimately may be empty for some users, decide whether absence should deny (current behavior) and document it.
Defensive patterns
Strategy: validation
Validate before calling
// Decode the relevant token and confirm the claim path exists before enabling role gating
function findRoleClaim(token, path, kind) {
const decoded = jwt.decode(token);
return kind === 'access_token' ? decoded?.[path] : decoded?.[path];
}
const roles = findRoleClaim(idToken, process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH, process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND);
if (!roles || (!Array.isArray(roles) && typeof roles !== 'string')) {
throw new Error(`Role claim '${process.env.OPENID_REQUIRED_ROLE_PARAMETER_PATH}' not found in ${process.env.OPENID_REQUIRED_ROLE_TOKEN_KIND}`);
} Type guard
function isRoleClaim(v: unknown): v is string | string[] {
return typeof v === 'string' || (Array.isArray(v) && v.every((r) => typeof r === 'string'));
} Try / catch
try {
// role enforcement block
} catch (err) {
if (err.message.includes('role to log in')) return done(null, false, { message: err.message });
throw err;
} Prevention
- Before enabling OPENID_REQUIRED_ROLE, decode a real user's id_token AND access_token and confirm which carries the claim and its exact path.
- Set OPENID_REQUIRED_ROLE_TOKEN_KIND and OPENID_REQUIRED_ROLE_PARAMETER_PATH to match what the IdP actually emits.
- Grant the app role to at least one admin user in the IdP before turning gating on.
When it happens
Trigger: `OPENID_REQUIRED_ROLE` is set (e.g. `admin`) and `OPENID_REQUIRED_ROLE_PARAMETER_PATH`/`OPENID_REQUIRED_ROLE_TOKEN_KIND` point at a claim the IdP does not emit for this user — e.g. Azure AD without the `roles` directory-role claim, or an IdP that puts groups in `groups` rather than `roles`, or a user whose app-role assignment is empty. Also when the claim exists but is an object/number rather than array/string.
Common situations: Enabling role-gated login for the first time without confirming the IdP actually issues the claim; Azure AD app registration missing the 'app roles' assignment; `OPENID_REQUIRED_ROLE_PARAMETER_PATH` typo (e.g. `role` vs `roles`); the claim lives in the access_token but `OPENID_REQUIRED_ROLE_TOKEN_KIND` defaults to the id_token.
Related errors
- Email domain not allowed
- [MCP][${serverName}][${toolName}] upstream authentication fa
- User must be authenticated via OpenID to perform OBO token e
- auth_failed
- User does not exist
AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12).
Data as JSON: /api/errors/a9b074825f56488b.
Report an issue: GitHub.