|
12 | 12 | - [Managing Clients](#managing-clients)
|
13 | 13 | - [Requesting Tokens](#requesting-tokens)
|
14 | 14 | - [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) |
15 | 18 | - [Password Grant Tokens](#password-grant-tokens)
|
16 | 19 | - [Creating A Password Grant Client](#creating-a-password-grant-client)
|
17 | 20 | - [Requesting Tokens](#requesting-password-grant-tokens)
|
@@ -454,6 +457,82 @@ If your application issues short-lived access tokens, users will need to refresh
|
454 | 457 |
|
455 | 458 | 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.
|
456 | 459 |
|
| 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 | + |
457 | 536 | <a name="password-grant-tokens"></a>
|
458 | 537 | ## Password Grant Tokens
|
459 | 538 |
|
|
0 commit comments