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

# Authentication

> Create a wallet-scoped session cookie. No shared secret.

## The model

Calm authenticates users **by wallet**. Your app already proves the
user owns a wallet through whatever sign-in stack you've wired up.
Calm treat that as a proof for a short-lived `calm_session` cookie
bound to the wallet, plus a 30-day `calm_refresh` cookie that lets the
SDK silently re-create the session without re-running the heavy
verification.

A **publishable key** (`calm_public_(live|sandbox)_…`) identifies your
Calm tenant on every session-create call. Issue them from your Calm dashboard;
live keys are tied to an HTTPS origin allowlist, sandbox keys are
unrestricted when the allowlist is empty.

## How it works

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant U as User
    participant W as Wallet stack
    participant App as Your app
    participant C as Calm API
    U->>W: Sign in (your existing wallet auth)
    W-->>App: Wallet proof
    App->>C: POST /v1/session/0x.../{privy|dynamic|siwe}<br>(proof + publishable key)
    Note over C: Verify the proof<br>Resolve tenant from publishable key
    C-->>App: Set-Cookie calm_session + calm_refresh
    Note over App,C: Subsequent API calls auto-attach calm_session
    App->>C: GET /v1/wallets/0x... (calm_session)
    C-->>App: 200 OK
    Note over App,C: Before session expires (every 50 min)
    App->>C: POST /v1/session/0x.../{privy|dynamic|siwe}<br>(calm_refresh cookie)
    Note over C: Verify refresh cookie only<br>Skip the wallet round-trip
    C-->>App: Set-Cookie calm_session + calm_refresh (rotated)
```

The shape of "wallet proof" depends on the auth modality. Calm ships
three out of the box, and you can plug in your own:

* [`<PrivyCalmProvider>`](/sdk/react/privy) — sends the user's Privy
  identity token. Best when you're already using Privy for sign-in.
* [`<DynamicCalmProvider>`](/sdk/react/dynamic) — sends the JWT Dynamic
  mints on sign-in. Best when you're already using Dynamic for sign-in.
* [`<WagmiCalmProvider>`](/sdk/react/wagmi) — drops into any
  wagmi-based app; runs an
  [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) signature
  handshake on cold start, silent on refresh.

You can offer multiple modalities under the same publishable key —
the customer record is shared across them.

## Cookie attributes

Both cookies share the cross-site embed model (your app → Calm API).

| Attribute       | `calm_session` | `calm_refresh` | Why                                                       |
| --------------- | -------------- | -------------- | --------------------------------------------------------- |
| `HttpOnly`      | ✓              | ✓              | Your JavaScript can't read it.                            |
| `Secure`        | ✓              | ✓              | Required by browsers when `SameSite=None`.                |
| `SameSite=None` | ✓              | ✓              | Required to attach on cross-site fetches.                 |
| `Partitioned`   | ✓              | ✓              | CHIPS — not categorized as a third-party tracking cookie. |
| `Path`          | `/`            | `/v1/session`  | Refresh only attaches to session-create routes.           |
| `Max-Age`       | 3600           | 2592000        | One hour / 30 days.                                       |
