BookStackApp/BookStack · error · OidcException

errors.oidc_no_email_address

Error message

errors.oidc_no_email_address

What it means

BookStack requires an email address to link/match an OIDC login to a local user. When the ID token and userinfo response together yield an empty email, this OidcException with the translated 'errors.oidc_no_email_address' message is thrown and login aborts.

Source

Thrown at app/Access/Oidc/OidcService.php:210

        ]);

        if (!is_null($returnClaims)) {
            $idToken->replaceClaims($returnClaims);
        }

        if ($this->config()['dump_user_details']) {
            throw new JsonDebugException($idToken->getAllClaims());
        }

        try {
            $idToken->validate($settings->clientId);
        } catch (OidcInvalidTokenException $exception) {
            throw new OidcException("ID token validation failed with error: {$exception->getMessage()}");
        }

        $userDetails = $this->getUserDetailsFromToken($idToken, $accessToken, $settings);
        if (empty($userDetails->email)) {
            throw new OidcException(trans('errors.oidc_no_email_address'));
        }
        if (empty($userDetails->name)) {
            $userDetails->name = $userDetails->externalId;
        }

        $isLoggedIn = auth()->check();
        if ($isLoggedIn) {
            throw new OidcException(trans('errors.oidc_already_logged_in'));
        }

        try {
            $user = $this->registrationService->findOrRegister(
                $userDetails->name,
                $userDetails->email,
                $userDetails->externalId
            );
        } catch (UserRegistrationException $exception) {
            throw new OidcException($exception->getMessage());

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. Ensure the 'email' and 'profile'/'openid' scopes are requested and granted by the IdP client
  2. Check the IdP user actually has an email set and the client is allowed to read it
  3. If the email lives in a nonstandard claim, set OIDC_EMAIL_CLAIM (email_claim config) to that claim name
  4. Review getUserDetailsFromToken flow: if userinfo endpoint is enabled, confirm it returns email

Example fix

// before
# no email claim configured, IdP omits email
// after (.env)
OIDC_AUTH_ENDPOINT=...
OIDC_ADDITIONAL_SCOPES=email profile
OIDC_EMAIL_CLAIM=email
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the IdP releases email before relying on OIDC login:
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" https://idp.example.com/userinfo | jq -e '.email != null and .email != ""'
// And in .env ensure scopes include email:
// OIDC_ADDITIONAL_SCOPES="email profile"

Try / catch

try {
    auth()->attemptOidcLogin();
} catch (BookStack\Access\Oidc\OidcException $e) {
    if (trans('errors.oidc_no_email_address') === $e->getMessage()) {
        abort(400, 'Identity provider did not return an email claim; enable email scope/claim at the IdP');
    }
    throw $e;
}

Prevention

When it happens

Trigger: processAccessTokenCallback calls getUserDetailsFromToken; the resulting userDetails->email is empty because the IdP's ID token/userinfo omit the email claim, or BOOKSTACK_OIDC_END_SESSION... specifically the email_claim config points at a claim the IdP does not send.

Common situations: IdP not configured to release the email scope/claim (common with Azure AD, Keycloak, Authentik defaults), or custom external_id_claim/email claim misconfigured in .env.

Related errors


AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02). Data as JSON: /api/errors/fd36a60235541b65. Report an issue: GitHub.