{"record":{"id":"e810500b0309b63a","repo":"passbolt/passbolt_api","slug":"the-email-claim-is-not-found-or-invalid","errorCode":null,"errorMessage":"The email claim is not found or invalid.","messagePattern":"The email claim is not found or invalid\\.","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"plugins/PassboltEe/Sso/src/Utility/OpenId/BaseIdToken.php","lineNumber":130,"sourceCode":"\n        $this->assertAudClaim($tokenClaims);\n        $this->assertIssClaim($tokenClaims);\n        $this->assertEmailClaim($tokenClaims);\n    }\n\n    /**\n     * Validation email claim against application email validation rule\n     *\n     * @param array $tokenClaims claims\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if the claim does not validate\n     */\n    public function assertEmailClaim(array $tokenClaims): void\n    {\n        $emailClaim = Configure::read('passbolt.plugins.sso.security.oauth2.emailClaimAlias') ?? 'email';\n\n        if (!isset($tokenClaims[$emailClaim]) || !EmailValidationRule::check($tokenClaims[$emailClaim])) {\n            throw new BadRequestException('The email claim is not found or invalid.');\n        }\n    }\n\n    /**\n     * Validate issuer against provider base uri\n     * Allows for trailing slash variations\n     *\n     * @param array $tokenClaims claims\n     * @return void\n     * @throws \\Cake\\Http\\Exception\\BadRequestException if the claim does not validate\n     */\n    public function assertIssClaim(array $tokenClaims): void\n    {\n        if (!isset($tokenClaims['iss']) || !is_string($tokenClaims['iss'])) {\n            throw new BadRequestException('The iss (issuer) parameter is invalid.');\n        }\n\n        $openIdBaseUri = rtrim($this->provider->getOpenIdBaseUri(), '/');","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltEe/Sso/src/Utility/OpenId/BaseIdToken.php#L112-L148","documentation":"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.').","triggerScenarios":"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).","commonSituations":"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`).","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."],"exampleFix":"// before\n'security' => ['oauth2' => ['emailClaimAlias' => 'user_email']] // provider sends 'email'\n// after\n'security' => ['oauth2' => ['emailClaimAlias' => 'email']]","handlingStrategy":"validation","validationCode":"$alias = Configure::read('passbolt.plugins.sso.security.oauth2.emailClaimAlias') ?? 'email';\nif (!isset($claims[$alias]) || !filter_var($claims[$alias], FILTER_VALIDATE_EMAIL)) {\n    // request email scope or fix emailClaimAlias before proceeding\n}","typeGuard":"function hasValidEmailClaim(array $claims, string $alias = 'email'): bool {\n    return isset($claims[$alias]) && is_string($claims[$alias]) && filter_var($claims[$alias], FILTER_VALIDATE_EMAIL) !== false;\n}","tryCatchPattern":"try {\n    $token->assertTokenClaims($claims);\n} catch (BadRequestException $e) {\n    if (str_contains($e->getMessage(), 'email claim')) { /* check scopes/claim alias */ }\n}","preventionTips":["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"],"tags":["jwt","claims","email","sso","openid"],"backgroundTag":"schema-validation-failed","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}