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

# Hosted approval

> Create a short-lived approval session and preserve the user identity boundary.

Hosted approval binds your authenticated end user to one exact Attesso mandate through a passkey ceremony.

## Before you create a session

Your backend must already know the end user. It creates a short-lived signed identity assertion whose subject exactly matches the mandate's `subject_reference`.

The assertion must satisfy the issuer, audience, expiry, and unique-ID requirements configured for your organization. Keep personal data out of the subject. Use a stable opaque identifier.

## Create the session

```http theme={null}
POST /v1/mandates/{mandate_id}/approval-sessions
Authorization: Bearer att_test_...
Idempotency-Key: aps_...
Content-Type: application/json
```

```json theme={null}
{
  "identity_assertion": "eyJ...",
  "return_url": "https://example.com/attesso/return",
  "return_state": "csrf_01HZX8F4N2Q7W9"
}
```

* `return_url` must be HTTPS and its origin must be pre-registered.
* `return_state` is opaque CSRF state. Generate at least 16 characters of unpredictable state and validate the returned value.
* A new session invalidates any previous open session for the same mandate.

## Redirect safely

The response includes a five-minute, single-use `approval_url` only while the session is `OPEN`.

<Warning>
  Treat `approval_url` as a bearer secret. Redirect from your backend without logging it, adding it to analytics, persisting it in browser storage, or sending it over email.
</Warning>

Attesso's isolated approval origin resolves the session, displays the exact mandate, and performs the WebAuthn ceremony. Biometric data and private keys remain on the end user's device.

## Handle the return

<Steps>
  <Step title="Validate state">
    Compare the returned state with the value bound to the signed-in browser session. Reject a mismatch.
  </Step>

  <Step title="Read the mandate from your backend">
    Retrieve `GET /v1/mandates/{mandate_id}` with your server-side API key. Do not infer approval from the redirect alone.
  </Step>

  <Step title="Continue only from an eligible state">
    `ACTIVE` is available now. `SCHEDULED` was approved but starts later. Terminal and pending states do not permit authorization.
  </Step>
</Steps>

## Expired or interrupted sessions

Approval sessions are intentionally disposable. If a user returns later or the session expires, reauthenticate the user in your application and create a fresh session. Do not reuse or recover the old approval URL.
