---
title: Authentication
slug: api-docs/authentication
description: How to authenticate against the Litmus Edge, Edge Manager, and Unify APIs. Token issuance, session lifetimes, required headers, and common 401/403 causes.
docTags: 
createdAt: 2026-05-11T22:00:46.270Z
---

# Authentication

All Litmus APIs use OAuth2 `client_credentials`. You exchange a `client_id` and `client_secret` for a short-lived Bearer token, then send that token on every subsequent API call.

## Litmus Edge

### Token endpoint

```javascript
POST {{edgeUrl}}/auth/v3/oauth/token
```

:::BlockQuote
Important: use `/auth/v3/oauth/token`. The Keycloak admin URL (`/auth/realms/...`) you may see in the Edge admin UI is **not** the API token endpoint.
:::

### Request

```bash
curl -X POST "https://<edge-host>/auth/v3/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=<your_client_id>" \
  -d "client_secret=<your_client_secret>"
```

### Response

```json
{
  "access_token": "eyJhbGciOi...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

### Using the token

```bash
curl "https://<edge-host>/devicehub/version" \
  -H "Authorization: Bearer eyJhbGciOi..."
```

## Litmus Edge Manager (LEM)

LEM uses a long-lived admin API token rather than OAuth2 exchange. Generate one from the LEM Admin Console.

Two headers are used depending on the endpoint prefix:

| Endpoint prefix | Header                                 |
| --------------- | -------------------------------------- |
| `/api/v1/...`   | `X-AuthToken: <token>`                 |
| `/admin/v1/...` | `X-AuthToken: <token>`                 |
| `/mpcs/...`     | `Authorization: <token>` (no `Bearer`) |

:::BlockQuote
Sending the wrong header returns 401. The `/mpcs/` marketplace endpoints use a plain `Authorization` header value, the other prefixes use `X-AuthToken`. See [LEM base URLs](#).
:::

## Litmus UNS

UNS uses OAuth2 password grant against its bundled Keycloak.

```javascript
POST {{uns_url}}/auth/realms/standalone/protocol/openid-connect/token
```

Body (form-encoded): `grant_type=password`, `client_id`, `username`, `password`.

The returned `access_token` is sent as `Authorization: Bearer <token>` on every `/mqtt/gql` GraphQL call.

## Token lifetime and refresh

- LE tokens default to 1 hour (`expires_in: 3600`). Re-fetch before expiry.
- LEM admin tokens are long-lived; rotate via the Admin Console.
- UNS tokens follow the Keycloak realm policy (typically 15-60 minutes).

## Where to get credentials

| Product     | Where                                             |
| ----------- | ------------------------------------------------- |
| Litmus Edge | System -> Settings -> Users -> API Clients        |
| LEM         | Admin Console -> API Tokens                       |
| LUNS        | Admin -> Users (use the configured Keycloak user) |

