# Token authentication

## What is token authentication?

Token authentication means making a request to an API endpoint while also sending a special header that contains an
access token. The access token was previously generated by (usually) the same API as the one you are sending requests to
and it consists of an alphanumeric string.

## How does it work?

In order to protect specific resources, clients need to be authenticated with user/admin roles.
These roles are identified from the access token sent via the `Authorization` header.

When Dotkernel API receives a request, it tries to read the access token.

If it does not find an access token, client has `guest` role:

- if the requested endpoint needs no authentication, the requested resource is returned
- else, a `403 Forbidden` response is returned

Else, client's account is identified and client has `admin`/`user` role (the one assigned in their account)

- if the requested endpoint is accessible to the client, the requested resource is returned
- else, a `403 Forbidden` response is returned

Dotkernel API provides out-of-the-box both an `admin` and a `user` account.

### Credentials

The admin account with **role** set to both `superuser` and `admin` with the following credentials:

- **identity**: `admin`
- **password**: `dotadmin`

The user account with **role** set to both `user` and `guest` with the following credentials:

- **identify**: `test@dotkernel.com`
- **password**: `dotkernel`

## Flow

- client sends API request with credentials
- API returns a JSON object containing a new access and refresh token
- client sends API request using `Authentication` header containing the previously generated access token
- API returns requested resource

### Note

> The first two steps need to be executed only once.
> Access token should be stored and reused for all upcoming requests.
> Refresh token should be stored and used to refresh expired access token.

For a better overview of the flow, see the below image:

![Token authentication flow](https://docs.dotkernel.org/img/api/v6/token-authentication.png)

## Generate admin access token

Send a `POST` request to the `/security/generate-token` endpoint with `Content-Type` header set to `application/json`.

Set request body to:

```json
{
  "grant_type": "password",
  "client_id": "admin",
  "client_secret": "admin",
  "scope": "api",
  "username": "<identity>",
  "password": "<password>"
}
```

### Note

> Replace `<identity>` with your admin account's `identity` and `<password>` with your admin account's `password`.
> Both fields come from table `admin`.

### Test using curl

Execute the below command:

```shell
curl --location 'https://api.dotkernel.net/security/generate-token' \
--header 'Content-Type: application/json' \
--data-raw '{
  "grant_type": "password",
  "client_id": "admin",
  "client_secret": "admin",
  "scope": "api",
  "username": "admin",
  "password": "dotkernel"
}'
```

## Generate user access token

Send a `POST` request to the `/security/generate-token` endpoint with `Content-Type` header set to `application/json`.

Set request body to:

```json
{
  "grant_type": "password",
  "client_id": "frontend",
  "client_secret": "frontend",
  "scope": "api",
  "username": "<identity>",
  "password": "<password>"
}
```

### Note

> Replace `<identity>` with your user account's `identity` and `<password>` with your user account's `password`.
> Both fields come from table `user`.

### Test using curl

Execute the below command:

```shell
curl --location 'https://api.dotkernel.net/security/generate-token' \
--header 'Content-Type: application/json' \
--data-raw '{
  "grant_type": "password",
  "client_id": "frontend",
  "client_secret": "frontend",
  "scope": "api",
  "username": "test@dotkernel.com",
  "password": "dotkernel"
}'
```

### Response on success

You should see a `200 OK` response with the following JSON body:

```json
{
    "token_type": "Bearer",
    "expires_in": 86400,
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.e...wuE39ON1mS5mnTKfA_dSpSWxOmNQdny_AKIbc1qZjMfS24qSUV8HIoOw",
    "refresh_token": "def502005a035c8dfe5456d27e85069813a4f8...0b844e843cd62865662a0e723165752dfd7012491502d3d819c2a61d"
}
```

Field description:

- `token_type`: token type to be set when sending the `Authorization` header (example: `Authorization: Bearer eyJ0e...`)
- `expires_in`: access token lifetime (modify in: `config/autoload/local.php` > `authentication`.`access_token_expire`)
- `access_token`: generated access token (store it for later use)
- `refresh_token`: generated refresh token (store it for regenerating expired access token)

### Response on failure

You should see a `400 Bad Request` response with the following JSON body:

```json
{
    "error": "Invalid credentials.",
    "error_description": "Invalid credentials.",
    "message": "Invalid credentials."
}
```

## Refresh admin access token

Send a `POST` request to the `/security/refresh-token` endpoint with `Content-Type` header set to `application/json`.

Set request body to:

```json
{
  "grant_type": "refresh_token",
  "client_id": "admin",
  "client_secret": "admin",
  "scope": "api",
  "refresh_token": "<refresh-token>"
}
```

### Test using curl

Execute the below command:

```shell
curl --location 'https://api.dotkernel.net/security/refresh-token' \
--header 'Content-Type: application/json' \
--data-raw '{
  "grant_type": "refresh_token",
  "client_id": "admin",
  "client_secret": "admin",
  "scope": "api",
  "refresh_token": "<refresh-token>"
}'
```

### Note

> Make sure you replace `<refresh-token>` with the refresh token generated with the access token.

## Refresh user access token

Send a `POST` request to the `/security/refresh-token` endpoint with `Content-Type` header set to `application/json`.

Set request body to:

```json
{
  "grant_type": "refresh_token",
  "client_id": "frontend",
  "client_secret": "frontend",
  "scope": "api",
  "refresh_token": "<refresh-token>"
}
```

### Test using curl

Execute the below command:

```shell
curl --location 'https://api.dotkernel.net/security/refresh-token' \
--header 'Content-Type: application/json' \
--data-raw '{
  "grant_type": "refresh_token",
  "client_id": "frontend",
  "client_secret": "frontend",
  "scope": "api",
  "refresh_token": "<refresh-token>"
}'
```

### Note

> Make sure you replace `<refresh-token>` with the refresh token generated with the access token.

### Response on success

You should see a `200 OK` response with the following JSON body:

```json
{
    "token_type": "Bearer",
    "expires_in": 86400,
    "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.e...wuE39ON1mS5mnTKfA_dSpSWxOmNQdny_AKIbc1qZjMfS24qSUV8HIoOw",
    "refresh_token": "def502005a035c8dfe5456d27e85069813a4f8...0b844e843cd62865662a0e723165752dfd7012491502d3d819c2a61d"
}
```

Field description:

- `token_type`: token type to be set when sending the `Authorization` header (example: `Authorization: Bearer eyJ0e...`)
- `expires_in`: access token lifetime (change here: `config/autoload/local.php` `authentication`->`access_token_expire`)
- `access_token`: generated access token (store it for later use)
- `refresh_token`: generated refresh token (store it for regenerating expired access token)

### Response on failure

You should see a `401 Unauthorized` response with the following JSON body:

```json
{
    "error": "invalid_request",
    "error_description": "The refresh token is invalid.",
    "hint": "Cannot decrypt the refresh token",
    "message": "The refresh token is invalid."
}
```

## Test admin authentication flow

### Step 1: Fail to fetch protected API content

Try to view your admin account by executing:

```shell
curl --location 'https://api.dotkernel.net/admin/my-account'
```

You should get a `403 Forbidden` JSON response.

### Step 2: Generate access token

Generate admin access token by executing:

```shell
curl --location 'https://api.dotkernel.net/security/generate-token' \
--header 'Content-Type: application/json' \
--data-raw '{
  "grant_type": "password",
  "client_id": "admin",
  "client_secret": "admin",
  "scope": "api",
  "username": "admin",
  "password": "dotkernel"
}'
```

You should get a `200 OK` JSON response.

Store the value of `access_token` for later use.

### Step 3: Successfully fetch protected API content

Try again viewing your admin account by executing:

```shell
curl --location 'https://api.dotkernel.net/admin/my-account' \
--header 'Authorization: Bearer <access_token>'
```

Replace `<access_token>` with the previously stored access token.

You should get a `200 OK` JSON response with the requested resource in the body.

## Test user authentication flow

### Step 1: Fail to fetch protected API content

Try to view your admin account by executing:

```shell
curl --location 'https://api.dotkernel.net/user/my-account'
```

You should get a `403 Forbidden` JSON response.

### Step 2: Generate access token

Generate admin access token by executing:

```shell
curl --location 'https://api.dotkernel.net/security/generate-token' \
--header 'Content-Type: application/json' \
--data-raw '{
  "grant_type": "password",
  "client_id": "frontend",
  "client_secret": "frontend",
  "scope": "api",
  "username": "test@dotkernel.com",
  "password": "dotkernel"
}'
```

You should get a `200 OK` JSON response.

Store the value of `access_token` for later use.

### Step 3: Successfully fetch protected API content

Try again viewing your admin account by executing:

```shell
curl --location 'https://api.dotkernel.net/user/my-account' \
--header 'Authorization: Bearer <access_token>'
```

Replace `<access_token>` with the previously stored access token.

You should get a `200 OK` JSON response with the requested resource in the body.
