# OAuth2 JWT issuer mismatch allows token forgery

- **ID:** `security/oauth2-jwt-issuer-mismatch-allows-token-forgery`
- **Domain:** security
- **Category:** auth_error
- **Error Code:** `OAUTH2_JWT_ISSUER_MISMATCH`
- **Verification:** ai_generated
- **Fix Rate:** 90%

## Root Cause

When a JWT token's 'iss' (issuer) claim does not match the expected identity provider, the token could be forged by an attacker using a different issuer, bypassing authentication if the validation is not enforced.

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| JWT | active | — | — |
| Spring Security 5.7+ | active | — | — |
| Keycloak 22.0.0 | active | — | — |
| Auth0 2024.01 | active | — | — |

## Workarounds

1. **Validate the 'iss' claim against a whitelist of trusted issuers. Example in Java with Spring Security: JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(jwt -> { if (!trustedIssuers.contains(jwt.getIssuer())) throw new AuthenticationException(); ... });** (95% success)
   ```
   Validate the 'iss' claim against a whitelist of trusted issuers. Example in Java with Spring Security: JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(jwt -> { if (!trustedIssuers.contains(jwt.getIssuer())) throw new AuthenticationException(); ... });
   ```
2. **Use OpenID Connect Discovery to fetch the issuer's configuration and validate against it dynamically. Example: jwks_uri from .well-known/openid-configuration.** (90% success)
   ```
   Use OpenID Connect Discovery to fetch the issuer's configuration and validate against it dynamically. Example: jwks_uri from .well-known/openid-configuration.
   ```
3. **Ensure the JWT library enforces issuer validation (e.g., in jose-jwt library: JwtConsumer.builder().setExpectedIssuer('https://my-idp.com').build()).** (85% success)
   ```
   Ensure the JWT library enforces issuer validation (e.g., in jose-jwt library: JwtConsumer.builder().setExpectedIssuer('https://my-idp.com').build()).
   ```

## Dead Ends

- **** — Relying solely on signature validation is insufficient because an attacker can sign a token with a different issuer's key if the public key is obtained from an untrusted source. (70% fail)
- **** — Ignoring the issuer claim entirely and only validating the audience (aud) claim allows tokens from any issuer to be accepted. (80% fail)
- **** — Using a hardcoded issuer value in code without checking the token's actual issuer is bypassed if the token's iss is different. (60% fail)
