Kareadita/Kavita · error · KavitaException
errors.oidc.role-not-assigned
Error message
errors.oidc.role-not-assigned
What it means
Thrown in CreateNewAccount when settings.SyncUserSettings is on but the OIDC principal's role claims (filtered by RolesClaim + RolesPrefix) contain neither the LoginRole nor the AdminRole. Kavita won't auto-create users who lack an authorized role when role sync is enabled — a deny-by-default gate.
Source
Thrown at Kavita.Services/OidcService.cs:215
/// Tries to construct a new account from the OIDC Principal may fail if required conditions aren't met
/// </summary>
/// <param name="request"></param>
/// <param name="principal"></param>
/// <param name="settings"></param>
/// <param name="oidcId"></param>
/// <returns></returns>
/// <exception cref="KavitaException"></exception>
private async Task<AppUser?> CreateNewAccount(HttpRequest request, ClaimsPrincipal principal, OidcConfigDto settings, string oidcId)
{
// Check if the token contains the login role, or the admin role
var isAllowedToBeCreated = principal.GetClaimsWithPrefix(settings.RolesClaim, settings.RolesPrefix)
.Intersect([PolicyConstants.LoginRole, PolicyConstants.AdminRole], StringComparer.OrdinalIgnoreCase)
.Any();
if (settings.SyncUserSettings && !isAllowedToBeCreated)
{
logger.LogDebug("Login role was not found under claim {Claim} with prefix {Prefix}", settings.RolesClaim, settings.RolesPrefix);
throw new KavitaException("errors.oidc.role-not-assigned");
}
try
{
return await NewUserFromOpenIdConnect(request, settings, principal, oidcId);
}
catch (KavitaException)
{
throw;
}
catch (Exception e)
{
logger.LogError(e, "An error occured creating a new user");
throw new KavitaException("errors.oidc.creating-user");
}
}
View on GitHub (pinned to 9c3e540000)
Solutions
- Verify the IdP actually issues role claims and that the user holds the LoginRole or AdminRole.
- Re-check OIDC settings: RolesClaim must match the token's claim type and RolesPrefix must correctly trim the prefix.
- If role sync isn't needed, disable SyncUserSettings (then SetDefaults applies DefaultRoles instead).
- Decode the access token and inspect the configured claim + prefix against the actual claim names.
Defensive patterns
Strategy: validation
Validate before calling
var roles = principal.GetClaimsWithPrefix(settings.RolesClaim, settings.RolesPrefix);
var allowed = roles.Intersect(new[] { PolicyConstants.LoginRole, PolicyConstants.AdminRole }, StringComparer.OrdinalIgnoreCase);
if (settings.SyncUserSettings && !allowed.Any())
return Forbid("User does not have a login or admin role."); Type guard
bool HasLoginRole(ClaimsPrincipal p, OidcConfigDto s) =>
!s.SyncUserSettings ||
p.GetClaimsWithPrefix(s.RolesClaim, s.RolesPrefix)
.Intersect(new[] { PolicyConstants.LoginRole, PolicyConstants.AdminRole }, StringComparer.OrdinalIgnoreCase)
.Any(); Try / catch
try { var user = await oidcService.LoginOrCreate(Request, principal, ct); }
catch (KavitaException ex) when (ex.Message == "errors.oidc.role-not-assigned")
{ return Forbid("Contact an admin to be granted the login role."); } Prevention
- Verify RolesClaim and RolesPrefix match the token's actual claim names.
- Ensure the IdP issues role claims and the user holds LoginRole/AdminRole.
- Disable SyncUserSettings if role-based provisioning isn't required.
When it happens
Trigger: First-time OIDC login with SyncUserSettings=true where the token's role claims — after applying RolesClaim and RolesPrefix — don't intersect {LoginRole, AdminRole}. The user isn't authorized to be provisioned.
Common situations: RolesClaim or RolesPrefix misconfigured so the claim path is wrong (roles under 'role' but configured as 'roles', or a prefix that strips too much); IdP doesn't emit role claims at all; user genuinely lacks the login role in the IdP.
Related errors
- errors.oidc.email-not-verified
- errors.oidc.email-in-use
- errors.oidc.syncing-user
- User is not authenticated
- url-blocked-address
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/f11b5a412e40869d.
Report an issue: GitHub.