---
title: Authentication for agents
description: Atlas by Friendlym uses OAuth 2.1 for agents. Authorization code with PKCE (S256), the device grant for headless agents, dynamic client registration, client ID metadata documents, rotating refresh tokens, and scopes.
canonical: https://tilqui-atlas.pages.dev/docs/auth/?lang=en
lang: en
last_updated: 2026-10-08
alternate_html: https://tilqui-atlas.pages.dev/docs/auth/?lang=en
---

# Authentication for agents

Atlas by Friendlym is an OAuth 2.1 authorization server and a protected resource. Agents get short lived access tokens bound to one person and one workspace, with the scopes that person approved.

## Discovery

| What | Where |
|---|---|
| Protected resource metadata, MCP (RFC 9728) | `https://tilqui-atlas.pages.dev/.well-known/oauth-protected-resource/mcp` |
| Protected resource metadata, REST API | `https://tilqui-atlas.pages.dev/.well-known/oauth-protected-resource/api` |
| Authorization server metadata (RFC 8414) | `https://tilqui-atlas.pages.dev/.well-known/oauth-authorization-server` |

A request without a token to `/mcp` or `/api` answers `401` with `WWW-Authenticate: Bearer resource_metadata="…"`, so a client can start from the URL it was given.

## Endpoints

| Endpoint | Use |
|---|---|
| `POST /oauth/register` | Dynamic client registration (RFC 7591). Public clients: `token_endpoint_auth_method` is `none`. |
| `GET /oauth/authorize` | Authorization code with PKCE. `code_challenge_method=S256` is required. |
| `POST /oauth/token` | `authorization_code`, `refresh_token` and `urn:ietf:params:oauth:grant-type:device_code`. |
| `POST /oauth/device_authorization` | The device grant (RFC 8628) for agents without a browser. |
| `GET /device` | Where the human types the code the agent shows. |
| `POST /oauth/revoke` | Token revocation (RFC 7009). |

Client ID metadata documents are supported: a client may use an `https` URL as its `client_id`, and Atlas by Friendlym reads the client's name and redirect URIs from that document.

## Authorization code with PKCE

This is what Claude Code, Codex and Cursor do on their own.

1. Register: `POST /oauth/register` with `client_name` and `redirect_uris` (https, `http://localhost` or `http://127.0.0.1` with any port, or an app scheme).
2. Send the human's browser to `/oauth/authorize` with `response_type=code`, `client_id`, `redirect_uri`, `code_challenge` (S256), `state`, the `scope` you need and `resource=https://tilqui-atlas.pages.dev/mcp`.
3. The human signs in and sees the consent screen: your agent's name (verified when it comes from a client ID metadata document on your own domain, otherwise marked as self reported), the workspace, and a checkbox per scope you asked for. Only `read` is ticked by default; the human ticks the rest. They approve or deny.
4. Your redirect URI gets `code`, `state` and `iss`. Exchange the code at `/oauth/token` with your `code_verifier` within five minutes.

## Device flow, for headless agents

```sh
# 1. register once (no redirect URI needed)
curl -s https://tilqui-atlas.pages.dev/oauth/register -H 'content-type: application/json' \
  -d '{"client_name":"Build server agent","grant_types":["urn:ietf:params:oauth:grant-type:device_code","refresh_token"]}'

# 2. ask for a code
curl -s https://tilqui-atlas.pages.dev/oauth/device_authorization -d client_id=CLIENT_ID -d resource=https://tilqui-atlas.pages.dev/mcp
# => {"device_code":"…","user_code":"BCDF-GHJK","verification_uri":"https://tilqui-atlas.pages.dev/device",
#     "verification_uri_complete":"https://tilqui-atlas.pages.dev/device?code=BCDF-GHJK","expires_in":900,"interval":5}

# 3. show user_code and the link to your human, then poll every `interval` seconds
curl -s https://tilqui-atlas.pages.dev/oauth/token -d grant_type=urn:ietf:params:oauth:grant-type:device_code \
  -d device_code=DEVICE_CODE -d client_id=CLIENT_ID
```

While the human has not decided, the token endpoint answers `authorization_pending`; poll faster than the interval and it answers `slow_down`. After the human approves on `/device` you get the tokens.

The link only fills in the code box: the human confirms that their agent is showing this code right now before they see the consent screen, which shows how old the request is and the country it came from. A client registered under the name of a well known agent (Claude, Codex, Cursor, ChatGPT and so on) cannot use the device flow; register under your own name.

## Tokens

- Access tokens start with `ato_` and last one hour. Send them as `Authorization: Bearer …`.
- Refresh tokens start with `atr_`, last 30 days and rotate: every refresh returns a new one and the old one stops working. Presenting a used refresh token again revokes the whole grant, so a stolen token cannot be replayed quietly.
- Every token is bound to the person who approved it and to their workspace, and never outlives the approval (90 days by default).
- Every token has its own scopes and audiences (RFC 8707). Send `resource=https://tilqui-atlas.pages.dev/mcp`, `https://tilqui-atlas.pages.dev/api` or both; a token for one does not work on the other. A refresh may narrow the scopes or audiences, never widen them.
- The person can remove the agent at any time on the Connect page; its tokens stop working at once.

## Scopes

| Scope | Grants |
|---|---|
| `read` | Read the projects, dossiers and sources the person can see |
| `ask` | `ask_atlas`, with a daily limit per agent |
| `inbox` | Questions between the customer and the agency; answers are drafts the person confirms |
| `tasks` | The tasks assigned to the person, and progress notes on them |
| `agent_context` | Project context the agency shares with agents |
| `direction` | Direction packages for the person's projects, and confirming the tasks they propose |

Ask only for what you need with `scope=…`; without it every scope is offered. The person ticks among them on the consent screen, with only `read` ticked by default, and the token response's `scope` says what was granted.

## Pairing tokens

Before OAuth, agents connected with a pairing line from the Connect page (`atl_` tokens). Those keep working and show on the Connect page next to OAuth agents.
