# AvianSuite auth.md

You are an agent. This file tells you how to register with AvianSuite for your person and get a credential. It is the one way a new agent gets in, whether or not your person already has an account, following the [auth.md](https://workos.com/auth-md) protocol (user-claimed flow, email entrypoint).

Agent audience: AI agents and MCP clients acting for a person who wants their business data (customers, deals, invoices, notes) kept in AvianSuite. Every credential stands for one agent connection on the person's workspace; writes made with it are attributed to that agent and can be undone with `undo_changes`.

- Resource server: https://mcp.aviansuite.com/mcp
- Authorization server: https://app.aviansuite.com
- Supported: `service_auth` (register with the person's email, the person confirms a six-digit code). Not supported: anonymous registration and provider-verified ID-JAG assertions.

## Contract

```yaml
audience: agent
identity_endpoint: https://app.aviansuite.com/agent/identity
register_uri: https://app.aviansuite.com/agent/identity
claim_endpoint: https://app.aviansuite.com/agent/identity/claim
claim_uri: https://app.aviansuite.com/agent/identity/claim
token_endpoint: https://app.aviansuite.com/oauth/token
revocation_uri: https://app.aviansuite.com/oauth/revoke
identity_types_supported: ["service_auth", "identity_assertion"]  # identity_assertion means verified_email: the same email flow
identity_assertion:
  assertion_types_supported: ["verified_email"]
  credential_types_supported: ["urn:ietf:params:oauth:token-type:access_token"]
credential_use: "Authorization: Bearer <access_token> on every request to https://mcp.aviansuite.com/mcp"
```

## Discover

1. Protected Resource Metadata (RFC 9728) is at https://mcp.aviansuite.com/.well-known/oauth-protected-resource and names the authorization server.
2. Authorization Server Metadata (RFC 8414) is at https://app.aviansuite.com/.well-known/oauth-authorization-server. Its `agent_auth` block lists the endpoints above. It carries both the auth.md v0.2 names (`identity_endpoint`, `claim_endpoint`) and the earlier ones (`register_uri`, `claim_uri`); they point at the same endpoints.

## Before you start

You need your person's email. If they have no account, they create one during the claim: a free sandbox with no card, free for 7 days (2 agent connections, 100 MB), then read-only, and deleted after 30 days unless they add a card, which starts the normal 14-day trial with nothing lost.

MCP clients that open a browser for the person (Claude, ChatGPT, Cursor) sign in to an existing account with standard OAuth instead, from the same authorization server metadata.

Only register when your person asked you to connect AvianSuite for them.

## Register

Self-contained registration flow: register with the person's email, give them the code, poll for the token.

```http
POST /agent/identity HTTP/1.1
Host: app.aviansuite.com
Accept: application/json
Content-Type: application/json

{"type": "service_auth", "login_hint": "person@example.com", "agent_name": "Example Agent", "purpose": "Keep ticket status for the help desk"}
```

`agent_name` is optional; it names the agent connection the person approves. `purpose` is optional too: one line on what you will record, which becomes the sandbox's description if the person creates one.

Response:

```json
{
  "registration_id": "reg_...",
  "registration_type": "service_auth",
  "claim_url": "https://app.aviansuite.com/agent/identity/claim",
  "claim_token": "clm_...",
  "claim_token_expires": "2026-10-04T04:00:00Z",
  "post_claim_scopes": ["facts"],
  "claim": {
    "user_code": "123456",
    "verification_uri": "https://app.aviansuite.com/agent/claim?claim_attempt_token=cla_...",
    "expires_in": 600,
    "interval": 5
  }
}
```

Keep `claim_token` secret; it is what pays out the credential.

## Claim ceremony

1. Give your person `claim.verification_uri` and `claim.user_code`. They open the link and type the code there, not back to you. If they have an account, they sign in as the email you registered first. If they don't, AvianSuite emails a link to that address to confirm it is theirs; they open it, set a password, and get a free sandbox you are connected to. Keep polling meanwhile: the claim token stays good for an hour.
2. Poll the token endpoint every `interval` seconds:

```http
POST /oauth/token HTTP/1.1
Host: app.aviansuite.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn:workos:agent-auth:grant-type:claim&claim_token=clm_...
```

- `400 authorization_pending`: the person has not typed the code yet. Keep polling.
- `400 expired_token`: the code expired (10 minutes) or was mistyped five times. Get a new one and give it to your person:

```http
POST /agent/identity/claim HTTP/1.1
Host: app.aviansuite.com
Content-Type: application/json

{"claim_token": "clm_..."}
```

The response's `claim_attempt` block has a new `user_code` and `verification_uri`.

When the person approves, the poll returns once:

```json
{
  "access_token": "avs_at_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "facts",
  "identity_assertion": "<service-signed JWT>",
  "assertion_expires": "2026-11-03T03:00:00Z"
}
```

## Exchange the assertion

There is no refresh token. When the access token expires, trade the identity assertion for a new one:

```http
POST /oauth/token HTTP/1.1
Host: app.aviansuite.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<identity_assertion>
```

The assertion lasts 30 days. After that, or if the person revokes the connection (`invalid_grant`), register again.

## Use the access_token

```http
POST /mcp HTTP/1.1
Host: mcp.aviansuite.com
Authorization: Bearer <access_token>
Content-Type: application/json
Accept: application/json, text/event-stream
```

Send it in the `Authorization` header only, never in a query string.

## Errors

| Status | Where | What to do |
| --- | --- | --- |
| `400 unsupported_identity_type` | `/agent/identity` | Use `"type": "service_auth"` with `login_hint`. |
| `400 invalid_request` | `/agent/identity` | Send the person's email as `login_hint`. |
| `429 slow_down` | `/agent/identity` | Too many registrations; wait for `Retry-After`. |
| `400 authorization_pending` | `/oauth/token` | Keep polling every `interval` seconds. |
| `400 expired_token` | `/oauth/token` | Get a new code at `/agent/identity/claim`. |
| `400 invalid_grant` | `/oauth/token` | The claim token or assertion is invalid, used or revoked: register again. |
| `401` | `/mcp` | The access token expired: exchange the assertion. |

## Revocation

- You: `POST https://app.aviansuite.com/oauth/revoke` with `token=<access_token or identity_assertion>` (RFC 7009). Either one ends the connection.
- The person: revoke the agent connection at https://app.aviansuite.com/account/agents, which cuts you off at once.

More: [Connect an agent over MCP](https://aviansuite.com/docs/mcp/) and [llms.txt](https://aviansuite.com/llms.txt).
