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

  1. Verify the IdP actually issues role claims and that the user holds the LoginRole or AdminRole.
  2. Re-check OIDC settings: RolesClaim must match the token's claim type and RolesPrefix must correctly trim the prefix.
  3. If role sync isn't needed, disable SyncUserSettings (then SetDefaults applies DefaultRoles instead).
  4. 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

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


AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13). Data as JSON: /api/errors/f11b5a412e40869d. Report an issue: GitHub.