passbolt/passbolt_api · error · BadRequestException
The email claim is not found or invalid.
Error message
The email claim is not found or invalid.
What it means
assertEmailClaim validates that the token claims contain a valid email. It reads the claim key from `passbolt.plugins.sso.security.oauth2.emailClaimAlias` (default 'email') and checks presence plus EmailValidationRule::check; missing or malformed emails throw BadRequestException('The email claim is not found or invalid.').
Solutions
- Ensure the OAuth authorization request includes the `email` (and `profile`) scope so the provider emits the email claim.
- Check `passbolt.plugins.sso.security.oauth2.emailClaimAlias` matches the actual claim name your provider returns (inspect the decoded token payload).
- In the provider admin console, verify the user account has a primary, verified email address.
- Inspect the raw token (debugEnabled or jwt.io) to confirm which claims are actually present.
Example fix
// before 'security' => ['oauth2' => ['emailClaimAlias' => 'user_email']] // provider sends 'email' // after 'security' => ['oauth2' => ['emailClaimAlias' => 'email']]
Defensive patterns
Strategy: validation
Validate before calling
$alias = Configure::read('passbolt.plugins.sso.security.oauth2.emailClaimAlias') ?? 'email';
if (!isset($claims[$alias]) || !filter_var($claims[$alias], FILTER_VALIDATE_EMAIL)) {
// request email scope or fix emailClaimAlias before proceeding
} Type guard
function hasValidEmailClaim(array $claims, string $alias = 'email'): bool {
return isset($claims[$alias]) && is_string($claims[$alias]) && filter_var($claims[$alias], FILTER_VALIDATE_EMAIL) !== false;
} Try / catch
try {
$token->assertTokenClaims($claims);
} catch (BadRequestException $e) {
if (str_contains($e->getMessage(), 'email claim')) { /* check scopes/claim alias */ }
} Prevention
- Include the `email` scope in every authorization request
- Verify the emailClaimAlias against the actual claim names in a decoded sample token per provider
- Ensure users have verified primary emails in the provider directory
When it happens
Trigger: assertTokenClaims runs assertEmailClaim and the configured email claim key is absent from the decoded id_token claims, or its value fails RFC email validation (missing, null, non-string, or syntactically invalid).
Common situations: Provider scope not requesting email (missing `email` scope); Azure/Google tokens lacking email when the user has no verified address; admins renaming the claim via emailClaimAlias but the provider uses a different key (e.g. `mail`, `upn`).
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- No claims
- The aud (client id) parameter is invalid.
- The iss (issuer) parameter does not match.
- The iss (issuer) parameter is invalid.
- JWT token is missing.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/e810500b0309b63a.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Utility/OpenId/BaseIdToken.php:130
$this->assertAudClaim($tokenClaims);
$this->assertIssClaim($tokenClaims);
$this->assertEmailClaim($tokenClaims);
}
/**
* Validation email claim against application email validation rule
*
* @param array $tokenClaims claims
* @return void
* @throws \Cake\Http\Exception\BadRequestException if the claim does not validate
*/
public function assertEmailClaim(array $tokenClaims): void
{
$emailClaim = Configure::read('passbolt.plugins.sso.security.oauth2.emailClaimAlias') ?? 'email';
if (!isset($tokenClaims[$emailClaim]) || !EmailValidationRule::check($tokenClaims[$emailClaim])) {
throw new BadRequestException('The email claim is not found or invalid.');
}
}
/**
* Validate issuer against provider base uri
* Allows for trailing slash variations
*
* @param array $tokenClaims claims
* @return void
* @throws \Cake\Http\Exception\BadRequestException if the claim does not validate
*/
public function assertIssClaim(array $tokenClaims): void
{
if (!isset($tokenClaims['iss']) || !is_string($tokenClaims['iss'])) {
throw new BadRequestException('The iss (issuer) parameter is invalid.');
}
$openIdBaseUri = rtrim($this->provider->getOpenIdBaseUri(), '/');View on GitHub (pinned to 31c1bbc10f)