thephpleague/oauth2-server · error · OAuthServerException

server_error

server_error

Error message

Unsupported code challenge method `%s`

What it means

This server_error is thrown by AuthCodeGrant::validateCodeChallenge when the stored authorization-code payload contains a `code_challenge_method` that the grant does not support (only `plain` and `S256` are allowed). It is a server-side configuration/issue-time problem, not a client verifier mismatch, and intentionally returns HTTP 500-class code `server_error` per RFC 6749 semantics.

Solutions

  1. Re-issue the authorization code requesting code_challenge_method=S256 (or plain) exactly, with no whitespace or case variants.
  2. Validate/normalize code_challenge_method at the authorize endpoint before persisting the payload (reject unknown values there).
  3. Check custom AuthCodePayload serialization/deserialization and any storage middleware that could alter the method string.
  4. Upgrade league/oauth2-server to a version whose validateAuthorizationCode/authorize path restricts challenge methods to S256/plain.

Example fix

// before: authorize endpoint accepts any method and stores it
$payload->code_challenge_method = $request->getQueryParams()['code_challenge_method'];
// after
$method = $request->getQueryParams()['code_challenge_method'] ?? null;
if (!in_array($method, ['plain', 'S256'], true)) {
    throw OAuthServerException::invalidRequest('code_challenge_method');
}
$payload->code_challenge_method = $method;
Defensive patterns

Strategy: validation

Validate before calling

// at the authorize endpoint, before storing the payload
$method = $_GET['code_challenge_method'] ?? null;
if (isset($_GET['code_challenge']) && !in_array($method, ['plain', 'S256'], true)) {
    throw OAuthServerException::invalidRequest('code_challenge_method');
}

Try / catch

try {
    $token = $server->respondToAccessTokenRequest($request, $response);
} catch (\League\OAuth2\Server\Exception\OAuthServerException $e) {
    if ($e->getCode() === 'server_error' && str_contains($e->getMessage(), 'code challenge method')) {
        // log the offending stored method; re-issue code with S256
    }
    throw $e;
}

Prevention

When it happens

Trigger: Exchanging an authorization code whose payload's code_challenge_method is anything other than 'plain' or 'S256' — typically because the authorization request specified code_challenge_method=unsupported-value (e.g. 'S256 ' with whitespace, lowercase variants, or a custom method) and it was stored verbatim, or the payload was hand-crafted/tampered with.

Common situations: A proxy or client SDK sent a non-standard code_challenge_method value that the server persisted; custom storage adapters that lower/uppercase or mutate the method string; forged or stale cached payloads; a server that enabled proof exchange without restricting the method on authorize.

Related errors


AI-assisted analysis of thephpleague/oauth2-server@9d2f6fc0a0 (2026-09-15). Data as JSON: /api/errors/6a6f35746a0f1115. Report an issue: GitHub.

Appendix: source

Thrown at src/Grant/AuthCodeGrant.php:186

            throw OAuthServerException::invalidRequest(
                'code_verifier',
                'Code Verifier must follow the specifications of RFC-7636.'
            );
        }

        if (property_exists($authCodePayload, 'code_challenge_method')) {
            if (isset($this->codeChallengeVerifiers[$authCodePayload->code_challenge_method])) {
                $codeChallengeVerifier = $this->codeChallengeVerifiers[$authCodePayload->code_challenge_method];

                if (
                    !property_exists($authCodePayload, 'code_challenge') ||
                    !isset($authCodePayload->code_challenge) ||
                    $codeChallengeVerifier->verifyCodeChallenge($codeVerifier, $authCodePayload->code_challenge) === false
                ) {
                    throw OAuthServerException::invalidGrant('Failed to verify `code_verifier`.');
                }
            } else {
                throw OAuthServerException::serverError(
                    sprintf(
                        'Unsupported code challenge method `%s`',
                        $authCodePayload->code_challenge_method
                    )
                );
            }
        }
    }

    /**
     * Validate the authorization code.
     */
    private function validateAuthorizationCode(
        stdClass $authCodePayload,
        ClientEntityInterface $client,
        ServerRequestInterface $request
    ): void {
        if (!property_exists($authCodePayload, 'auth_code_id')) {

View on GitHub (pinned to 9d2f6fc0a0)