Documented Server, both important Interfaces
This commit is contained in:
		| @@ -37,7 +37,14 @@ interface AuthorizationFormInterface { | ||||
| 	 * and make sure to include the required element. This will usually involve getting a | ||||
| 	 * CSRF token with `$request->getAttribute()` and including it in an `<input type="hidden" …/>`. | ||||
| 	 *  | ||||
| 	 * The form SHOULD present  | ||||
| 	 * The form SHOULD offer the user the opportunity to choose which of the request scopes,  | ||||
| 	 * if any, they wish to grant. It should describe what effect each scope grants. If no scopes are  | ||||
| 	 * requested, tell the user that the app is only requesting authorization, not access to their data. | ||||
| 	 *  | ||||
| 	 * The form MAY offer the user UIs for additional token configuration, e.g. a custom token lifetime. | ||||
| 	 * You may have to refer to the documentation for your instance of `TokenStorageInterface` to ensure | ||||
| 	 * that lifetime configuration works correctly. Any other additional data is not used by the IndieAuth | ||||
| 	 * library, but, if stored on the access token, will be available to your app for use. | ||||
| 	 *  | ||||
| 	 * @param ServerRequestInterface $request The current request. | ||||
| 	 * @param array $authenticationResult The array returned from the Authentication Handler. Guaranteed to contain a 'me' key, may also contain additional keys e.g. 'profile'. | ||||
| @@ -50,11 +57,35 @@ interface AuthorizationFormInterface { | ||||
| 	/** | ||||
| 	 * Transform Authorization Code | ||||
| 	 *  | ||||
| 	 * This method is called on a successful authorization form submission. The `$code` array | ||||
| 	 * is a partially-constructed authorization code array, which is guaranteed to have the  | ||||
| 	 * following keys: | ||||
| 	 *  | ||||
| 	 * * `client_id`: the validated `client_id` request parameter | ||||
| 	 * * `redirect_uri`: the validated `redirect_uri` request parameter | ||||
| 	 * * `state`: the `state` request parameter | ||||
| 	 * * `code_challenge`: the `code_challenge` request parameter | ||||
| 	 * * `code_challenge_method`: the `code_challenge_method` request parameter | ||||
| 	 * * `requested_scope`: the value of the `scope` request parameter | ||||
| 	 * * `me`: the value of the `me` key from the authentication result returned from the authentication request handler callback | ||||
| 	 *  | ||||
| 	 * It may also have additional keys, which can come from the following locations: | ||||
| 	 *  | ||||
| 	 * * All keys from the the authentication request handler callback result which do not clash  | ||||
| 	 *   with the keys listed above (with the exception of `me`, which is always present). Usually | ||||
| 	 *   this is a `profile` key, but you may choose to return additional data from the authentication | ||||
| 	 *   callback, which will be present in `$data`. | ||||
| 	 *  | ||||
| 	 * This method should add any additional data to the auth code, before it is persisted and | ||||
| 	 * returned to the client app. Typically, this involves setting the `scope` key to be a  | ||||
| 	 * valid space-separated scope string of any scopes granted by the user in the form. | ||||
| 	 *  | ||||
| 	 * If the form offers additional token configuration, this method should set any relevant | ||||
| 	 * keys in `$code` based on the form data in `$request`. | ||||
| 	 *  | ||||
| 	 * @param array $code The base authorization code data, to be added to. | ||||
| 	 * @param ServerRequestInterface $request The current request. | ||||
| 	 * @return array The $code argument with any necessary changes. | ||||
| 	 * @return array The $code data after making any necessary changes. | ||||
| 	 */ | ||||
| 	public function transformAuthorizationCode(ServerRequestInterface $request, array $code): array; | ||||
| } | ||||
| @@ -63,6 +63,13 @@ class IndieAuthException extends Exception { | ||||
| 		return self::EXC_INFO[$this->code] ?? self::EXC_INFO[self::INTERNAL_ERROR]; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Trust Query Params | ||||
| 	 *  | ||||
| 	 * Only useful on authorization form submission requests. If this returns false, | ||||
| 	 * the client_id and/or request_uri have likely been tampered with, and the error | ||||
| 	 * page SHOULD NOT offer the user a link to them. | ||||
| 	 */ | ||||
| 	public function trustQueryParams() { | ||||
| 		return $this->code == self::AUTHORIZATION_APPROVAL_REQUEST_INVALID_HASH | ||||
| 				|| $this->code == self::AUTHORIZATION_APPROVAL_REQUEST_MISSING_HASH; | ||||
|   | ||||
							
								
								
									
										181
									
								
								src/Server.php
									
									
									
									
									
								
							
							
						
						
									
										181
									
								
								src/Server.php
									
									
									
									
									
								
							| @@ -19,21 +19,65 @@ use Psr\Log\NullLogger; | ||||
| use Taproot\IndieAuth\Callback\AuthorizationFormInterface; | ||||
| use Taproot\IndieAuth\Callback\DefaultAuthorizationForm; | ||||
|  | ||||
| /** | ||||
|  * Development Reference | ||||
|  *  | ||||
|  * Specification: https://indieauth.spec.indieweb.org/ | ||||
|  * Error responses: https://www.rfc-editor.org/rfc/rfc6749.html#section-5.2 | ||||
|  * indieweb/indieauth-client: https://github.com/indieweb/indieauth-client-php | ||||
|  * Existing implementation with various validation functions and links to relevant spec portions: https://github.com/Zegnat/php-mindee/blob/development/index.php | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * IndieAuth Server | ||||
|  *  | ||||
|  * A PSR-7 compatible implementation of the request-handling logic for IndieAuth authorization endpoints | ||||
|  * and token endpoints. | ||||
|  *  | ||||
|  * Typical usage looks something like this: | ||||
|  *      | ||||
|  *     // Somewhere in your app set-up: | ||||
|  *      | ||||
|  *     use Taproot\IndieAuth; | ||||
|  *      | ||||
|  *     $server = new IndieAuth\Server([ | ||||
|  *       'secret' => APP_INDIEAUTH_SECRET, | ||||
|  *       'tokenStorage' => '/../data/auth_tokens/', | ||||
|  *       'handleAuthenticationRequestCallback' => new IndieAuth\Callback\SingleUserPasswordAuthenticationCallback([ | ||||
|  *           'me' => 'https://your-domain.com/' | ||||
|  *         ], | ||||
|  *         YOUR_HASHED_PASSWORD | ||||
|  *       ) | ||||
|  *     ]); | ||||
|  *      | ||||
|  *     // In your authorization endpoint route: | ||||
|  *     return $server->handleAuthorizationEndpointRequest($request); | ||||
|  *      | ||||
|  *     // In your token endpoint route: | ||||
|  *     return $server->handleTokenEndpointRequest($request); | ||||
|  *  | ||||
|  * Refer to the `__construct` documentation for further configuration options, and to the | ||||
|  * documentation for both handling methods for further documentation about them. | ||||
|  *  | ||||
|  * @link https://indieauth.spec.indieweb.org/ | ||||
|  * @link https://www.rfc-editor.org/rfc/rfc6749.html#section-5.2 | ||||
|  * @link https://github.com/indieweb/indieauth-client-php | ||||
|  * @link https://github.com/Zegnat/php-mindee/blob/development/index.php | ||||
|  */ | ||||
| class Server { | ||||
| 	const HANDLE_NON_INDIEAUTH_REQUEST = 'handleNonIndieAuthRequestCallback'; | ||||
| 	const HANDLE_AUTHENTICATION_REQUEST = 'handleAuthenticationRequestCallback'; | ||||
|  | ||||
| 	/** | ||||
| 	 * The query string parameter key used for storing the hash used for validating authorization request parameters. | ||||
| 	 */ | ||||
| 	const HASH_QUERY_STRING_KEY = 'taproot_indieauth_server_hash'; | ||||
|  | ||||
| 	/** | ||||
| 	 * The key used to store the CSRF token everywhere it’s used: Request parameters, Request body, and Cookies. | ||||
| 	 */ | ||||
| 	const DEFAULT_CSRF_KEY = 'taproot_indieauth_server_csrf'; | ||||
|  | ||||
| 	/** | ||||
| 	 * The form data key used for identifying a request as an authorization (consent screen) form submissions. | ||||
| 	 */ | ||||
| 	const APPROVE_ACTION_KEY = 'taproot_indieauth_action'; | ||||
|  | ||||
| 	/** | ||||
| 	 * The form data value used for identifying a request as an authorization (consent screen) form submissions. | ||||
| 	 */ | ||||
| 	const APPROVE_ACTION_VALUE = 'approve'; | ||||
|  | ||||
| 	protected Storage\TokenStorageInterface $tokenStorage; | ||||
| @@ -54,6 +98,69 @@ class Server { | ||||
|  | ||||
| 	protected string $secret; | ||||
|  | ||||
| 	/** | ||||
| 	 * Constructor | ||||
| 	 *  | ||||
| 	 * Server instances are configured by passing a config array to the constructor. | ||||
| 	 *  | ||||
| 	 * The following keys are required: | ||||
| 	 *  | ||||
| 	 * * `handleAuthenticationRequestCallback`: a callable with the signature | ||||
| 	 *   `function (ServerRequestInterface $request, string $authenticationRedirect, ?string $normalizedMeUrl): array|ResponseInterface`. | ||||
| 	 *   This function is called on IndieAuth authorization requests, after validating the query parameters. | ||||
| 	 *    | ||||
| 	 *   It should check to see if $request is authenticated, then: | ||||
| 	 *     * If it is authenticated, return an array which MUST have a `me` key, mapping to the  | ||||
| 	 *       canonical URL of the currently logged-in user. It may additionally have a `profile` key. These | ||||
| 	 *       keys will be stored in the authorization code and sent to the client, if successful. | ||||
| 	 *     * If it is not authenticated, either present or redirect to an authentication flow. This flow MUST | ||||
| 	 *       redirect the logged-in used back to `$authenticationRedirect`. | ||||
| 	 *    | ||||
| 	 *   If the request has a valid `me` parameter, the canonicalized version of it is passed as | ||||
| 	 *   `$normalizedMeUrl`. Otherwise, this parameter is null. This parameter can optionally be used  | ||||
| 	 *   as a suggestion for which user to log in as in a multi-user authentication flow, but should NOT | ||||
| 	 *   be considered valid data. | ||||
| 	 * * `secret`: A cryptographically random string with a minimum length of 64 characters. Used | ||||
| 	 *   to hash and subsequently query parameters which get passed around. | ||||
| 	 * * `tokenStorage`: Either an object implementing `Storage\TokenStorageInterface`, or a string path, | ||||
| 	 *   which will be passed to `Storage\FilesystemJsonStorage`. This object handles persisting authorization | ||||
| 	 *   codes and access tokens, as well as implementation-specific parts of the exchange process which are  | ||||
| 	 *   out of the scope of the Server class (e.g. lifetimes and expiry). Refer to the `Storage\TokenStorageInterface` | ||||
| 	 *   documentation for more details. | ||||
| 	 *  | ||||
| 	 * The following keys may be required depending on which packages you have installed: | ||||
| 	 *  | ||||
| 	 * * `httpGetWithEffectiveUrl`: must be a callable with the following signature: | ||||
| 	 *   `function (string $url): array [ResponseInterface $response, string $effectiveUrl]`, where  | ||||
| 	 *   `$effectiveUrl` is the final URL after following any redirects (unfortunately, neither the PSR-7 | ||||
| 	 *   Response nor the PSR-18 Client interfaces offer a standard way of getting this very important | ||||
| 	 *   data, hence the unusual return signature).  If `guzzlehttp/guzzle` is installed, this parameter | ||||
| 	 *   will be created automatically. Otherwise, the user must provide their own callable. | ||||
| 	 *  | ||||
| 	 * The following keys are optional: | ||||
| 	 *  | ||||
| 	 * * `authorizationForm`: an instance of `AuthorizationFormInterface`. Defaults to `DefaultAuthorizationForm`. | ||||
| 	 *   Refer to that implementation if you wish to replace the consent screen/scope choosing/authorization form. | ||||
| 	 * * `csrfMiddleware`: an instance of `MiddlewareInterface`, which will be used to CSRF-protect the | ||||
| 	 *   user-facing authorization flow. By default an instance of `DoubleSubmitCookieCsrfMiddleware`. | ||||
| 	 *   Refer to that implementation if you want to replace it with your own middleware — you will  | ||||
| 	 *   likely have to either make sure your middleware sets the same request attribute, or alter your | ||||
| 	 *   templates accordingly. | ||||
| 	 * * `exceptionTemplatePath`: string, path to a template which will be used for displaying user-facing | ||||
| 	 *   errors. Defaults to `../templates/default_exception_response.html.php`, refer to that if you wish | ||||
| 	 *   to write your own template. | ||||
| 	 * * `handleNonIndieAuthRequestCallback`: A callback with the following signature: | ||||
| 	 *   `function (ServerRequestInterface $request): ?ResponseInterface` which will be called if the | ||||
| 	 *   authorization endpoint gets a request which is not identified as an IndieAuth request or authorization | ||||
| 	 *   form submission request. You could use this to handle various requests e.g. client-side requests | ||||
| 	 *   made by your authentication or authorization pages, if it’s not convenient to put them elsewhere. | ||||
| 	 *   Returning `null` will result in a standard `invalid_request` error being returned. | ||||
| 	 * * `logger`: An instance of `LoggerInterface`. Will be used for internal logging, and will also be set | ||||
| 	 *   as the logger for most objects passed in config which implement `LoggerAwareInterface`. | ||||
| 	 *  | ||||
| 	 * @param array $config An array of configuration variables | ||||
| 	 * @return self | ||||
| 	 */ | ||||
| 	public function __construct(array $config) { | ||||
| 		$config = array_merge([ | ||||
| 			'csrfMiddleware' => null, | ||||
| @@ -149,6 +256,35 @@ class Server { | ||||
| 	/** | ||||
| 	 * Handle Authorization Endpoint Request | ||||
| 	 *  | ||||
| 	 * This method handles all requests to your authorization endpoint, passing execution off to | ||||
| 	 * other callbacks when necessary. The logical flow can be summarised as follows: | ||||
| 	 *  | ||||
| 	 * * If this request an **auth code exchange for profile information**, validate the request | ||||
| 	 *   and return a response or error response. | ||||
| 	 * * Otherwise, proceed, wrapping all execution in CSRF-protection middleware. | ||||
| 	 * * Validate the request’s indieauth authorization code request parameters, returning an  | ||||
| 	 *   error response if any are missing or invalid. | ||||
| 	 * * Call the authentication callback | ||||
| 	 *     * If the callback returned an instance of ResponseInterface, the user is not currently | ||||
| 	 *       logged in. Return the Response, which will presumably start an authentication flow. | ||||
| 	 *     * Otherwise, the callback returned information about the currently logged-in user. Continue. | ||||
| 	 * * If this request is an authorization form submission, validate the data, store and authorization | ||||
| 	 *   code and return a redirect response to the client redirect_uri with code data. On an error, return | ||||
| 	 *   an appropriate error response. | ||||
| 	 * * Otherwise, fetch the client_id, parse app data if present, validate the `redirect_uri` and present | ||||
| 	 *   the authorization form/consent screen to the user. | ||||
| 	 * * If none of the above apply, try calling the non-indieauth request handler. If it returns a Response, | ||||
| 	 *   return that, otherwise return an error response. | ||||
| 	 *  | ||||
| 	 * This route should NOT be wrapped in additional CSRF-protection, due to the need to handle API  | ||||
| 	 * POST requests from the client. Make sure you call it from a route which is excluded from any | ||||
| 	 * CSRF-protection you might be using. To customise the CSRF protection used internally, refer to the | ||||
| 	 * `__construct` config array documentation for the `csrfMiddleware` key. | ||||
| 	 *  | ||||
| 	 * Most user-facing errors are thrown as instances of `IndieAuthException`, which are passed off to | ||||
| 	 * `handleException` to be turned into an instance of `ResponseInterface`. If you want to customise | ||||
| 	 * error behaviour, one way to do so is to subclass `Server` and override that method. | ||||
| 	 *  | ||||
| 	 * @param ServerRequestInterface $request | ||||
| 	 * @return ResponseInterface | ||||
| 	 */ | ||||
| @@ -246,6 +382,7 @@ class Server { | ||||
| 					}); | ||||
| 					if (!empty($missingRequiredParameters)) { | ||||
| 						$this->logger->warning('The authorization request was missing required parameters. Returning an error response.', ['missing' => $missingRequiredParameters]); | ||||
| 						// TODO: if the missing parameter isn’t redirect_uri or client_id, this should be a redirect error. | ||||
| 						throw IndieAuthException::create(IndieAuthException::REQUEST_MISSING_PARAMETER, $request); | ||||
| 					} | ||||
|  | ||||
| @@ -373,6 +510,11 @@ class Server { | ||||
| 						// Otherwise, the user is authenticated and needs to authorize the client app + choose scopes. | ||||
|  | ||||
| 						// Fetch the client_id URL to find information about the client to present to the user. | ||||
| 						// TODO: in order to comply with https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1, | ||||
| 						// it may be necessary to do this before returning any other kind of error response, as, per | ||||
| 						// the spec, errors should only be shown to the user if the client_id and redirect_uri parameters | ||||
| 						// are missing or invalid. Otherwise, they should be sent back to the client with an error | ||||
| 						// redirect response. | ||||
| 						try { | ||||
| 							/** @var ResponseInterface $clientIdResponse */ | ||||
| 							list($clientIdResponse, $clientIdEffectiveUrl) = call_user_func($this->httpGetWithEffectiveUrl, $queryParams['client_id']); | ||||
| @@ -447,6 +589,24 @@ class Server { | ||||
| 		}));	 | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle Token Endpoint Request | ||||
| 	 *  | ||||
| 	 * Handles requests to the IndieAuth token endpoint. The logical flow can be summarised as follows: | ||||
| 	 *  | ||||
| 	 * * Check that the request is a code redeeming request. Return an error if not. | ||||
| 	 * * Ensure that all required parameters are present. Return an error if not. | ||||
| 	 * * Attempt to exchange the `code` parameter for an access token. Return an error if it fails. | ||||
| 	 * * Make sure the client_id and redirect_uri request parameters match those stored in the auth code. If not, revoke the access token and return an error. | ||||
| 	 * * Make sure the provided code_verifier hashes to the code_challenge stored in the auth code. If not, revoke the access token and return an error. | ||||
| 	 * * Make sure the granted scope stored in the auth code is not empty. If it is, revoke the access token and return an error. | ||||
| 	 * * Otherwise, return a success response containing information about the issued access token. | ||||
| 	 *  | ||||
| 	 * This method must NOT be CSRF-protected as it accepts external requests from client apps. | ||||
| 	 *  | ||||
| 	 * @param ServerRequestInterface $request | ||||
| 	 * @return ResponseInterface | ||||
| 	 */ | ||||
| 	public function handleTokenEndpointRequest(ServerRequestInterface $request): ResponseInterface { | ||||
| 		if (isIndieAuthAuthorizationCodeRedeemingRequest($request)) { | ||||
| 			$this->logger->info('Handling a request to redeem an authorization code for profile information.'); | ||||
| @@ -524,6 +684,11 @@ class Server { | ||||
| 		])); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Handle Exception | ||||
| 	 *  | ||||
| 	 * Turns an instance of `IndieAuthException` into an appropriate instance of `ResponseInterface`. | ||||
| 	 */ | ||||
| 	protected function handleException(IndieAuthException $exception): ResponseInterface { | ||||
| 		$exceptionData = $exception->getInfo(); | ||||
|  | ||||
|   | ||||
| @@ -2,14 +2,107 @@ | ||||
|  | ||||
| namespace Taproot\IndieAuth\Storage; | ||||
|  | ||||
| // TODO: document. | ||||
|  | ||||
| /** | ||||
|  * Token Storage Interface | ||||
|  *  | ||||
|  * This interface defines the bare minimum methods required by the Server class in order to  | ||||
|  * implement auth code issuing and exchange flows, as well as to let external code get access | ||||
|  * tokens (for validating requests authenticated by an access_token) and revoke access tokens. | ||||
|  *  | ||||
|  * The contract made between Server and implementations of TokenStorageInterface can broadly | ||||
|  * be summarized as follows: | ||||
|  *  | ||||
|  * * The Server class is responsible for performing all validation which is | ||||
|  *   defined in the IndieAuth spec and is not implementation-specific. For example: checking | ||||
|  *   validity of all the authorization request parameters, checking that client_id, request_uri | ||||
|  *   and code_verifier parameters in token exchange requests match with the stored data. | ||||
|  * * The TokenStorageInterface class is responsible for performing implementation-specific | ||||
|  *   validation, such as assigning and checking expiry times for auth codes and access tokens. | ||||
|  *  | ||||
|  * Implementations of TokenStorageInterface will usually implement additional methods to allow | ||||
|  * for lower-level querying, saving, updating and deletion of token data. These can be used to, | ||||
|  * for example, implement a UI for users to review and revoke currently valid access tokens. | ||||
|  *  | ||||
|  * The behaviour of `TokenStorageInterface` is somewhat coupled with the implementation of your | ||||
|  * authentication handler callback (documented in `Server::__construct`) and `AuthorizationFormInterface`, | ||||
|  * so you should refer to the documentation for both while implementing `TokenStorageInterface`. | ||||
|  *  | ||||
|  * Periodic deletion of expired tokens is out of the scope of this interface. Implementations may | ||||
|  * choose to offer a clean-up method, and potentially the option to call it once automatically  | ||||
|  * on instanciation. | ||||
|  */ | ||||
| interface TokenStorageInterface { | ||||
| 	/** | ||||
| 	 * Create Auth Code | ||||
| 	 *  | ||||
| 	 * This method is called on a valid authorization token request. The `$data` | ||||
| 	 * array is guaranteed to have the following keys: | ||||
| 	 *  | ||||
| 	 * * `client_id`: the validated `client_id` request parameter | ||||
| 	 * * `redirect_uri`: the validated `redirect_uri` request parameter | ||||
| 	 * * `state`: the `state` request parameter | ||||
| 	 * * `code_challenge`: the `code_challenge` request parameter | ||||
| 	 * * `code_challenge_method`: the `code_challenge_method` request parameter | ||||
| 	 * * `requested_scope`: the value of the `scope` request parameter | ||||
| 	 * * `me`: the value of the `me` key from the authentication result returned from the authentication request handler callback | ||||
| 	 *  | ||||
| 	 * It may also have additional keys, which can come from the following locations: | ||||
| 	 *  | ||||
| 	 * * All keys from the the authentication request handler callback result which do not clash  | ||||
| 	 *   with the keys listed above (with the exception of `me`, which is always present). Usually | ||||
| 	 *   this is a `profile` key, but you may choose to return additional data from the authentication | ||||
| 	 *   callback, which will be present in `$data`. | ||||
| 	 * * Any keys added by the `transformAuthorizationCode` method on the currently active instance | ||||
| 	 *   of `Taproot\IndieAuth\Callback\AuthorizationFormInterface`. Typically this is the `scope` | ||||
| 	 *   key, which is a valid scope string listing the scopes granted by the user on the consent | ||||
| 	 *   screen. Other implementations of `AuthorizationFormInterface` may add additional data, such | ||||
| 	 *   as custom token-specific settings, or a custom token lifetime. | ||||
| 	 *  | ||||
| 	 * This method should store the data passed to it, generate a corresponding authorization code, | ||||
| 	 * and return an instance of `Storage\Token` containing both. Implementations will usually add  | ||||
| 	 * an expiry time, usually under the `valid_until` key. | ||||
| 	 *  | ||||
| 	 * The method call and data is structured such that implementations have a lot of flexibility | ||||
| 	 * about how to store authorization code data. It could be a record in an auth code database | ||||
| 	 * table, a record in a table which is used for both auth codes and access tokens, or even | ||||
| 	 * a stateless self-encrypted token — note that in the latter case, you must persist a copy | ||||
| 	 * of the auth code with it’s access token to check against, in order to prevent it being | ||||
| 	 * exchanged for an access token more than once. | ||||
| 	 *  | ||||
| 	 * On an error, return null. The reason for the error is irrelevant for calling code, but it’s | ||||
| 	 * recommended to log it for reference. | ||||
| 	 */ | ||||
| 	public function createAuthCode(array $data): ?Token; | ||||
|  | ||||
| 	/** | ||||
| 	 * Exchange Authorization Code for Access Token | ||||
| 	 *  | ||||
| 	 * Attempt to exchange an authorization code identified by `$code` for | ||||
| 	 * an access token, returning it in a `Token` on success and null on error. | ||||
| 	 *  | ||||
| 	 * This method is responsible for ensuring that the matched auth code is | ||||
| 	 * not expired. If it is, it should return null, presumably after deleting | ||||
| 	 * the corresponding authorization code record. | ||||
| 	 *  | ||||
| 	 * If the exchanged access token should expire, this method should set its  | ||||
| 	 * expiry time, usually in a `valid_until` key. | ||||
| 	 */ | ||||
| 	public function exchangeAuthCodeForAccessToken(string $code): ?Token; | ||||
|  | ||||
| 	/** | ||||
| 	 * Get Access Token | ||||
| 	 *  | ||||
| 	 * Fetch access token data identified by the token `$token`, returning  | ||||
| 	 * null if it is expired or invalid. The data should be structured in | ||||
| 	 * exactly the same way it was stored by `exchangeAuthCodeForAccessToken`. | ||||
| 	 */ | ||||
| 	public function getAccessToken(string $token): ?Token; | ||||
|  | ||||
| 	/** | ||||
| 	 * Revoke Access Token | ||||
| 	 *  | ||||
| 	 * Revoke the access token identified by `$token`. Return true on success, | ||||
| 	 * or false on error, including if the token did not exist. | ||||
| 	 */ | ||||
| 	public function revokeAccessToken(string $token): bool; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user