prestodb/presto · error · ChallengeFailedException

Error while fetching access token:

Error message

Error while fetching access token: 

What it means

Thrown by NimbusOAuth2Client when the HTTP exchange to the OAuth2 token endpoint fails while exchanging an authorization code or refresh token; the exception detail is appended. It means the server's token could not be obtained, so the login challenge fails rather than the request being malformed.

Source

Thrown at presto-main/src/main/java/com/facebook/presto/server/security/oauth2/NimbusOAuth2Client.java:454

    private <T extends AccessTokenResponse> T getTokenResponse(String code, URI callbackUri, NimbusAirliftHttpClient.Parser<T> parser)
            throws ChallengeFailedException
    {
        return getTokenResponse(new AuthorizationCodeGrant(new AuthorizationCode(code), callbackUri), parser);
    }

    private <T extends AccessTokenResponse> T getTokenResponse(String refreshToken, NimbusAirliftHttpClient.Parser<T> parser)
            throws ChallengeFailedException
    {
        return getTokenResponse(new RefreshTokenGrant(new RefreshToken(refreshToken)), parser);
    }

    private <T extends AccessTokenResponse> T getTokenResponse(AuthorizationGrant authorizationGrant, NimbusAirliftHttpClient.Parser<T> parser)
            throws ChallengeFailedException
    {
        T tokenResponse = httpClient.execute(new TokenRequest(tokenUrl, clientAuth, authorizationGrant, scope), parser);
        if (!tokenResponse.indicatesSuccess()) {
            throw new ChallengeFailedException("Error while fetching access token: " + tokenResponse.toErrorResponse().toJSONObject());
        }
        return tokenResponse;
    }

    /**
     * Retrieves JWT claims for the given access token.
     *
     * IMPORTANT: This method should NOT be used for extracting the principal field.
     * Per OIDC specification, the principal should come from the ID token, not the access token.
     * This method is kept for backward compatibility and the getClaims() API method.
     *
     * @param accessToken the access token value
     * @return Optional containing claims from access token or UserInfo endpoint
     */
    private Optional<JWTClaimsSet> getJWTClaimsSet(String accessToken)
    {
        // Try parsing access token as JWT
        Optional<JWTClaimsSet> claims = parseAccessToken(accessToken);

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Start a fresh login flow instead of replaying the old callback URL (codes are single-use)
  2. Verify oauth2.client-id, client-secret and redirect-uri match the IdP application registration exactly
  3. Check the appended IdP error JSON in the message (e.g. invalid_grant) to identify the exact rejection
  4. Ensure the callback is not retried/double-delivered by proxies or browser refresh

Example fix

// before
// browser refresh of POST /oauth2/callback?code=OLD_CODE -> invalid_grant
// after
// redirect user to a fresh /oauth2/authentication/challenge flow
Defensive patterns

Strategy: retry

Validate before calling

// Verify oauth2.client-id, client-secret, redirect-uri are non-empty and match the IdP app registration before starting the flow

Type guard

boolean tokenRequestConfigValid(String clientId, String secret, java.net.URI redirectUri) { return clientId != null && !clientId.isEmpty() && secret != null && !secret.isEmpty() && redirectUri != null; }

Try / catch

try { return client.getOAuth2Response(code, callbackUri, nonce); } catch (ChallengeFailedException e) { if (!e.getMessage().contains("invalid_grant")) retryWithBackoff(); else restartLoginFlow(); throw e; }

Prevention

When it happens

Trigger: Exchanging the authorization code when the code is expired/already used, redirect_uri or client credentials mismatch the original request, or the IdP rejects the grant (invalid_grant, unauthorized_client).

Common situations: Replaying an old callback URL after login already completed, mismatched oauth2.client-id/secret or redirect-uri config, clock skew, callback retried by the browser, load balancer double-delivering the callback.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/d99d9eff5e0b1916. Report an issue: GitHub.