quarkusio/quarkus · error · AuthenticationCompletionException

Authorization response 'iss' parameter '%s' does not match t

Error message

Authorization response 'iss' parameter '%s' does not match the expected issuer '%s'

What it means

During OIDC authorization code flow completion, Quarkus validates the 'iss' (issuer) parameter returned in the authorization response callback against the expected tenant issuer. If the response explicitly carries an 'iss' value that differs from the configured issuer, the response may come from a different or spoofed provider, so an AuthenticationCompletionException is thrown and login fails.

Source

Thrown at extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java:926

            }

            return bean;
        }
        return null;
    }

    private void validateAuthorizationResponseIssuer(MultiMap requestParams, TenantConfigContext configContext) {
        String expectedIssuer = configContext.getOidcMetadata().getIssuer();

        if (expectedIssuer == null || OidcProvider.ANY_ISSUER.equals(expectedIssuer)) {
            return;
        }

        String issParam = requestParams.get(OidcConstants.CODE_FLOW_ISSUER);

        if (issParam != null) {
            if (!issParam.equals(expectedIssuer)) {
                throw new AuthenticationCompletionException(String.format(
                        "Authorization response 'iss' parameter '%s' does not match the expected issuer '%s'",
                        issParam, expectedIssuer));
            }
        } else if (configContext.getOidcMetadata().isAuthorizationResponseIssParameterSupported()) {
            throw new AuthenticationCompletionException(
                    "Authorization response 'iss' parameter is required but is not present");
        }
    }

    private Uni<SecurityIdentity> performCodeFlow(IdentityProviderManager identityProviderManager,
            RoutingContext context, TenantConfigContext configContext, MultiMap requestParams,
            String[] parsedStateCookieValue) {

        String userPath = null;
        String userQuery = null;

        // This is an original redirect from IDP, check if the original request path and query need to be restored
        CodeAuthenticationStateBean stateBean = getCodeAuthenticationBean(parsedStateCookieValue, configContext);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Compare the 'iss' in the error/log with quarkus.oidc.<tenant>.issuer (or the value derived from auth-server-url) and align them exactly, including trailing slash.
  2. If using keycloak, ensure the realm name in the URL matches the realm that issued the codes.
  3. Verify the tenant is selected correctly (state cookie encodes tenant) and no hostname/proxy rewrite alters the issuer.
  4. Check the OIDC provider's discovery document (/.well-known/openid-configuration) issuer field and use that exact value.

Example fix

// before
quarkus.oidc.auth-server-url=http://localhost:8180/realms/wrong-realm
// after
quarkus.oidc.auth-server-url=http://localhost:8180/realms/correct-realm
Defensive patterns

Strategy: validation

Validate before calling

// Before enabling code flow, compare discovery issuer with config
String discoveryIssuer = Json.parse(httpGet(authServerUrl + "/.well-known/openid-configuration")).getString("issuer");
if (!discoveryIssuer.equals(configuredIssuer)) {
    throw new IllegalStateException("Configured issuer does not match discovery issuer: " + discoveryIssuer);
}

Try / catch

try {
    return completeAuthentication(callbackParams);
} catch (AuthenticationCompletionException e) {
    if (e.getMessage() != null && e.getMessage().contains("does not match the expected issuer")) {
        log.error("Callback 'iss' != configured issuer; check tenant config and realm URL");
    }
    redirectToLogin();
    return null;
}

Prevention

When it happens

Trigger: Browser redirect back to the redirect_uri includes CODE_FLOW_ISSUER request param whose value != expectedIssuer in CodeAuthenticationMechanism during code flow state processing.

Common situations: quarkus.oidc.auth-server-url/issuer misconfigured (trailing slash differences, wrong realm/tenant); multiple tenants where the callback hits the wrong tenant configuration; a proxy or third party initiating a fake callback with a foreign iss.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/f1c514b8b2d7101d. Report an issue: GitHub.