# Get an access token for a backend service

Sign a backend service in as itself with the client credentials grant, and get an access token for the one API it calls.

A backend service that calls another service has no person to sign in. It signs in as itself with the `client_credentials` grant (RFC 6749, section 4.4), and receives an access token for the one API it calls.

Use this guide for a service that holds a client secret. For an AI agent, see [Give an AI agent an identity](/quickstart/agent). An agent holds its own key, never a shared secret.

## Before you begin

You need:

- An AuthFI project and its issuer, the project's URL. This guide uses `https://acme.authfi.io`.
- Permission to add applications in the AuthFI console.
- The API you want to call, registered as an application in the same project. You need its client ID.

<Steps>

### Register the calling service

1. In the console, open **Integrations > Applications** and choose **Register**.
2. Select **OIDC / OAuth 2.0**, then choose **Continue**.
3. Select the kind **Machine-to-machine**.
4. Enter a **Name**.
5. Check the **Review** step, then choose **Register**.

The **Done** step shows the application's client ID, and its **Client secret**. The client secret is shown once. Copy both, then tick **I have copied the client secret**.

```bash
export CLIENT_ID=<the calling service's client ID>
export CLIENT_SECRET=<the calling service's client secret>
```

### Grant the service access to the API

An access token is issued for one API, named by that API's client ID. The calling service must hold a grant on the API's application before it can request a token for it.

1. On the **Done** step, choose the button that opens the application. You can also open it later from **Integrations > Applications**.
2. On the application's page, choose **Allow an API** and allow the API you want to call.

The APIs the service can call are listed in the **APIs it may call** section of its page.

```bash
export API_CLIENT_ID=<the API's client ID>
```

### Request an access token

Send the service's client ID and client secret to the token endpoint, and name the API in `resource`. The body is form-encoded.

<Endpoint method="POST" path="/oauth/token" />

<Tabs labels={["Shell", "Node.js", "Python"]}>

```bash
curl https://acme.authfi.io/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=client_credentials \
  -d resource="$API_CLIENT_ID"
```

```js
const res = await fetch("https://acme.authfi.io/oauth/token", {
  method: "POST",
  headers: {
    authorization: "Basic " + Buffer.from(`${process.env.CLIENT_ID}:${process.env.CLIENT_SECRET}`).toString("base64"),
    "content-type": "application/x-www-form-urlencoded",
  },
  body: new URLSearchParams({ grant_type: "client_credentials", resource: process.env.API_CLIENT_ID }),
});
const { access_token, expires_in } = await res.json();
```

```python
import os, requests

res = requests.post(
    "https://acme.authfi.io/oauth/token",
    auth=(os.environ["CLIENT_ID"], os.environ["CLIENT_SECRET"]),
    data={"grant_type": "client_credentials", "resource": os.environ["API_CLIENT_ID"]},
)
token = res.json()["access_token"]
```

</Tabs>

| Parameter    | Value                                                                                                                 |
| ------------ | --------------------------------------------------------------------------------------------------------------------- |
| `grant_type` | `client_credentials`                                                                                                  |
| `resource`   | Optional. The client ID of the one API the token is for. Without it, the token is for the calling application itself. |
| `scope`      | Optional. The scopes to put in the token.                                                                             |

AuthFI returns an access token:

```json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6Ii4uLiJ9...",
  "token_type": "Bearer",
  "expires_in": 900
}
```

The response contains an access token only, with no refresh token and no ID token. `expires_in` is in seconds. When the access token expires, request another.

### Validate the access token at the API

The API validates the access token against the project's keys, and checks that `aud` contains the API's own client ID. For the full list of checks, see [Checking a token](/reference/tokens#checking-a-token).

</Steps>

## Check that it works

Decode the payload of the access token and read its claims.

```bash
python3 -c 'import base64, json, sys; p = sys.argv[1].split(".")[1]; print(json.dumps(json.loads(base64.urlsafe_b64decode(p + "=" * (-len(p) % 4))), indent=2))' "$ACCESS_TOKEN"
```

`$ACCESS_TOKEN` is the `access_token` from the previous response. The flow works when `sub` and `client_id` are the calling service's client ID, and `aud` contains the API's client ID.

## What the access token contains

| Claim       | Value                                                 |
| ----------- | ----------------------------------------------------- |
| `sub`       | The calling service's client ID                       |
| `client_id` | The calling service's client ID                       |
| `aud`       | The API named in `resource`                           |
| `scope`     | The scopes you asked for, unchanged                   |
| `exp`       | 15 minutes after issue, unless the project changed it |

The access token has no `sid`, `amr` or `acr` claim, because no person signed in. Every claim is described in [Tokens and claims](/reference/tokens).

## Call more than one API

An access token is accepted at one API, the one named in `resource`. This stops an access token taken from one service from being used at another.

To call two APIs, request two access tokens, one for each `resource`. The calling service needs a grant on each API's application.

## Troubleshooting

The token endpoint answers a failure with an OAuth error in `error`.

| What you see          | Cause                                                                                                 | Fix                                                                                                                                                                                                                                        |
| --------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `invalid_client`      | The client ID is unknown, the client secret is wrong, or the calling application has no client secret | Check both values. If the client secret is lost, choose **Rotate the secret** on the application's page. An application with no client secret cannot use this grant: register the calling service as a **Machine-to-machine** application. |
| `unauthorized_client` | The application is not of the kind **Machine-to-machine**                                             | Register the calling service as a **Machine-to-machine** application                                                                                                                                                                       |
| `invalid_target`      | `resource` is not an application, or the service has no grant on it                                   | Send the API's client ID in `resource`, and use **Allow an API** on the service's page                                                                                                                                                     |

Every error is listed in the [endpoint reference](/reference/oauth#errors).

## Next steps

<Cards>
  <Card href="/applications/types" title="Application types and redirect URIs">
    How a machine-to-machine application differs from the types that sign people in.
  </Card>
  <Card href="/reference/tokens" title="Tokens and claims">
    Every claim in an access token, and how a service checks one.
  </Card>
  <Card href="/zero-code/protect-api" title="Protect an API">
    Require an access token at an API on Kubernetes, without changing its code.
  </Card>
  <Card href="/quickstart/agent" title="Give an AI agent an identity">
    Sign an agent in with its own key instead of a client secret.
  </Card>
</Cards>
