diff --git a/V4-docs.md b/V4-docs.md new file mode 100644 index 00000000..7dfaa3e9 --- /dev/null +++ b/V4-docs.md @@ -0,0 +1,9 @@ +--- +layout: default +title: V4 Docs +permalink: /v4-docs/ +--- + +# V4 Docs + +Checkout the `gh-pages-v4` branch and run `jekyll serve` \ No newline at end of file diff --git a/_data/menu.yml b/_data/menu.yml index 74357333..06b90d2b 100644 --- a/_data/menu.yml +++ b/_data/menu.yml @@ -3,12 +3,14 @@ Getting Started: Terminology: '/terminology/' Requirements: '/requirements/' Installation: '/installation/' - #Framework Integrations: '/framework-integrations/' + Database Setup: '/database-setup/' + Framework Integrations: '/framework-integrations/' + V4 Docs: '/V4-docs/' Authorization Server: 'Which grant?': '/authorization-server/which-grant/' 'Client Credentials Grant': '/authorization-server/client-credentials-grant/' 'Password Grant': '/authorization-server/resource-owner-password-credentials-grant/' -# 'Authorization Code Grant': '/authorization-server/auth-code-grant/' + 'Authorization Code Grant': '/authorization-server/auth-code-grant/' # 'Implict Grant': '/authorization-server/auth-code-grant/' # 'Refresh Token Grant': '/authorization-server/refresh-token-grant/' # 'Creating custom grants': '/authorization-server/custom-grants/' diff --git a/auth-server-auth-code.md b/auth-server-auth-code.md index 759f409a..c00b3747 100755 --- a/auth-server-auth-code.md +++ b/auth-server-auth-code.md @@ -1,198 +1,117 @@ --- layout: default -title: Authorization server with authorization code grant +title: Authorization code grant permalink: /authorization-server/auth-code-grant/ --- -# Authorization server with authorization code grant +# Authorization code grant + +The authorization code grant should be very familiar if you've ever signed into a web app using your Facebook or Google account. + +## Flow + +### Part One + +The client will redirect the user to the authorization server with the following parameters in the query string: + +* `response_type` with the value `code` +* `client_id` with the client identifier +* `redirect_uri` with the client redirect URI. This parameter is optional, but if not send the user will be redirected to a pre-registered redirect URI. +* `scope` a space delimited list of scopes +* `state` with a CSRF token. This parameter is optional but highly recommended. + +All of these parameters will be validated by the authorization server. + +The user will then be asked to login to the authorization server and approve the client. + +If the user approves the client they will be redirected back to the authorization server with the following parameters in the query string: + +* `code` with the authorization code +* `state` with the state parameter sent in the original request + +### Part Two + +The client will now send a POST request to the authorization server with the following parameters: + +* `grant_type` with the value of `authorization_code` +* `client_id` with the client identifier +* `client_secret` with the client secret +* `redirect_uri` with the same redirect URI the user was redirect back to +* `code` with the authorization code from the query string (remember to url decode it first) + +The authorization server will respond with a JSON object containing the following properties: + +* `token_type` with the value `Bearer` +* `expires_in` with an integer representing the TTL of the access token +* `access_token` a JWT signed with the authorization server's private key +* `refresh_token` an encrypted payload that can be used to refresh the access token when it expires. ## Setup -Wherever you intialise your objects, initialize a new instance of the authorization server and bind the storage interfaces and authorization code grant: +Wherever you initialize your objects, initialize a new instance of the authorization server and bind the storage interfaces and authorization code grant: -~~~ php -$server = new \League\OAuth2\Server\AuthorizationServer; +{% highlight php %} +// Init our repositories +$clientRepository = new ClientRepository(); +$scopeRepository = new ScopeRepository(); +$accessTokenRepository = new AccessTokenRepository(); +$authCodeRepository = new AuthCodeRepository(); +$refreshTokenRepository = new RefreshTokenRepository(); +$userRepository = new UserRepository(); -$server->setSessionStorage(new Storage\SessionStorage); -$server->setAccessTokenStorage(new Storage\AccessTokenStorage); -$server->setClientStorage(new Storage\ClientStorage); -$server->setScopeStorage(new Storage\ScopeStorage); -$server->setAuthCodeStorage(new Storage\AuthCodeStorage); - -$authCodeGrant = new \League\OAuth2\Server\Grant\AuthCodeGrant(); -$server->addGrantType($authCodeGrant); -~~~ +// Path to public and private keys +$privateKeyPath = 'file://path/to/private.key'; +$publicKeyPath = 'file://path/to/public.key'; + +// Setup the authorization server +$server = new \League\OAuth2\Server\Server( + $clientRepository, + $accessTokenRepository, + $scopeRepository, + $privateKeyPath, + $publicKeyPath +); +// Enable the authentication code grant on the server with a token TTL of 1 hour +$server->enableGrantType( + new \League\OAuth2\Server\Grant\AuthCodeGrant( + $authCodeRepository, + $refreshTokenRepository, + $userRepository, + new \DateInterval('PT10M') + ), + new \DateInterval('PT1H') +); +{% endhighlight %} ## Implementation -Create a route which will respond to a request to `/oauth` which is where the client will redirect the user to. +The client will request an access token so create an `/access_token` endpoint. -~~~ php -$router->get('/oauth', function (Request $request) use ($server) { +{% highlight php %} +$app->post('/oauth2', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) { - // First ensure the parameters in the query string are correct + /* @var \League\OAuth2\Server\Server $server */ + $server = $app->getContainer()->get(Server::class); + + // Try to respond to the request try { - - $authParams = $server->getGrantType('authorization_code')->checkAuthorizeParams(); - - } catch (\Exception $e) { - - if ($e->shouldRedirect()) { - return new Response('', 302, [ - 'Location' => $e->getRedirectUri() - ]); - } - - return new Response( - json_encode([ - 'error' => $e->errorType, - 'message' => $e->getMessage() - ]), - $e->httpStatusCode, // All of the library's exception classes have a status code specific to the error - $e->getHttpHeaders() // Some exceptions have headers which need to be sent - ); - - } - - // Everything is okay, save $authParams to the a session and redirect the user to sign-in - - return new Response('', 302, [ - 'Location' => '/signin' - ]); - -}); -~~~ - - - -The user is redirected to a sign-in screen. If the user is not signed in then sign them in. - -~~~ php -$router->get('/signin', function (Request $request) use ($server) { - - if ($user) { - - $response = new Response('', 302, [ - 'Location' => '/authorize' - ]); - - return $response; - - } else { - - // Logic here to show the a sign-in form and sign the user in - - } - -}); -~~~ - - -The final part is to show a web page that tells the user the name of the client, the scopes requested and two buttons, an "Approve" button and a "Deny" button. - -View: - -~~~ php -// Authorize view -