thephpleague/oauth2-server · info · OAuthServerException

access_denied

access_denied

Error message

The user denied the request

What it means

OAuthServerException::accessDenied('The user denied the request') is thrown by ImplicitGrant::completeAuthorizationRequest when the authorization request's user did not approve the client. The library redirects the user agent back to the client's redirect URI with error=access_denied and the original state, per RFC 6749 section 4.2.2.1. It is an expected, user-driven outcome, not a bug.

Solutions

  1. Treat this as normal control flow: catch OAuthServerException, inspect the redirect response, and show 'authorization denied' to the user
  2. If denial is unexpected, verify your consent screen calls approveAuthorizationRequest(true) when the user approves
  3. Re-initiate the authorization flow when the user wants to try again
  4. Include state handling on the client so the error redirect can be matched to the original request

Example fix

// before
$grant->completeAuthorizationRequest($authRequest, $response); // approval state unset
// after
if ($userApproved) {
    $authRequest->approveAuthorizationRequest(true);
}
try {
    return $grant->completeAuthorizationRequest($authRequest, $response);
} catch (OAuthServerException $e) {
    // user denied: redirect already carries error=access_denied&state=...
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!$authorizationRequest->isAuthorizationApproved()) {
    // user has not approved yet; render consent screen instead of completing
}

Type guard

function isApproved(AuthorizationRequest $r): bool {
    return $r->isAuthorizationApproved() === true;
}

Try / catch

try {
    return $grant->completeAuthorizationRequest($authRequest, $response);
} catch (OAuthServerException $e) {
    if ($e->getErrorType() === 'access_denied') {
        // expected user denial: redirect carries error=access_denied&state=...
        return $e->generateHttpResponse($response);
    }
    throw $e;
}

Prevention

When it happens

Trigger: completeAuthorizationRequest where AuthorizationRequest::getAuthorizationApproved? is false (approveAuthorizationRequest never called) or authorizationApproved was set to false by the user-approval UI; the grant then builds the error redirect and throws.

Common situations: User clicks 'Deny' on the consent screen; authorization server app never calls $authorizationRequest->approveAuthorizationRequest() due to routing/session bugs; consent screen times out or user cancels; developer forgets to set approval state in the user-approval endpoint.

Related errors


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

Appendix: source

Thrown at src/Grant/ImplicitGrant.php:195

            $response = new RedirectResponse();
            $response->setRedirectUri(
                $this->makeRedirectUri(
                    $finalRedirectUri,
                    [
                        'access_token' => $accessToken->toString(),
                        'token_type'   => 'Bearer',
                        'expires_in'   => $accessToken->getExpiryDateTime()->getTimestamp() - time(),
                        'state'        => $authorizationRequest->getState(),
                    ],
                    $this->queryDelimiter
                )
            );

            return $response;
        }

        // The user denied the client, redirect them back with an error
        throw OAuthServerException::accessDenied(
            'The user denied the request',
            $this->makeRedirectUri(
                $finalRedirectUri,
                [
                    'state' => $authorizationRequest->getState(),
                ],
                $this->queryDelimiter
            )
        );
    }
}

View on GitHub (pinned to 9d2f6fc0a0)