> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aion.to/llms.txt
> Use this file to discover all available pages before exploring further.

# Caller Authentication

> Identify callers to Python SDK servers with signed invocation tokens and renewable guest sessions.

Python SDK servers receive different credentials depending on whether a request comes through Aion or directly from
a guest client. Verify the credential to identify the caller, then check access to the requested context or task.
Authentication alone does not grant conversation access.

<Warning>
  The control-plane endpoints and Aion Chat client credential delivery are implemented. SDK server verification and
  resource-access enforcement for this contract are still pending. The server modes below describe the required behavior,
  not available configuration switches. Check receiver support before relying on this workflow in a deployment.
</Warning>

## Server Authentication Modes

* **Hosted deployment:** `DEPLOYMENT_ID` identifies a hosted runtime, which must require a verified invocation token.
* **Remote deployment:** managed authentication enforcement is opt-in and disabled by default.
* **Local development without client credentials:** require a verified anonymous session token. Public verification
  keys are sufficient; the server does not need a client secret to verify the signature.

Decoding a JWT is not verification. In each enforced mode, verify its signature and claims before using its caller
identity. Apply resource-access checks to task reads, cancellation, continuation, subscriptions, framework state,
and push configuration as well as context history.

## Credential Paths

| Path | Credential | Purpose |
| - | - | - |
| Signed-in client → Aion | Account access token | Identify the user; retain existing authorization. |
| Guest → public Aion A2A | Session bearer | Identify one guest without a user record. |
| Guest → local SDK server | Session bearer | Identify the guest on a direct request. |
| Aion → managed runtime | Invocation bearer | Identify the caller and destination runtime. |
| Runtime → Aion | Version access token | Retain the client ID/secret exchange and Version permissions. |

Use `Authorization: Bearer <token>`. Guest and invocation bearers are **ES256-signed JWTs, not encrypted**.
Their payload is readable; the signature prevents undetected modification. Use HTTPS except for explicitly configured
loopback development. Do not log, place in URLs, or expose these tokens to unrelated origins.

Usage attribution and push-callback credentials remain separate. An invocation bearer does not replace the Version
token used for calls back to Aion, authorize a push callback, or grant organization membership or agent impersonation.

## Public Verification Keys

Retrieve public keys from the configured Aion control-plane base URL:

```http theme={null}
GET /runtime/a2a/verification-keys
```

No authentication is required. The response is a JSON Web Key Set (JWKS) with content type
`application/jwk-set+json`. It contains the current public P-256 verification key, never the private signing key.

This illustrative response uses placeholders for the key coordinates and identifier:

```json theme={null}
{
  "keys": [
    {
      "kty": "EC",
      "crv": "P-256",
      "x": "<base64url-x-coordinate>",
      "y": "<base64url-y-coordinate>",
      "alg": "ES256",
      "use": "sig",
      "kid": "<key-thumbprint>"
    }
  ]
}
```

Match the JWT's protected `kid` to the returned key. Its value is the JWK's RFC 7638 SHA-256 thumbprint.
The endpoint permits five minutes of HTTP caching. Only the current key is published; rotation overlap is not provided.

Configure the trusted API URL and expected issuer independently: the issuer label is not necessarily the API URL.
Never discover a key server from an unverified token or follow token-provided `jku`, `x5u`, or embedded keys.

Fernet storage encryption is unrelated. `GET /runtime/a2a/encryption-key` remains protected by a Version API credential
and returns secret storage-encryption material for that authorized runtime. It is **not** included in the public JWKS.

## Token Reference

Aion issues a fresh one-hour invocation token before each managed-runtime request, including lifecycle methods
without request metadata. The audience is the destination runtime's public client-ID UUID. Anonymous session tokens
last 30 days and use a fixed audience instead.

### Protected Header

| Field | Session token | Invocation token |
| - | - | - |
| `alg` | `ES256` | `ES256` |
| `typ` | `aion-session+jwt` | `aion-invocation+jwt` |
| `kid` | Current public JWKS key ID | Current public JWKS key ID |

### Claims

| Claim | Session token | Invocation token |
| - | - | - |
| `iss` | Configured Aion issuer | Configured Aion issuer |
| `aud` | `urn:aion:a2a:anonymous-session` | Destination runtime client-ID UUID |
| `token_use` | `anonymous_session` | `a2a_invocation` |
| `contract_version` | Integer `1` | Integer `1` |
| `sub` | Encoded `AnonymousSession` identity | Encoded initiating caller identity |
| `assurance` | `session` | How Aion established the caller identity |
| `iat`, `nbf`, `exp` | UTC epoch seconds; 30-day lifetime | UTC epoch seconds; one-hour lifetime |

Invocation tokens also include three UUID claims, absent from session tokens:

* `owner_agent_identity_id`: the receiving agent identity.
* `edge_agent_environment_id`: the environment where the request entered Aion.
* `terminal_agent_environment_id`: the environment of the runtime receiving the request.

These identify the destination and routing scope; they do not grant conversation access. An established stream need
not close when its token expires, but each new request needs a valid token.

Subjects use `aion:v1:<PrincipalType>:<base64url-UTF8-principal-ID>` with canonical unpadded encoding. User and session
UUIDs remain distinct namespaces. `ExternalSender` represents a provider-asserted sender qualified by provider and
tenant, without requiring an Identity/user database record. It is not the service account receiving the message.

The invocation `assurance` is `account`, `runtime`, `provider`, `session`, `internal`, or `unattributed`.
It describes trusted ingress evidence, not permission to access a conversation. In particular, provider-verified sender
information is not an Aion account login; `unattributed` supplies no individual history-access scope.

### Decoded Invocation Example

The following header and payload illustrate an account caller. They are not a usable bearer token. The `kid` placeholder
matches the JWKS example; the issuer, client ID, and agent/environment IDs must match your deployment.

```json theme={null}
{
  "alg": "ES256",
  "typ": "aion-invocation+jwt",
  "kid": "<key-thumbprint>"
}
```

```json theme={null}
{
  "iss": "aion.io",
  "aud": "22222222-2222-4222-8222-222222222222",
  "sub": "aion:v1:AionUser:MTExMTExMTEtMTExMS00MTExLTgxMTEtMTExMTExMTExMTEx",
  "token_use": "a2a_invocation",
  "contract_version": 1,
  "assurance": "account",
  "owner_agent_identity_id": "33333333-3333-4333-8333-333333333333",
  "edge_agent_environment_id": "44444444-4444-4444-8444-444444444444",
  "terminal_agent_environment_id": "55555555-5555-4555-8555-555555555555",
  "iat": 1790856000,
  "nbf": 1790856000,
  "exp": 1790859600
}
```

Here, `sub` encodes user `11111111-1111-4111-8111-111111111111`. The token is valid for one hour from
October 1, 2026, at 12:00 UTC.

### Verification Checklist

1. Use the configured trusted API URL and expected issuer, never values discovered from an unverified token.
2. Match `kid` to the public key and verify the ES256 signature. Reject unknown keys and unsupported JOSE options.
3. Require the expected `typ`, exact audience, `token_use`, contract version, and valid subject/assurance combination.
4. Require integer `iat`, `nbf`, and `exp`, with `nbf == iat` and the exact lifetime for that token type.
   Allow 30 seconds of clock tolerance.
5. Reject duplicate fields and tokens larger than 8 KiB. Apply context and task authorization after verification.

A valid signature alone is insufficient: other Aion credentials use the same signing mechanism but have different
purposes and access rules.

## Anonymous Sessions

### Create a Session

Clients create a guest session without account authentication. Set `AION_API_URL` to your trusted control-plane
base URL, then send a request with no bearer:

```bash theme={null}
AION_API_URL="https://api.aion.to"
curl --fail-with-body --request POST "$AION_API_URL/auth/anonymous-sessions"
```

The response contains a new session ID, its bearer token, and the token expiration time:

```json theme={null}
{
  "sessionId": "11111111-1111-4111-8111-111111111111",
  "token": "<signed-session-JWT>",
  "expiresAt": "2026-10-31T12:00:00Z"
}
```

Send the returned token as `Authorization: Bearer <token>` on **every** subsequent guest request.
The bare `sessionId` is not a credential; there is no separate session-ID header.

### Renew a Session

Call the same endpoint with the current session bearer:

```http theme={null}
POST /auth/anonymous-sessions
Authorization: Bearer <current-session-JWT>
```

Renewal preserves the session ID and issues another 30-day token, with no absolute session lifetime limit.
Expired, malformed, wrong-purpose, or otherwise rejected renewal credentials return `401`, not a replacement session.
Clients must explicitly start a new session and warn that access to previous guest conversations will be lost.

The endpoint accepts any browser origin, uses no authentication cookies, and returns `Cache-Control: no-store`.
Browser clients use `credentials: "omit"`. The create/renew quota defaults to 20 attempts per minute per trusted
network peer; `429` responses provide `Retry-After`.

### Guest Access

On the control plane, guest bearers work only with public A2A routes and session renewal. This includes `GetContexts`,
`GetContext`, and `DeleteContext` for conversations the session can access. They do not grant access to private
distributions, GraphQL, MCP, Files, or administration. Registry discovery and the Aion Chat web catalog still require
account authentication.

Account authentication failure must not silently switch a client to guest mode. Account and guest histories remain
separate; signing in does not merge them. See
[Authentication And Guest Sessions](/tools/aion-chat#authentication-and-guest-sessions) for Aion Chat storage,
renewal, and recovery behavior.

## Conversation Ownership And Access

Each context belongs to the receiving agent identity within the ingress environment. Caller bindings record who has
been admitted. Account and guest clients cannot join an occupied context merely by supplying its ID. A provider can
admit multiple participants to a shared conversation; admitted participants see its complete stored history.

Ordinary user/session history requests require a caller binding. Reading history as the receiving agent requires
explicit owner-history authorization; a Version token does not automatically grant access to upstream distribution
history in another environment. Changing the ingress environment starts a separate history scope.

`DeleteContext` removes the caller's binding. Other recorded participants retain the conversation; removing the last
binding starts cancellation and deletion. See [Context](/a2a/extensions/aion/context/1.0.0) for the full lifecycle,
errors, retention, and File behavior.

<Note>
  Caller bindings are recorded best effort. A failed write can leave history unavailable until a later authorized
  message repairs access, or indefinitely if no repair succeeds. An unrecorded participant also cannot prevent deletion
  when the last recorded binding is removed. Provider room departures and kicks do not yet revoke recorded access.
</Note>

Only a task's initiating caller may change its push destination. Shared history access does not transfer that right.
Provider sender changes do not change billing payer/agent/executor attribution or response routing.

## Message Provenance

Preserve relevant incoming sender and extension metadata on returned messages, without copying credentials or
relabeling earlier history. Keep the requesting participant distinct from the agent authoring the response.
Echoed metadata is descriptive, not proof of authentication, and Aion does not reconstruct omitted response history.
