Exchange handoff token for a session
Consumes a one-time `handoff_token` minted by `POST /auth_attempts/{id}/handoff` and returns the resulting session and a `session_token`. The server resolves the originating `auth_attempt` from the token and then: | Originating auth_attempt | Outcome | |---|---| | No `session_id` | A new authenticated session is **created**. | | `session_id` points to an anonymous shell | Existing session is **upgraded** — user and factors written in, TTL reset to full session TTL. | | `session_id` points to an active session (step-up) | Existing session is **upgraded** — new factors merged, `assurance_levels[]` expanded. | The response shape is identical in all three cases. The `session_token` supersedes any previously issued `session_token` for the same session. Clients must replace their stored token at this point. Requires a project service key (OAuth2 client credentials).
Consumes a one-time handoff_token minted by POST /auth_attempts/{id}/handoff
and returns the resulting session and a session_token.
The server resolves the originating auth_attempt from the token and then:
| Originating auth_attempt | Outcome |
|---|---|
No session_id | A new authenticated session is created. |
session_id points to an anonymous shell | Existing session is upgraded — user and factors written in, TTL reset to full session TTL. |
session_id points to an active session (step-up) | Existing session is upgraded — new factors merged, assurance_levels[] expanded. |
The response shape is identical in all three cases.
The session_token supersedes any previously issued session_token for the same session.
Clients must replace their stored token at this point.
Requires a project service key (OAuth2 client credentials).
Authorization
oauth2 sessions.writeIn: header
Scope: sessions.write
Query Parameters
The unique identifier of the project
Header Parameters
Optional retry key for safe retries of the handoff exchange (Category B idempotency). Retries carrying the same key within the exchange window return the cached session payload without consuming the one-time handoff token again.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Request to exchange a handoff token for a session and session_token.
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/sessions/exchange?project_id=river-8421" \ -H "Content-Type: application/json" \ -d '{ "handoff_token": "handoff_abc123def456xyz" }'{ "session": { "session_id": "abc123def456", "project_id": "river-8421", "state": "active", "user_id": "user_id_12345", "factors": [ { "method": "password", "verified_at": "2026-04-28T15:32:00Z", "payload": { "user_id": "user_id_12345" } } ], "assurance_levels": [ "urn:nist:aal:1", "urn:nist:aal:2" ], "metadata": {}, "user_agent": { "fingerprint": "fp_abc123", "ip": "203.0.113.42" }, "created_at": "2026-04-29T10:00:00Z", "expires_at": "2026-04-30T10:00:00Z" }, "session_token": "stok_abc123def456"}{ "code": "string", "message": "string", "details": {}}{ "code": "string", "message": "string", "details": {}}{ "code": "string", "message": "string", "details": {}}{ "code": "string", "message": "string", "details": {}}Create an anonymous session shell POST
Creates an anonymous session shell with no user and no factors (`state: building`). This is optional — an `auth_attempt` will create a session implicitly if none is provided. Use this explicitly when you want to: - Pre-allocate a `session_id` before the user is known, so device/telemetry signals can be correlated with the eventual authenticated session from the start. - Track anonymous state (bot detection, device fingerprint) that survives until authentication. The returned `session_token` authorises GET and DELETE on this session. It is superseded when a handoff exchange completes — clients must replace it at that point. Anonymous sessions expire aggressively (10-minute TTL). The TTL resets to the configured full session TTL when the first authentication factor is written via a completing `auth_attempt`.
Get my session state GET
Returns the current state of the current session including its factors and all currently satisfied assurance levels. `assurance_levels[]` may shrink over time as factor freshness windows expire, without the session itself expiring. Use step-up authentication (a new `auth_attempt` against the same `session_id`) to restore a dropped assurance level.