# Consume internal API on behalf of an employee

This how-to guides you through the steps required to consume an API secured with [Entra ID](/auth/entra-id.md) on behalf of an employee.
This is also known as the *on-behalf-of (OBO)* flow.

## Prerequisites

- Your application receives requests with an employee subject token in the `Authorization` header. Your application is either:- [a backend API secured with Entra ID](/auth/entra-id/how-to/secure.md), or
  - [a backend-for-frontend that logs in employees](/auth/entra-id/how-to/login.md)
- The API you're consuming has [granted access to your application and employees](/auth/entra-id/how-to/secure.md#grant-access-to-consumers)

## Configure your application

Enable Entra ID in your application:

```yaml
spec:
  azure:
    application:
      enabled: true
```

Depending on how you communicate with the API you're consuming, [configure the appropriate outbound access policies](/workloads/explanations/zero-trust.md#outbound-traffic):

**Service discovery**

```yaml
spec:
  accessPolicy:
    outbound:
      rules:
        - application: <some-api>
          namespace: <some-team>
```

**External addresses**

```yaml
spec:
  accessPolicy:
    outbound:
      external:
        - host: <some-host> 
```

## Exchange token

Now you can exchange the employee's subject token for a new token, targeting the API that you want to consume.

Send a HTTP POST request to the endpoint found in the `NAIS_TOKEN_EXCHANGE_ENDPOINT` environment variable.
The request must have a `Content-Type` header set to either:

- `application/json` or
- `application/x-www-form-urlencoded`

The body of the request should contain the following parameters:

| Parameter | Example Value | Description |
| :--- | :--- | :--- |
| `identity_provider` | `entra_id` | Always `entra_id`. |
| `target` | `<cluster>:<namespace>:<other-api-app-name>` | The intended *audience* (target API or recipient) of the new token. The legacy format `api://<cluster>.<namespace>.<other-api-app-name>/.default` is also accepted. |
| `user_token` | `eyJra...` | The user's access token from the inbound request. Token that should be exchanged. |

**application/json**

```http
POST ${NAIS_TOKEN_EXCHANGE_ENDPOINT} HTTP/1.1
Content-Type: application/json

{
    "identity_provider": "entra_id",
    "target": "<cluster>:<namespace>:<other-api-app-name>",
    "user_token": "eyJra..."
}
```

**application/x-www-form-urlencoded**

```http
POST ${NAIS_TOKEN_EXCHANGE_ENDPOINT} HTTP/1.1
Content-Type: application/x-www-form-urlencoded

identity_provider=entra_id&
target=<cluster>:<namespace>:<other-api-app-name>&
user_token=eyJra...
```

```json
{
    "access_token": "eyJra...",
    "expires_in": 3599,
    "token_type": "Bearer"
}
```

Your application does not need to validate this token.

> **Tokens are automatically cached by default**
> The endpoint will always return a cached token, if available.
> The endpoint will never return an expired token.

> To forcibly get a new token, set the `skip_cache` property to `true` in the request.
> This is only necessary if the token is denied by the target API, for example if permissions have changed since the token was issued.

## Consume API

Once you have acquired a new token, you can finally consume the target API by using the token as a [Bearer token](/auth/explanations.md#bearer-token):

```http
GET /resource HTTP/1.1

Host: api.example.com
Authorization: Bearer eyJraWQ...
```

## Related pages

📚 [Entra ID reference](/auth/entra-id/reference.md)
