quarkusio/quarkus · warning · AuthenticationFailedException

Required ID token is not returned in the refresh token grant

Error message

Required ID token is not returned in the refresh token grant response, re-authentication is required

What it means

When a refresh token grant response arrives and auto-refresh was not triggered proactively, if the application requires an ID token (isIdTokenRequired) but the provider did not return one alongside the new access token, Quarkus cannot refresh the session and throws AuthenticationFailedException carrying the current ID token, forcing the user to re-authenticate via a fresh code flow.

Source

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

    private Uni<AuthorizationCodeTokens> refreshTokensUni(TenantConfigContext configContext,
            String currentIdToken, String refreshToken, boolean autoRefresh) {
        return configContext.provider().refreshTokens(refreshToken).onItem()
                .transform(new Function<AuthorizationCodeTokens, AuthorizationCodeTokens>() {
                    @Override
                    public AuthorizationCodeTokens apply(AuthorizationCodeTokens tokens) {

                        if (tokens.getRefreshToken() == null) {
                            tokens.setRefreshToken(refreshToken);
                        }

                        if (tokens.getIdToken() == null) {
                            if (autoRefresh) {
                                // Auto-refresh is triggered while current ID token is still valid, continue using it.
                                tokens.setIdToken(currentIdToken);
                            } else if (isIdTokenRequired(configContext)) {
                                LOG.debugf(
                                        "Required ID token is not returned in the refresh token grant response, re-authentication is required");
                                throw new AuthenticationFailedException(tokenMap(currentIdToken));
                            } else {
                                if (!isInternalIdToken(currentIdToken, configContext)) {
                                    LOG.debugf(
                                            "OIDC provider issued an ID token after the authorization code flow completion but did not refresh it,"
                                                    + " an internal ID token will be generated");
                                }
                                tokens.setIdToken(generateInternalIdToken(configContext, null, currentIdToken,
                                        tokens.getAccessTokenExpiresIn()));
                            }
                        }

                        return tokens;
                    }

                });
    }

    private Uni<AuthorizationCodeTokens> getCodeFlowTokensUni(RoutingContext context, TenantConfigContext configContext,

View on GitHub (pinned to e1c734241f)

Solutions

  1. Allow Quarkus to keep and reuse the existing ID token across refreshes (do not force re-verification of a fresh ID token) or relax the ID-token-required setting for the tenant.
  2. Configure quarkus.oidc.token.verify-access-token-with-user-info=false / adjust token settings so the old ID token remains valid for session purposes.
  3. Upgrade or reconfigure the OIDC provider to return id_token in refresh token grant responses.
  4. If acceptable, shorten the session so users re-authenticate via the code flow when the ID token expires.

Example fix

// before
quarkus.oidc.authentication.id-token-required=true
// after (if provider omits id_token on refresh and session can rely on access token)
quarkus.oidc.authentication.id-token-required=false
Defensive patterns

Strategy: fallback

Validate before calling

// Probe provider behavior: does refresh_token grant return id_token?
Map<String, String> resp = tokenRequest("refresh_token", refreshToken);
if (isIdTokenRequired() && !resp.containsKey("id_token")) {
    log.warn("Provider omits id_token on refresh; configure session to reuse the original ID token");
}

Try / catch

try {
    return refreshSession(refreshToken);
} catch (AuthenticationFailedException e) {
    if (e.getMessage() != null && e.getMessage().contains("Required ID token is not returned")) {
        // fall back to re-authentication
        redirectToAuthorizationEndpoint();
        return null;
    }
    throw e;
}

Prevention

When it happens

Trigger: Token refresh (session expiry or token refresh in CodeAuthenticationMechanism) returns a token map without id_token while isIdTokenRequired(configContext) is true and autoRefresh is false.

Common situations: OIDC providers that omit id_token in refresh_token grant responses (some providers only return access_token); configuring quarkus.oidc.token.refresh-expired or requiring ID token verification with such providers; provider policy changes after an upgrade.

Understand the failure class

Related errors


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