---
title: Authentication
description: Learn how to authenticate with NoLag using access tokens and API keys.
---

# Authentication

NoLag has two kinds of credential, and they are not interchangeable:

| Credential | Used for | Where it goes |
|---|---|---|
| **API key** | Managing resources over the REST API: apps, rooms, actors | Your backend or a setup script |
| **Access token** | Connecting a client to the broker over WebSocket | The client, or a backend service |
| **Client token** | Connecting an untrusted browser or mobile client | Minted per session by your backend |

## API Keys

An API key authenticates calls to the [REST API](/docs/api-reference) at
`https://api.nolag.app/v1`. It is the one credential you create by hand, and it is
the bootstrap secret for scripted or agent-driven setup.

API keys are **project-scoped**, so the key itself determines which project's
resources you can reach and no organization or project id appears in the URL.

### Creating an API Key

1. Log in to the [NoLag Dashboard](https://portal.nolag.app).
2. Open your project and go to **API Keys**.
3. Create a key and copy it immediately. The secret half is shown only once.

### Key Format

```bash [Terminal]
nlg_live_{keyId}.{secret}
```

Live keys are prefixed `nlg_live_`, sandbox keys `nlg_sandbox_`. Send the whole
string, including the dot and the secret, as a bearer token:

```bash [Terminal]
curl https://api.nolag.app/v1/apps \
  -H "Authorization: Bearer nlg_live_xxx.secret"
```

An API key can create and delete every app, room, and actor in its project. Keep it
on a server, never in a browser, mobile binary, or public repository.

## Access Tokens

Access tokens are used to authenticate your clients with NoLag. Each token is associated with an Actor (user, device, or server) and determines what topics they can access.

### Obtaining Tokens

1. Log in to the [NoLag Dashboard](https://portal.nolag.app)
2. Navigate to your project
3. Go to **Actors** section
4. Create a new Actor or select an existing one
5. Copy the access token (shown only once on creation)

## Using Access Tokens

```typescript [TypeScript]
import { NoLag } from '@nolag/js-sdk'

// Using an access token
const client = NoLag('your_access_token')
await client.connect()

console.log('Authenticated and connected!')
```
```python [Python]
from nolag import NoLag

# Using an access token
client = NoLag('your_access_token')
await client.connect()

print('Authenticated and connected!')
```
```go [Go]
package main

import (
    "fmt"

    nolag "github.com/NoLagApp/go-sdk"
)

func main() {
    // Using an access token
    client := nolag.New("your_access_token")
    client.Connect()

    fmt.Println("Authenticated and connected!")
}
```

## Client Tokens (Browser and Mobile)

Access tokens are long-lived, so they belong on servers, not in browsers. For untrusted clients, your backend mints a short-lived JWT (a **client token**) signed with a project-level signing key, and the browser connects with that instead:

```typescript [Browser]
import { NoLag } from '@nolag/js-sdk'

// The SDK calls your endpoint for a fresh token on every connect
const client = NoLag(async () => {
  const res = await fetch('/api/nolag-token')
  const { token } = await res.json()
  return token
})
await client.connect()
```

The client token names an actor and expires within minutes; all permissions still resolve from the actor. See the full guide: [Client Tokens](/docs/client-tokens).

## Actor Types

Every actor is created with an `actorType`. It describes what the connection is,
which makes actors easier to filter and audit — and for two of them it also
changes how the broker treats the connection:

| `actorType` | Use for | Session |
|---|---|---|
| `device` | Browsers, mobile apps, IoT hardware | clean |
| `user` | Authenticated end users | clean |
| `service` | Backend services and microservices | clean |
| `session` | Short-lived or temporary connections | clean |
| `agent` | Autonomous LLM-powered connections | **persists** |
| `orchestrator` | Coordination actors that dispatch work across agents | **persists** |
| `observer` | Read-only audit and monitoring connections | clean |

Permissions come from the actor's topic access, not from its type. See
[Access Control](/docs/concepts/acl).

### Why the session column matters

`agent` and `orchestrator` connections hold a **persistent session**. When one
disconnects, the broker keeps its subscriptions and queues messages for it, so a
worker that goes away finds its work waiting when it comes back. That is what
makes an agent that scales to zero — or is woken by a webhook — workable.

It has two consequences worth knowing before you pick a type.

**A session belongs to a client instance, not to a credential.** Two processes
sharing one agent token are two attempts at the same session: the first keeps a
resumable one and the rest get clean sessions instead. If you want several
concurrent workers under one token to each keep their own, give each a stable
[`clientId`](/docs/protocol#1-authentication):

```typescript [TypeScript]
const client = NoLag(token, { clientId: process.env.WORKER_NAME })
```

**Sessions expire on the plan's session window.** A subscription left behind by
a persistent connection survives until then, so an agent that reconnects under a
different load-balance group name can briefly belong to both.

If you do not want any of this — a per-request connection, a browser, a
short-lived job — use `service`, `session` or `device`. They connect clean, any
number of them can share a token concurrently, and nothing is retained when they
go.

## Security Best Practices

- **Never ship an access token to a browser** - Mint short-lived [client tokens](/docs/client-tokens) on your backend instead
- **Rotate tokens regularly** - Especially for production environments
- **Use least privilege** - Only grant necessary permissions to each Actor
- **Monitor usage** - Check the dashboard for unusual activity

## Next Steps

- [Client Tokens](/docs/client-tokens)
- [Quick Start Guide](/docs/getting-started)
- [Access Control Lists](/docs/concepts/acl)
