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

# Identity and the vault

> How a token is bound to an identity, where values are kept, and how to erase them.

## The identity context

A token belongs to the context it was created under, and only that context can restore it.

<CodeGroup>
  ```ts TypeScript theme={null}
  const context = { subject: user.id };
  const scoped = { subject: user.id, scope: conversation.id };
  ```

  ```python Python theme={null}
  context = CloakContext(subject=user.id)
  scoped = CloakContext(subject=user.id, scope=conversation.id)
  ```
</CodeGroup>

`subject` is your own identifier for the end user, or for the session. It is never a value the end user supplied about themselves. `scope` narrows the binding further, for example to one conversation or one purpose.

A context is required whenever anything is tokenized. The check happens up front, before any network call, so a missing context fails on your first request and not on the first real piece of personal data.

## What "refused" means

A response that carries another context's token is refused:

* By default the restore **throws** `RestoreDeniedError`. The message says how many tokens were refused, never which, and never the values.
* With `onDenied: "leave"`, the tokens are left in place and counted in `denied`.

A token turning up in a response for someone it does not belong to is either a model repeating something it should not have seen, or an attempt to read another user's data through yours. Either way, returning the value would be the leak. A refused restore is reported to your console as a count.

## The vault

Tokenized values live in a vault. The default is process memory.

| Setting | Default | Meaning |
| - | - | - |
| `vaultTtlMs` | `3600000` | How long a value is kept: one hour. |
| `maxVaultEntries` | `10000` | How many values the in-memory store holds before it drops the oldest. |
| `key` | random per process | The secret that keys tokens and hashes. |
| `vault` | in-memory | Your own store. |

<CodeGroup>
  ```ts TypeScript theme={null}
  new FrostWolfClient({
    apiKey,
    guard: {
      cloak: {
        vault: myVault,
        key: process.env.CLOAK_KEY,
        vaultTtlMs: 3_600_000,
      },
    },
  });
  ```

  ```python Python theme={null}
  FrostWolfClient(
      api_key=key,
      guard=GuardOptions(
          cloak=CloakConfig(
              vault=my_vault,
              key=os.environ["CLOAK_KEY"],
              vault_ttl_ms=3_600_000,
          )
      ),
  )
  ```
</CodeGroup>

The default store is bounded and expiring, and a restart loses all of it. That is the right default for a store the SDK does not encrypt: the only copy of the original is one your own process already held.

### Your own vault

A vault implements `get(token)` and `set(token, entry)`, and optionally `deleteContext(contextId)` (`delete_context` in Python), which `forget` needs. Each entry holds the value and the opaque id of the context it belongs to.

<Warning>
  The SDK never encrypts what it stores. A vault that persists must encrypt at rest itself, and must be protected as carefully as the data it holds.
</Warning>

### A stable key

Pass a stable `key` if you use a vault that outlives the process. A token is a keyed digest, so a stable key keeps the same value on the same token across restarts. Restoring does not depend on the key, because restore looks the token up in the vault.

The context id stored in a vault is a hash of the context, not your user id.

## Erasure

`forget` removes everything held for one identity. Afterwards nothing protected under that context can be restored, including responses still in flight.

<CodeGroup>
  ```ts TypeScript theme={null}
  const removed = await fw.guard.cloak.forget({ subject: user.id });
  ```

  ```python Python theme={null}
  removed = fw.guard.cloak.forget(CloakContext(subject=user.id))
  ```
</CodeGroup>

Use it for a right-to-erasure request. It throws if the configured vault has no `deleteContext`.

## Collisions

A token is a keyed digest cut to 12 hex characters, which is 48 bits. Before settling on a token, Cloak checks the vault. If the slot is held by a different value it moves to a longer token rather than overwrite it, because restoring the wrong person's value would be worse than any failure to restore.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.