# Consume internal API as an application

This how-to guides you through the steps required to consume an API secured with [Entra ID](/auth/entra-id.md) as an application (or a machine user).
This is also known as the *machine-to-machine (M2M)* or *client credentials* flow.

## Prerequisites

- The API you're consuming has [granted access to your application](/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> 
```

## Acquire token

Now you can request a new token for the API that you want to consume.

Send a HTTP POST request to the endpoint found in the `NAIS_TOKEN_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. |

**application/json**

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

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

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

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

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

```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)
