Skip to content

Commit 5e0e2b4

Browse files
authored
Update passport.md
Adds docs for Authentication code with PKCE Grant - laravel/passport#1065
1 parent 6f3da92 commit 5e0e2b4

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed

passport.md

+79
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
- [Managing Clients](#managing-clients)
1313
- [Requesting Tokens](#requesting-tokens)
1414
- [Refreshing Tokens](#refreshing-tokens)
15+
- [Authorization Code Grant with PKCE](#code-grant-pkce)
16+
- [Creating A Authorization Code Grant with PKCE](#creating-a-auth-pkce-grant-client)
17+
- [Requesting Tokens](#requesting-auth-pkce-grant-tokens)
1518
- [Password Grant Tokens](#password-grant-tokens)
1619
- [Creating A Password Grant Client](#creating-a-password-grant-client)
1720
- [Requesting Tokens](#requesting-password-grant-tokens)
@@ -454,6 +457,82 @@ If your application issues short-lived access tokens, users will need to refresh
454457

455458
This `/oauth/token` route will return a JSON response containing `access_token`, `refresh_token`, and `expires_in` attributes. The `expires_in` attribute contains the number of seconds until the access token expires.
456459

460+
<a name="code-grant-pkce"></a>
461+
## Authorization Code Grant with PKCE
462+
463+
The Authorization Code with Proof Key for Code Exchange (PKCE) is the preferred way for the front end (e.g. a single page web application) or a native application such as a mobile app to access an API. This grant should be used when you can't guarantee that the client secret will be stored confidentiality or when mitigating the threat of having the authorization code intercepted by an attacker. A combination of a code verifier and a code challenge replaces the client secret when exchanging the authorization code for an access token.
464+
465+
<a name="creating-a-auth-pkce-grant-client"></a>
466+
### Creating A Authorization Code Grant with PKCE
467+
468+
Before your application can issue tokens via the authorization code grant with PKCE, you will need to create a PKCE-enabled client. You may do this using the `passport:client` command with the `--public` option:
469+
470+
php artisan passport:client --public
471+
472+
<a name="requesting-auth-pkce-grant-tokens"></a>
473+
### Requesting Tokens
474+
475+
#### Code verifier and Code challenge
476+
477+
As this authorization grant does not provide a client secret, developers will need to generate a combination of code verifier and code challenge to be able to request a token.
478+
479+
The code verifier is recommended to be a random, case insensitive string of with a minimum length of 43 characters and a maximum length of 128 characters created with letters, numbers and `"-"`, `"."`, `"_"`, `"~"`, as defined in the [RFC 7636 specification](https://tools.ietf.org/html/rfc7636).
480+
481+
The code challenge should be created using a Base64 encoding with URL and filename-safe characters, with all trailing `'='` characters omitted and without the inclusion of any line breaks, whitespace, or other additional characters.
482+
483+
$code_challenge = strtr(rtrim(base64_encode(hash('sha256', $code_verifier, true)), '='), '+/', '-_');
484+
485+
#### Redirecting For Authorization
486+
487+
Once a client has been created, developers may use their client ID and a generated code verifier and a code challenge to request an authorization code and access token from your application. First, the consuming application should make a redirect request to your application's `/oauth/authorize` route like so:
488+
489+
Route::get('/redirect', function (Request $request) {
490+
$request->session()->put('state', $state = Str::random(40));
491+
$request->session()->put('code_verifier', $code_verifier = Str::random(128));
492+
493+
$code_challenge = strtr(rtrim(base64_encode(hash('sha256', $code_verifier, true)), '='), '+/', '-_');
494+
495+
$query = http_build_query([
496+
'client_id' => 'client-id',
497+
'redirect_uri' => 'http://example.com/callback',
498+
'response_type' => 'code',
499+
'scope' => '',
500+
'state' => $state,
501+
'code_challenge' => $code_challenge,
502+
'code_challenge_method' => 'S256',
503+
]);
504+
505+
return redirect('http://your-app.com/oauth/authorize?'.$query);
506+
});
507+
508+
#### Converting Authorization Codes To Access Tokens
509+
510+
If the user approves the authorization request, they will be redirected back to the consuming application. The consumer should verify the `state` parameter against the value that was stored prior to the redirect, as in the standard Authorization Code Grant. If the state parameter matches the consumer should issue a `POST` request to your application to request an access token. The request should include the authorization code that was issued by your application when the user approved the authorization request along with the originally generated code verifier.
511+
512+
Route::get('/callback', function (Request $request) {
513+
$state = $request->session()->pull('state');
514+
$code_verifier = $request->session()->pull('code_verifier');
515+
516+
throw_unless(
517+
strlen($state) > 0 && $state === $request->state,
518+
InvalidArgumentException::class
519+
);
520+
521+
$http = new GuzzleHttp\Client;
522+
523+
$response = $http->post('http://your-app.com/oauth/token', [
524+
'form_params' => [
525+
'grant_type' => 'authorization_code',
526+
'client_id' => 'client-id',
527+
'redirect_uri' => 'http://example.com/callback',
528+
'code_verifier' => $code_verifier,
529+
'code' => $request->code,
530+
],
531+
]);
532+
533+
return json_decode((string) $response->getBody(), true);
534+
});
535+
457536
<a name="password-grant-tokens"></a>
458537
## Password Grant Tokens
459538

0 commit comments

Comments
 (0)