Create an anonymous session shell
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`.
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_idbefore 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.
Authorization
oauth2 sessions.writeIn: header
Scope: sessions.write
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Request to create an anonymous session shell.
Response Body
application/json
application/json
application/json
curl -X POST "https://example.com/sessions" \ -H "Content-Type: application/json" \ -d '{ "project_id": "river-8421" }'{ "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": {}}Sessions
OpenAPI operations for session creation, lookup, exchange, and teardown.
Exchange handoff token for a session POST
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).