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
- Treat this as normal control flow: catch OAuthServerException, inspect the redirect response, and show 'authorization denied' to the user
- If denial is unexpected, verify your consent screen calls approveAuthorizationRequest(true) when the user approves
- Re-initiate the authorization flow when the user wants to try again
- 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
- Always call approveAuthorizationRequest(true) when the user consents
- Handle the state parameter on the client to correlate denial redirects
- Design UX so denial is a normal outcome, not an application error
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)