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
- Check which email alias field passbolt expects and inspect the decoded token payload (toArray()) to see which claims Azure actually returned.
- 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.
- Verify the Azure user account has a verified mail/upn attribute.
- If passbolt setting uses an alias the tenant cannot provide, change the SSO email claim setting to a claim Azure actually emits.
- 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
- Configure Azure optional claims (email) on the app registration before enabling SSO
- Match passbolt's email alias setting to a claim the tenant actually emits
- Test with a real organizational account whose mail attribute is populated
- Log resourceOwner->toArray() in a staging environment to inspect actual claims
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
- Invalid provider data. Expected Azure settings.
- Invalid provider. Expected Azure as provider.
- Invalid provider. Expected OAuth2.
- No valid SSO settings found.
- No valid SSO settings found.
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)