# Machine to machine with cURL

> Add OneiD to a cURL service with Client credentials grant, step by step.

Source: https://oltinid.com/docs/quickstarts/curl/ · Section: Quickstarts · All OneiD documentation: https://oltinid.com/llms.txt

This quickstart adds OneiD to a machine to machine with **Client credentials grant**. Every file is complete and runs as it is.

> **Tip:** Using an AI coding agent? Give it this page as Markdown (add `.md` to the address) together with the [Connector specification](https://oltinid.com/docs/ai/connector-specification/). See [Build with AI coding agents](https://oltinid.com/docs/ai/build-with-ai/).

## Before you start

- A OneiD address, for example `https://YOUR_ONEID`. The code below uses the demonstration instance `https://auth.oltinid.com`; replace it with your own.
- A client registered for this application (step 1). The code uses the client ID `quickstart`; replace it with yours.

## 1. Register the application

Ask your OneiD administrator to register a client with these settings, or register it yourself in the admin console. See [Register an application](https://oltinid.com/docs/get-started/register-an-application/).

| Setting | Value |
|---|---|
| Client type | `confidential` (OneiD generates a secret and shows it once) |
| Grant types | `client_credentials` |
| Allowed scopes | the API scopes the service needs, for example `orders.read` |

## 2. Add the code

`token.sh`

```bash
# A service that calls an API with its own identity (no user). An administrator registers
# a confidential client with the client credentials grant and gives you its ID and secret.

# 1. Read the endpoints.
curl https://auth.oltinid.com/.well-known/openid-configuration

# 2. Get an access token.
curl https://auth.oltinid.com/connect/token \
  --user "$CLIENT_ID:$CLIENT_SECRET" \
  --data grant_type=client_credentials \
  --data scope="$API_SCOPE"

# 3. Call your API with the token.
curl https://api.example.com/orders \
  --header "Authorization: Bearer $ACCESS_TOKEN"
```

## 3. Run it

Set YOUR_CLIENT_ID and YOUR_CLIENT_SECRET, then run the commands one by one.

A client credentials client needs a secret, so it is always a confidential client.

> **Checkpoint:** The first command prints the discovery document as JSON. The second command prints a JSON object; its access_token value is the token that the third command sends to your API.

## Common issues

- **`invalid_client`.** The client ID or secret is wrong, the secret expired, or the client is disabled.
- **`invalid_scope`.** The client is not allowed the scope it asks for.
- **HTTP 429.** Too many token requests. Cache the token until shortly before it expires and wait for the `Retry-After` time.
- More errors and fixes: [Errors and troubleshooting](https://oltinid.com/docs/reference/errors/).

## Learn more

- [Client credentials for services](https://oltinid.com/docs/guides/client-credentials/)
- [Rate limits](https://oltinid.com/docs/reference/rate-limits/)
- [Protect an API](https://oltinid.com/docs/guides/protect-an-api/)
