Kareadita/Kavita · error · KavitaException
errors.oidc.email-not-verified
Error message
errors.oidc.email-not-verified
What it means
Thrown when settings.RequireVerifiedEmail is true and principal.HasVerifiedEmail() returns false. Kavita refuses to provision/link an account from an OIDC identity whose email is unverified, to prevent account takeover via an unverified email. Only evaluated on the new-user / email-match path, after the email is confirmed present.
Source
Thrown at Kavita.Services/OidcService.cs:92
}
var user = await unitOfWork.UserRepository.GetByOidcId(oidcId, AppUserIncludes.UserPreferences | AppUserIncludes.SideNavStreams, ct);
if (user != null)
{
await SyncUserSettings(request, settings, principal, user);
return user;
}
var email = principal.FindFirstValue(ClaimTypes.Email);
if (string.IsNullOrEmpty(email))
{
throw new KavitaException("errors.oidc.missing-email");
}
if (settings.RequireVerifiedEmail && !principal.HasVerifiedEmail())
{
throw new KavitaException("errors.oidc.email-not-verified");
}
user = await unitOfWork.UserRepository.GetUserByEmailAsync(email, AppUserIncludes.UserPreferences | AppUserIncludes.SideNavStreams, ct);
if (user != null)
{
// Don't allow taking over accounts
// This could happen if the user changes their email in OIDC, and then someone else uses the old one
if (!string.IsNullOrEmpty(user.OidcId))
{
throw new KavitaException("errors.oidc.email-in-use");
}
logger.LogDebug("User {UserName} has matched on email to {OidcId}", user.Id, oidcId);
user.OidcId = oidcId;
await unitOfWork.CommitAsync(ct);
await SyncUserSettings(request, settings, principal, user);View on GitHub (pinned to 9c3e540000)
Solutions
- Have the user verify their email in the identity provider, then re-login.
- If the IdP doesn't emit email_verified, either disable RequireVerifiedEmail or configure the IdP to include a true email_verified claim.
- Decode the IdToken to confirm the 'email_verified' claim value.
- Re-check the OIDC settings RequireVerifiedEmail toggle matches your security policy.
Defensive patterns
Strategy: validation
Validate before calling
if (settings.RequireVerifiedEmail && !principal.HasVerifiedEmail())
return Challenge("Email not verified by identity provider."); Type guard
bool EmailIsVerifiedForPolicy(ClaimsPrincipal p, OidcConfigDto s) =>
!s.RequireVerifiedEmail || p.HasVerifiedEmail(); Try / catch
try { var user = await oidcService.LoginOrCreate(Request, principal, ct); }
catch (KavitaException ex) when (ex.Message == "errors.oidc.email-not-verified")
{ return Challenge("Please verify your email with your provider."); } Prevention
- Only enable RequireVerifiedEmail when the IdP issues email_verified.
- Have users verify email in the IdP before first login.
- Decode the IdToken to confirm email_verified=true during setup.
When it happens
Trigger: First-time OIDC login (or email-match to an existing local account) where RequireVerifiedEmail=true in OIDC settings but the token lacks the 'email_verified' claim or it's false.
Common situations: Admin enabled RequireVerifiedEmail but the IdP doesn't issue the email_verified claim or marks it false; user's email in the IdP is pending verification; test/dev IdP that omits the claim.
Related errors
- errors.oidc.email-in-use
- User is not authenticated
- errors.oidc.no-account
- errors.oidc.missing-external-id
- errors.oidc.missing-email
AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13).
Data as JSON: /api/errors/4cb55409ac2805bd.
Report an issue: GitHub.