# Create Token

> POST /v1/auth/tokens · Access management API

Source: https://developer.kustomer.com/api/access-management/create-token

```http
POST https://{orgname}.api.kustomerapp.com/v1/auth/tokens
```

## Authorization

No authentication. Callable without an API key.

Logs in to an organization with domain, email, and password.

#### NOTE
> **Machine tokens** can be created within the settings section by an administrator for API, tracking, and hook access

## About API keys and auth tokens

An auth token is the bearer credential sent with every API request. API keys are long-lived tokens that belong to a machine user with a fixed set of roles; session tokens are created when a person signs in. These endpoints list, inspect and revoke tokens.

Every request to the Kustomer API carries a token in `Authorization: Bearer <token>`, and each token belongs to a [user](https://developer.kustomer.com/api/access-management#users). API keys are created by admins in **Settings › Security › API Keys**. Each one is backed by its own machine user, has roles that are chosen when it's created and can't be edited, and can have an expiry and an IP range restriction. Session tokens are created when a person signs in to Kustomer and act with that person's roles. A token works until it expires or is deleted.

`POST /v1/auth/tokens` is the sign-in call behind the second kind: it takes an org `domain` with an `email` and `password` (or a Google or SAML sign-in token) and returns a session token for that person. It does not create API keys. Integrations should use an API key or [OAuth](https://developer.kustomer.com/docs/get-started/oauth) rather than storing someone's password.

#### What a token record shows

| Field | Meaning |
| --- | --- |
| `name` | The token's name; for an API key, the name it was given in Settings |
| `roles` | What the token is allowed to do |
| `lastTokenChars` | The last characters of the token, to tell keys apart |
| `lastAccessedAt` | When it was last used |
| `ipAddress`, `userAgent` | The IP address and client recorded with the token |
| `user` | The user the token acts as, in `relationships` |

The full token value is only returned when the token is created. After that, nothing in the API returns it again, so store a new API key in your secrets manager immediately.

#### Whose tokens you can see

`GET /v1/auth/tokens` needs a security admin role and by default returns the current user's tokens. Pass `userType` (`user`, `machine`, `limited` or `app`) to list tokens for that kind of user; `userType=machine` lists your org's API keys. `filter` matches the start of the token `name`. Any token can read or delete itself through `/v1/auth/tokens/current`, and the `/{id}` endpoints also work on your own tokens; acting on someone else's needs `org.admin.security` or `org.permission.security`.

#### Which endpoint to use

| To | Call |
| --- | --- |
| Check which user and roles the token you're using has | [`GET /v1/auth/tokens/current`](https://developer.kustomer.com/api/access-management/get-current-auth-token) |
| Revoke the token you're using, such as on sign-out | [`DELETE /v1/auth/tokens/current`](https://developer.kustomer.com/api/access-management/delete-current-auth-token) |
| List tokens, such as every API key in the org | [`GET /v1/auth/tokens`](https://developer.kustomer.com/api/access-management/get-auth-tokens) |
| Read or revoke a specific token | [`GET`](https://developer.kustomer.com/api/access-management/get-auth-token-by-id) or [`DELETE /v1/auth/tokens/{id}`](https://developer.kustomer.com/api/access-management/delete-auth-token-by-id) |
| Sign a person in with their credentials | [`POST /v1/auth/tokens`](https://developer.kustomer.com/api/access-management/create-token) |

Because a key's roles can't change, rotating a key means replacing it: create a new key with the same roles, deploy it, watch the old key's `lastAccessedAt` until it stops moving, then delete the old key. A deleted or expired token fails with `401`. `GET /v1/auth/tokens/current` works with any valid token, which makes it a good health check. Token lists are paginated with `page` and `pageSize` (up to 500).

Related: [API keys and roles](https://developer.kustomer.com/docs/get-started/api-keys-and-roles), [Authentication overview](https://developer.kustomer.com/docs/get-started/authentication), [Users](https://developer.kustomer.com/api/access-management#users), [Role groups](https://developer.kustomer.com/api/access-management#role-groups)

### Recipes

#### 1. Check your API key's access when an integration starts

Fail fast with a clear message if the key is missing, revoked or lacks a role, instead of failing later on the first real request.

**Step 1.** [`GET /v1/auth/tokens/current`](https://developer.kustomer.com/api/access-management/get-current-auth-token.md). Read the key's own record. A `401` means the key is wrong, expired or deleted. Otherwise compare `roles` with the roles your integration needs, and log `lastTokenChars` so you can tell which key is deployed without logging the key itself.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/auth/tokens/current" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/auth/tokens/current \
  | jq -e '.data.attributes.roles | index("org.permission.customer.read")' > /dev/null \
  || echo "API key is missing org.permission.customer.read" >&2
```

**Step 2.** [`GET /v1/users/current`](https://developer.kustomer.com/api/access-management/get-current-user.md). Read the user the key acts as. For an API key this is its own machine user, and every change the integration makes is attributed to it.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/users/current" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/users/current --fields id,attributes.name,attributes.userType
```

> An API key's roles are fixed when it's created. If one is missing, create a new key with the right roles and switch to it as in the rotation recipe below. See [API keys and roles](https://developer.kustomer.com/docs/get-started/api-keys-and-roles) for choosing roles.

#### 2. Find API keys nobody is using

List your org's API keys with when each was last used, so you can revoke the ones that have gone quiet.

**Step 1.** [`GET /v1/auth/tokens`](https://developer.kustomer.com/api/access-management/get-auth-tokens.md). List API keys with `userType=machine`. This needs a security admin role. `lastAccessedAt` is updated as a key is used, though not on every request, so it's accurate to within a few minutes.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/auth/tokens?userType=machine&pageSize=500" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/auth/tokens --query userType=machine --query pageSize=500 --all \
  | jq -r --arg cutoff "$(date -u -v-90d +%Y-%m-%dT%H:%M:%SZ)" \
    'select((.data.attributes.lastAccessedAt // .data.attributes.createdAt) < $cutoff)
      | [.data.id, .data.attributes.name, .data.attributes.lastTokenChars, .data.attributes.lastAccessedAt] | @tsv'
```

**Step 2.** [`GET /v1/auth/tokens/{id}`](https://developer.kustomer.com/api/access-management/get-auth-token-by-id.md). Before revoking a key, check with its owner and read it again to make sure it hasn't been used since you listed it.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/auth/tokens/$TOKEN_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/auth/tokens/$TOKEN_ID --fields attributes.name,attributes.lastAccessedAt
```

**Step 3.** [`DELETE /v1/auth/tokens/{id}`](https://developer.kustomer.com/api/access-management/delete-auth-token-by-id.md). Revoke the key. This can't be undone; anything still using it gets `401` from then on, and the only fix is a new key.

```bash title="cURL"
curl --request DELETE "https://api.kustomerapp.com/v1/auth/tokens/$TOKEN_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api DELETE /v1/auth/tokens/$TOKEN_ID --confirm --yes
```

> The cutoff uses BSD `date`, as on macOS; with GNU `date`, use `date -u -d '90 days ago' +%Y-%m-%dT%H:%M:%SZ`.

#### 3. Rotate an API key without downtime

Replace a key with a new one that has the same roles, switch your integration over, and revoke the old key only once nothing uses it.

**Step 1.** [`GET /v1/auth/tokens/current`](https://developer.kustomer.com/api/access-management/get-current-auth-token.md). With the old key, read its own record and note its `id` and `roles`. You need the ID to watch and revoke it later.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/auth/tokens/current" \
  --header "Authorization: Bearer $OLD_KUSTOMER_API_KEY"
```

```bash title="kusty"
KUSTY_API_KEY=$OLD_KUSTOMER_API_KEY kusty api GET /v1/auth/tokens/current --fields id,attributes.roles
```

**Step 2.** Create the new key in **Settings › Security › API Keys** with the same roles, and store it in your secrets manager straight away. Its full value is shown only once.

**Step 3.** [`GET /v1/auth/tokens/current`](https://developer.kustomer.com/api/access-management/get-current-auth-token.md). With the new key, confirm it works and that its `roles` match the old key's, then deploy it everywhere the old key was used.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/auth/tokens/current" \
  --header "Authorization: Bearer $NEW_KUSTOMER_API_KEY"
```

```bash title="kusty"
KUSTY_API_KEY=$NEW_KUSTOMER_API_KEY kusty api GET /v1/auth/tokens/current --fields id,attributes.roles
```

**Step 4.** [`GET /v1/auth/tokens/{id}`](https://developer.kustomer.com/api/access-management/get-auth-token-by-id.md). Watch the old key's `lastAccessedAt`. Wait until it has stopped moving for longer than your slowest scheduled job runs, because a forgotten job or server may still be using it. Reading another user's token needs a security admin role.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/auth/tokens/$OLD_TOKEN_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/auth/tokens/$OLD_TOKEN_ID --fields attributes.lastAccessedAt
```

**Step 5.** [`DELETE /v1/auth/tokens/current`](https://developer.kustomer.com/api/access-management/delete-current-auth-token.md). Revoke the old key by calling this endpoint with the old key itself. A key can always revoke itself, so this works without a security admin role. With one, [`DELETE /v1/auth/tokens/{id}`](https://developer.kustomer.com/api/access-management/delete-auth-token-by-id) and the old key's ID does the same.

```bash title="cURL"
curl --request DELETE "https://api.kustomerapp.com/v1/auth/tokens/current" \
  --header "Authorization: Bearer $OLD_KUSTOMER_API_KEY"
```

```bash title="kusty"
KUSTY_API_KEY=$OLD_KUSTOMER_API_KEY kusty api DELETE /v1/auth/tokens/current --confirm --yes
```

> Once it's revoked, requests with the old key fail with `401`. If something breaks, deploy the new key there; the old one can't be restored.

### Example object

A real record from [`GET /v1/auth/tokens/{id}`](https://developer.kustomer.com/api/access-management/get-auth-token-by-id.md):

```json
{
  "type": "auth_token",
  "id": "5822276811e88a1000787abe",
  "attributes": {
    "lastTokenChars": "xyz123",
    "name": "API Token",
    "ipAddress": "::ffff:10.0.5.222",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
    "roles": [
      "org"
    ],
    "updatedAt": "2016-11-08T19:28:40.280Z",
    "createdAt": "2016-11-08T19:28:40.280Z",
    "lastAccessedAt": "2016-11-08T19:28:40.280Z"
  },
  "relationships": {
    "org": {
      "links": {
        "self": "/v1/orgs/57f29863a1dbf61100e6aa92"
      },
      "data": {
        "type": "org",
        "id": "57f29863a1dbf61100e6aa92"
      }
    },
    "user": {
      "links": {
        "self": "/v1/users/58190b991f2932100010d683"
      },
      "data": {
        "type": "user",
        "id": "58190b991f2932100010d683"
      }
    }
  },
  "links": {
    "self": "/v1/auth/tokens/5822276811e88a1000787abe"
  }
}
```

Fields:

- `attributes.lastTokenChars` (string): The last 6 characters of the token, for telling keys apart. The full token is only returned once, when it's created.
- `attributes.name` (string): The token's name; for an API key, the name it was given in Settings. The `filter` parameter on `GET /v1/auth/tokens` matches the start of it.
- `attributes.ipAddress` (string): The IP address recorded when the token was created, such as the one a person signed in from. It isn't updated as the token is used.
- `attributes.userAgent` (string): The client recorded when the token was created, such as the browser a person signed in with.
- `attributes.roles` (array): What the token is allowed to do. For an API key, the roles chosen when it was created, limited to roles its creator held.
- `attributes.lastAccessedAt` (string): When the token was last used. It isn't updated on every request, so treat it as accurate to a few minutes. Use it to spot unused keys and to confirm a replaced key has gone quiet.
- `relationships.user` (object): The user the token acts as. Anything the token changes is attributed to this user.

### Relationships

- Points to **Users** via `relationships.user`: The user an auth token acts as, either the person who signed in or the machine user created for an API key. Anything the token changes is attributed to that user.

### Permissions

Fewest roles for a read-only integration: `org.permission.security`. For every endpoint: `org.permission.security`.

## Request body

Content type: `application/json`

- Any of:
  - any
  - any
  - any
  - any
- `domain` (string): (min length 3; max length 256; pattern ^[a-zA-Z0-9]{1}[a-zA-Z0-9-_]+$)
- `email` (string<email>): (max length 256)
- `password` (string): (min length 3; max length 256)
- `singleAccessToken` (string): (max length 256)
- `googleAuthToken` (string)
- `samlAuthToken` (string)
- `remember` (boolean)

Example:

```json
null
```

## Responses

### 201

Created

- `data` (object, required)
  - `type` (string, required)
  - `id` (string, required)
  - `attributes` (object, required)
    - `token` (string, required)
    - `lastTokenChars` (string, required)
    - `name` (string, required)
    - `ipAddress` (string, required)
    - `userAgent` (string, required)
    - `roles` (array<string>, required)
    - `updatedAt` (string, required)
    - `createdAt` (string, required)
    - `lastAccessedAt` (string, required)
  - `relationships` (object, required)
    - `org` (object, required)
    - `user` (object, required)
  - `links` (object, required)
    - `self` (string, required)

```json
{
  "data": {
    "type": "auth_token",
    "id": "5822276811e88a1000787abe",
    "attributes": {
      "token": "...",
      "lastTokenChars": "xyz123",
      "name": "API Token",
      "ipAddress": "::ffff:10.0.5.222",
      "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
      "roles": [
        "org"
      ],
      "updatedAt": "2016-11-08T19:28:40.280Z",
      "createdAt": "2016-11-08T19:28:40.280Z",
      "lastAccessedAt": "2016-11-08T19:28:40.280Z"
    },
    "relationships": {
      "org": {
        "links": {
          "self": "/v1/orgs/57f29863a1dbf61100e6aa92"
        },
        "data": {
          "type": "org",
          "id": "57f29863a1dbf61100e6aa92"
        }
      },
      "user": {
        "links": {
          "self": "/v1/users/58190b991f2932100010d683"
        },
        "data": {
          "type": "user",
          "id": "58190b991f2932100010d683"
        }
      }
    },
    "links": {
      "self": "/v1/auth/tokens/5822276811e88a1000787abe"
    }
  }
}
```

### 400

Bad Request - Invalid request parameters or body

### 401

Unauthorized - Authentication required or invalid credentials

## Example request

```bash
curl --request POST \
  --url 'https://api.kustomerapp.com/v1/auth/tokens' \
  --header 'Content-Type: application/json' \
  --data 'null'
```
