passbolt/passbolt_api · error · BadRequestException
The iss (issuer) parameter does not match.
Error message
The iss (issuer) parameter does not match.
What it means
After confirming iss is a string, assertIssClaim compares it (trailing-slash-insensitive) with the provider's configured OpenID base URI via $this->provider->getOpenIdBaseUri(). Any mismatch throws BadRequestException('The iss (issuer) parameter does not match.') because the token was issued by a different party than configured — a potential token-confusion attack or a configuration error.
Solutions
- Log both values (token iss vs configured base URI) and set `openIdBaseUri`/provider settings to exactly the token's iss value (issuer URI, not the auth endpoint).
- Use the provider's discovery document (`/.well-known/openid-configuration`) `issuer` field as the configured value.
- For Azure AD, ensure the tenant ID in the issuer matches the configured tenant (commondir vs single-tenant mismatches).
- Check for scheme/port/path differences (http vs https, trailing paths) between environments (staging vs production).
Example fix
// before 'openIdBaseUri' => 'https://accounts.google.com/o/oauth2/v2/auth' // auth endpoint // after 'openIdBaseUri' => 'https://accounts.google.com' // matches token iss
Defensive patterns
Strategy: validation
Validate before calling
$expected = rtrim($openIdConfiguration['issuer'], '/');
$actual = rtrim($claims['iss'] ?? '', '/');
if ($actual !== $expected) {
throw new RuntimeException("Issuer mismatch: token=$actual configured=$expected");
} Type guard
function issuerMatches(array $claims, string $configuredBaseUri): bool {
return is_string($claims['iss'] ?? null)
&& rtrim($claims['iss'], '/') === rtrim($configuredBaseUri, '/');
} Try / catch
try {
$token->assertTokenClaims($claims);
} catch (BadRequestException $e) {
if (str_contains($e->getMessage(), 'does not match')) {
// log both iss values; align openIdBaseUri with discovery 'issuer'
}
} Prevention
- Configure openIdBaseUri from the discovery document's `issuer` field, never from auth/token endpoint URLs
- Diff token iss vs configured URI when promoting config between environments
- For Azure, pin the correct tenant issuer URL for your app registration
When it happens
Trigger: Decoded token's `iss` differs from rtrim()'d getOpenIdBaseUri(): e.g. iss is `https://accounts.google.com` but configured base URI is `https://accounts.google.com/o/oauth2/v2/auth`, or tenant-specific issuer URLs (Azure: https://login.microsoftonline.com/{tenant}/v2.0) that don't match the configured value.
Common situations: Copying the authorization/token endpoint into the issuer/base-URI setting instead of the discovery issuer; Azure tenant changed; switching between http/https or adding/removing paths; provider migrating issuer URLs.
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
- The iss (issuer) parameter is invalid.
- No claims
- The aud (client id) parameter is invalid.
- The email claim is not found or invalid.
- JWT token is missing.
AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17).
Data as JSON: /api/errors/c3b8b55d4978b244.
Report an issue: GitHub.
Appendix: source
Thrown at plugins/PassboltEe/Sso/src/Utility/OpenId/BaseIdToken.php:151
/**
* 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(), '/');
$iss = rtrim($tokenClaims['iss'], '/');
if ($iss !== $openIdBaseUri) {
throw new BadRequestException('The iss (issuer) parameter does not match.');
}
}
/**
* https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3
*
* @param array $tokenClaims claims
* @return void
* @throws \Cake\Http\Exception\BadRequestException if the claim does not validate
*/
public function assertAudClaim(array $tokenClaims): void
{
if (isset($tokenClaims['aud'])) {
if (is_string($tokenClaims['aud'])) {
$auds[] = $tokenClaims['aud'];
} else {
$auds = $tokenClaims['aud'];
}View on GitHub (pinned to 31c1bbc10f)