passbolt/passbolt_api · error · BadRequestException

Single sign-on failed. The

Error message

Single sign-on failed. The {0} claim is not present, please contact your administrator.

What it means

AzureResourceOwner::getEmail() throws a BadRequestException when the configured email alias claim (emailAliasField, e.g. 'email', 'upn' or 'preferred_username') is missing or null in the Azure AD token/resource-owner payload. Passbolt needs an email to match the Azure identity to a local user, so SSO cannot proceed without that claim. It is an administrator-side configuration/tenant issue rather than a user mistake.

Solutions

  1. Check which email alias field passbolt expects and inspect the decoded token payload (toArray()) to see which claims Azure actually returned.
  2. In Azure Portal, configure the app registration's token configuration (optional claims) to include 'email' (or the configured alias, e.g. 'upn'/'preferred_username') in ID tokens.
  3. Verify the Azure user account has a verified mail/upn attribute.
  4. If passbolt setting uses an alias the tenant cannot provide, change the SSO email claim setting to a claim Azure actually emits.
  5. Ask users to authenticate with their organizational account rather than a personal/personal-Teams account.

Example fix

// before (Azure app registration lacks optional claims)
// token payload: { "aud": "...", "oid": "..." } // no 'email' => getEmail() throws
// after: Azure Portal -> App registrations -> Token configuration -> Add optional claim: email (ID token)
// token payload now: { "aud": "...", "oid": "...", "email": "user@corp.com" }
Defensive patterns

Strategy: try-catch

Validate before calling

$data = $resourceOwner->toArray();
if (!isset($data[$emailAliasField]) || $data[$emailAliasField] === null) {
    // surface admin-facing error before calling getEmail()
}

Type guard

function hasEmailClaim(array $data, string $field): bool {
    return isset($data[$field]) && is_string($data[$field]) && $data[$field] !== '';
}

Try / catch

try {
    $email = $resourceOwner->getEmail();
} catch (\Cake\Http\Exception\BadRequestException $e) {
    $this->log($e->getMessage());
    return $this->renderError('sso', 'Email claim missing in Azure token; check token configuration.');
}

Prevention

When it happens

Trigger: OAuth2/OpenID callback for Azure SSO calls getEmail() on the resource owner; the decoded ID token lacks the configured alias claim — e.g. Azure tenant admin removed the 'email' optional claim, user has no mail attribute, or passbolt is configured to use 'preferred_username'/'upn' but the token was issued without those claims.

Common situations: Azure AD tenants where the email claim is not emitted by default (personal accounts or service principals); admins switching email alias field in passbolt SSO settings without updating Azure optional-claims configuration; test accounts without a mail address.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/4da3a06bd4cccb23. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltEe/Sso/src/Utility/Azure/ResourceOwner/AzureResourceOwner.php:70

     * @return string|null
     */
    public function getId(): ?string
    {
        return $this->data['oid'] ?? null;
    }

    /**
     * Retrieves email of the resource owner.
     *
     * @return string
     * @throws \Cake\Http\Exception\BadRequestException When email alias field is not present in the data.
     */
    public function getEmail(): string
    {
        if (!isset($this->data[$this->emailAliasField]) || is_null($this->data[$this->emailAliasField])) {
            $msg = __('Single sign-on failed.') . ' ';
            $msg .= __('The {0} claim is not present, please contact your administrator.', $this->emailAliasField);
            throw new BadRequestException($msg);
        }

        return $this->data[$this->emailAliasField];
    }

    /**
     * Returns all the data obtained about the user.
     *
     * @return array
     */
    public function toArray(): array
    {
        return $this->data;
    }

    /**
     * @inheritDoc
     */

View on GitHub (pinned to 31c1bbc10f)