# Authorization code grant flow with proof key for code exchange

## Introduction

Proof Key for Code Exchange (PKCE) is an extension to the Authorization Code Flow to prevent CSRF and authorization code injection attacks.

PKCE is not a form of client authentication, and PKCE is not a replacement for a client secret or other client authentication. PKCE is recommended even if a client is using a client secret.

This flow was originally designed to protect the authorization code flow in mobile applications. However, its ability to prevent authorization code injection makes it useful for every type of OAuth client, including web apps that use client authentication.

For web applications, the client secret must be managed in a secure store or wallet within the client application to obtain the token pair for an issued authorization code.

It consists of the steps found below.

---

## Step 1: Authorizing the user

The URL of the Pagero Login page is:

- <https://sso.pageroonline.com/oauth/v2/oauth-authorize>

Request method: **GET**

Required query parameters:

| Parameter            | Description                                                                                                                                                                                                                                                              |
|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `response_type`      | Should be set to `code` to generate an `authorization_code`.                                                                                                                                                                                                             |
| `client_id`          | The client ID.                                                                                                                                                                                                                                                           |
| `redirect_uri`       | The client URI where the user will be redirected after successfully providing credentials. This URI must be the one that was agreed upon when the client was registered. <br> **Note:** This URI should be URL-encoded with `UTF-8` to ensure it is correctly processed. |
| `code_challenge`     | The derived `code_challenge` from the `code_verifier`.                                                                                                                                                                                                                   |
| `code_challenge_method` | The method used to derive the `code_challenge`. This should be `S256`.                                                                                                                                                                                                |

Optional query parameters:

| Parameter | Description                                                                                                                                                                                                                                                 |
|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `state`   | Returned to the client in the final redirect to track the session or prevent unauthorized requests.                                                                                                                                                         |
| `scope`   | The scopes must be separated by spaces. These scopes must be a subset of the scopes configured on the client. <br> **Possible values**: <br> - `all`: Default value <br> - `openid`: If set, it will provide an additional `id_token` property along with the `access_token` and `refresh_token` in the response |
| `prompt`  | Specifies whether the authorization server prompts the user login for re-authentication. <br> **Possible values**: <br> - `login`: Force the user to re-authenticate, ensuring that the person using the application is the legitimate owner of the account.|

#### Example

- <https://sso.pageroonline.com/oauth/v2/oauth-authorize?response_type=code&client_id=test-client&redirect_uri=https://urltoclient:4443&code_challenge=g6U5HmHguMcTwxKWwRaePpK_KrAYoSgajuiLeBftQ7M&code_challenge_method=S256>

---

## Step 2: Obtaining authorization code

Upon successful login, the `authorization_code` is posted back as a query parameter to the URL defined in the `redirect_uri` query parameter.

Response structure:

| Parameter  | Description                                                                                          |
|------------|------------------------------------------------------------------------------------------------------|
| `state`    | Matches the value provided in the initial request. Used to align the request with the redirect response.|
| `iss`      | Identifier of the authorization server where the request was sent.                                    |
| `code`     | A code used for authorization, utilized in the token request.                                         |

#### Example

- <https://urltoclient:4443/?code=0F7ijeaW4BCwhvyg6ozY9PeLsFF6KUi1&state=exampleState&iss=https%3A%2F%2Fauthorization-server.com>

---

## Step 3: Exchanging to a token

Using the `authorization_code`, the `code_verifier`, and the `client_secret`, it’s now possible to obtain an `access_token` and a `refresh_token`.

> [!IMPORTANT]
> The refresh token is issued with a **rolling lifetime of three years**,
> allowing it to generate new access tokens continuously within this period.
> After three years, user authentication will be required to obtain a new refresh token.
>

The URL for doing so is:

- <https://sso.pageroonline.com/oauth/v2/oauth-token>

Request method: **POST**

Required parameters in `application/x-www-form-urlencoded`:

| Parameter      | Description                                                                                                |
|----------------|------------------------------------------------------------------------------------------------------------|
| `grant_type`   | Should be `authorization_code`.                                                                            |
| `code`         | The authorization code.                                                                                    |
| `redirect_uri` | Must be identical to the redirected URI that was provided in the first step above.                         |
| `code_verifier`| The original `code_verifier` used to generate the `code_challenge`.                                        |
`client_id`*     | The client ID.
`client_secret`* | The client secret.

Required headers (if not `client_id` and `client_secret` provided in the body):

Header | Description
------------ | -------------
`Authorization` | Authorization header for basic authorization, where the user should be the client id and password should be the client secret.

Response structure:

| Parameter       | Description                                                                                                                       |
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `access_token`  | A freshly generated JSON Web Token (JWT)                                                                                          |
| `refresh_token` | A freshly generated refresh token                                                                                                 |
| `expires_in`    | Time in seconds until expiration                                                                                                  |
| `scope`         | A string with space-separated values                                                                                              |
| `token_type`    | Bearer or another type of token                                                                                                   |
| `id_token`*     | A signed JSON Web Token (JWT) containing user information like `email` and this is only present if the `scope` is set to `openid` |

#### Example with header option

```text Example with curl
curl https://sso.pageroonline.com/oauth/v2/oauth-token \
  -d 'grant_type=authorization_code' \
  -d 'code=0F7ijeaW4BCwhvyg6ozY9PeLsFF6KUi1' \
  -d 'redirect_uri=https://urltoclient:4443' \
  -d 'code_verifier=P-kgelWDHa807VoSN7IBXjbkW0rVtFmU1EUw7MWKd5U' \
  --user 'client-id:client-secret'
```

The response will contain a JSON body that looks like this:

```json
{
  "token_type": "bearer",
  "access_token": "eyJraWQiOiIxNTUzNzgyMDQxIiwieDV0IjoiYldvWF...",
  "refresh_token": "_1XBPWQQ_e61b091b-9139-4268-a7c7-765d2d418d52",
  "scope": "",
  "claims": "publicid",
  "expires_in": 600
}
 ```

> [!NOTE]
> The `access_token` value is redacted for brevity. The actual JWT that is issued will be longer.

---

## Making an API request using an access token

When making an API request, the access token should be provided in an Authentication header as a bearer token.

```text Example with curl
curl https://api.pageroonline.com/someresource \
  -H 'Authorization: Bearer eyJraWQiOiIxNTUzNzgyMDQxIiwieDV0IjoiYldvWF...'
```
