Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Useful error descriptions #1175

Draft
wants to merge 10 commits into
base: 9.0.0-WIP
Choose a base branch
from
95 changes: 95 additions & 0 deletions src/Exception/InvalidRequestException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

namespace League\OAuth2\Server\Exception;

use Throwable;

class InvalidRequestException extends OAuthServerException
{
private const ERROR_TYPE = 'invalid_request';
private const HTTP_STATUS_CODE = 400;
private const EXCEPTION_CODE = 3;

public function __construct($errorMessage, $redirectUri = null, Throwable $previousException = null)
{
parent::__construct($errorMessage, self::EXCEPTION_CODE, self::ERROR_TYPE, self::HTTP_STATUS_CODE, $redirectUri, $previousException);
}


public static function missingAuthCode() {
$errorMessage = 'The auth code is missing from the request';

return new static($errorMessage);
}

public static function authCodeDecryptError(Throwable $previousException)
{
$errorMessage = 'Cannot decrypt the authorization code';

return new static($errorMessage, null, $previousException);
}

public static function missingCodeVerifier()
{
$errorMessage = 'The code_verifier is missing';

return new static($errorMessage);
}

public static function illegalCharacters($parameterName)
{
$errorMessage = 'The ' . $parameterName . ' contains illegal characters';

return new static($errorMessage);
}

public static function missingAuthCodeId()
{
$errorMessage = 'The auth_code_id property is missing from the auth code provided';

return new static($errorMessage);
}

public static function authCodeExpired()
{
$errorMessage = 'The provided authorization code has expired';

return new static($errorMessage);
}

public static function authCodeNotClients()
{
$errorMessage = 'The authorization code was not issued to this client';

return new static($errorMessage);
}

public static function invalidRedirectUri()
{
$errorMessage = 'The redirect_uri given is not valid';

return new static($errorMessage);
}

public static function missingParameter(string $parameterName)
{
$errorMessage = 'The ' . $parameterName . ' is missing from the request';

return new static($errorMessage);
}

public static function invalidCodeChallengeMethod(array $methods)
{
$errorMessage = 'Code challenge method must be one of ' . \implode(', ', \array_map(
function ($method) {
return '`' . $method . '`';
},
$methods)
);

return new static($errorMessage);
}

### Illegal Characters
### Parameters Missing
}
108 changes: 24 additions & 84 deletions src/Exception/OAuthServerException.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ class OAuthServerException extends Exception
*/
private $errorType;

/**
* @var null|string
*/
private $hint;

/**
* @var null|string
*/
Expand All @@ -53,24 +48,19 @@ class OAuthServerException extends Exception
* @param int $code Error code
* @param string $errorType Error type
* @param int $httpStatusCode HTTP status code to send (default = 400)
* @param null|string $hint A helper hint
* @param null|string $redirectUri A HTTP URI to redirect the user back to
* @param Throwable $previous Previous exception
*/
public function __construct($message, $code, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null, Throwable $previous = null)
public function __construct($message, $code, $errorType, $httpStatusCode = 400, $redirectUri = null, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->httpStatusCode = $httpStatusCode;
$this->errorType = $errorType;
$this->hint = $hint;
$this->redirectUri = $redirectUri;
$this->payload = [
'error' => $errorType,
'error_description' => $message,
];
if ($hint !== null) {
$this->payload['hint'] = $hint;
}
}

/**
Expand Down Expand Up @@ -118,40 +108,35 @@ public function setServerRequest(ServerRequestInterface $serverRequest)
*/
public static function unsupportedGrantType()
{
$errorMessage = 'The authorization grant type is not supported by the authorization server.';
$hint = 'Check that all required parameters have been provided';
$errorMessage = 'The grant type is not supported by the authorization server.';

return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint);
return new static($errorMessage, 2, 'unsupported_grant_type', 400);
}

/**
* Invalid request error.
*
* @param string $parameter The invalid parameter
* @param null|string $hint
* @param Throwable $previous Previous exception
* @param string $errorMessage The error message
* @param Throwable $previous Previous exception
*
* @return static
*/
public static function invalidRequest($parameter, $hint = null, Throwable $previous = null)
public static function invalidRequest($errorMessage, Throwable $previous = null)
{
$errorMessage = 'The request is missing a required parameter, includes an invalid parameter value, ' .
'includes a parameter more than once, or is otherwise malformed.';
$hint = ($hint === null) ? \sprintf('Check the `%s` parameter', $parameter) : $hint;

return new static($errorMessage, 3, 'invalid_request', 400, $hint, null, $previous);
return new static($errorMessage, 3, 'invalid_request', 400, null, $previous);
}

/**
* Invalid client error.
*
* @param string $errorMessage
* @param ServerRequestInterface $serverRequest
*
* @return static
*/
public static function invalidClient(ServerRequestInterface $serverRequest)
public static function invalidClient($errorMessage, ServerRequestInterface $serverRequest)
{
$exception = new static('Client authentication failed', 4, 'invalid_client', 401);
$exception = new static($errorMessage, 4, 'invalid_client', 401);

$exception->setServerRequest($serverRequest);

Expand All @@ -161,52 +146,30 @@ public static function invalidClient(ServerRequestInterface $serverRequest)
/**
* Invalid scope error.
*
* @param string $scope The bad scope
* @param null|string $redirectUri A HTTP URI to redirect the user back to
*
* @return static
*/
public static function invalidScope($scope, $redirectUri = null)
{
$errorMessage = 'The requested scope is invalid, unknown, or malformed';

if (empty($scope)) {
$hint = 'Specify a scope in the request or set a default scope';
} else {
$hint = \sprintf(
'Check the `%s` scope',
\htmlspecialchars($scope, ENT_QUOTES, 'UTF-8', false)
);
}

return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri);
}

/**
* Invalid credentials error.
* @param string $errorMessage The error message
* @param null|string $redirectUri A HTTP URI to redirect the user back to
*
* @return static
*/
public static function invalidCredentials()
public static function invalidScope($errorMessage, $redirectUri = null)
{
return new static('The user credentials were incorrect.', 6, 'invalid_credentials', 401);
return new static($errorMessage, 5, 'invalid_scope', 400, $redirectUri);
}

/**
* Server error.
*
* @param string $hint
* @param Throwable $previous
*
* @return static
*
* @codeCoverageIgnore
*/
public static function serverError($hint, Throwable $previous = null)
public static function serverError(Throwable $previous = null)
{
return new static(
'The authorization server encountered an unexpected condition which prevented it from fulfilling'
. ' the request: ' . $hint,
. ' the request',
7,
'server_error',
500,
Expand All @@ -216,36 +179,21 @@ public static function serverError($hint, Throwable $previous = null)
);
}

/**
* Invalid refresh token.
*
* @param null|string $hint
* @param Throwable $previous
*
* @return static
*/
public static function invalidRefreshToken($hint = null, Throwable $previous = null)
{
return new static('The refresh token is invalid.', 8, 'invalid_grant', 400, $hint, null, $previous);
}

/**
* Access denied.
*
* @param null|string $hint
* @param null|string $redirectUri
* @param Throwable $previous
*
* @return static
*/
public static function accessDenied($hint = null, $redirectUri = null, Throwable $previous = null)
public static function accessDenied($errorMessage, $redirectUri = null, Throwable $previous = null)
{
return new static(
'The resource owner or authorization server denied the request.',
$errorMessage,
9,
'access_denied',
401,
$hint,
$redirectUri,
$previous
);
Expand All @@ -254,20 +202,20 @@ public static function accessDenied($hint = null, $redirectUri = null, Throwable
/**
* Invalid grant.
*
* @param string $hint
* @param string $errorMessage
* @param Throwable $previous
*
* @return static
*/
public static function invalidGrant($hint = '')
public static function invalidGrant($errorMessage, Throwable $previous = null)
{
return new static(
'The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token '
. 'is invalid, expired, revoked, does not match the redirection URI used in the authorization request, '
. 'or was issued to another client.',
$errorMessage,
10,
'invalid_grant',
400,
$hint
null,
$previous
);
}

Expand Down Expand Up @@ -378,12 +326,4 @@ public function getHttpStatusCode()
{
return $this->httpStatusCode;
}

/**
* @return null|string
*/
public function getHint()
{
return $this->hint;
}
}
15 changes: 9 additions & 6 deletions src/Grant/AbstractGrant.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ protected function validateClient(ServerRequestInterface $request)
if ($this->clientRepository->validateClient($clientId, $clientSecret, $this->getIdentifier()) === false) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));

throw OAuthServerException::invalidClient($request);
throw OAuthServerException::invalidClient('Client authentication failure', $request);
}

$client = $this->getClientEntityOrFail($clientId, $request);
Expand Down Expand Up @@ -218,7 +218,7 @@ protected function getClientEntityOrFail($clientId, ServerRequestInterface $requ

if ($client instanceof ClientEntityInterface === false || empty($client->getRedirectUri())) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidClient($request);
throw OAuthServerException::invalidClient('Client instance could not be retrieved or client redirect_uri missing', $request);
}

return $client;
Expand All @@ -239,7 +239,7 @@ protected function getClientCredentials(ServerRequestInterface $request)
$clientId = $this->getRequestParameter('client_id', $request, $basicAuthUser);

if (\is_null($clientId)) {
throw OAuthServerException::invalidRequest('client_id');
throw OAuthServerException::invalidRequest('client_id parameter is missing from the request');
}

$clientSecret = $this->getRequestParameter('client_secret', $request, $basicAuthPassword);
Expand All @@ -266,12 +266,12 @@ protected function validateRedirectUri(
&& (\strcmp($client->getRedirectUri(), $redirectUri) !== 0)
) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidClient($request);
throw OAuthServerException::invalidClient('Invalid redirect_uri provided', $request);
} elseif (\is_array($client->getRedirectUri())
&& \in_array($redirectUri, $client->getRedirectUri(), true) === false
) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::CLIENT_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidClient($request);
throw OAuthServerException::invalidClient('Invalid redirect_uri provided', $request);
}
}

Expand All @@ -297,7 +297,10 @@ public function validateScopes($scopes, $redirectUri = null)
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeItem);

if ($scope instanceof ScopeEntityInterface === false) {
throw OAuthServerException::invalidScope($scopeItem, $redirectUri);
throw OAuthServerException::invalidScope(
$scopeItem . ' is not a recognised scope identifier',
$redirectUri
);
}

$validScopes[] = $scope;
Expand Down
Loading