# Core (/docs/reference/core)

```ts
import { … } from "@monarcode/session-kit";
```

Guide: [Getting started](/docs/getting-started).

## Functions [#functions]

### createAuth [#createauth]

Creates an auth client. It keeps the session your backend issued, saves it, refreshes its tokens, and tells your app when it changes.

### createMirrorAuth [#createmirrorauth]

Creates a browser client ([`MirrorAuth`](#mirrorauth)) for a session your server keeps in an encrypted cookie, with `createServerAuth` from `@monarcode/session-kit/server`.

### fromAccessToken [#fromaccesstoken]

Reads the user from the access token, rather than from what `signIn` is given. Pass the result as `createAuth`'s `user` option.

### memoryStorage [#memorystorage]

Keeps the session in memory only. It ends when the page unloads, and other tabs never see it. Use it in tests, or where tokens must never be written to disk. Each call has its own entries.

### safeReturnTo [#safereturnto]

Makes a "send me back here after sign-in" path safe to redirect to, such as a `?redirectTo=` search param. It returns the path, normalized, when it leads somewhere in your app, query and fragment included.

### webStorage [#webstorage]

Saves the session in the browser's `localStorage`, or in `sessionStorage` with `{ area: "session" }`. Tabs follow each other's changes, such as a sign-out, and take turns to refresh where the browser supports Web Locks.

## Classes [#classes]

### AuthError [#autherror]

The error Session kit throws, rejects with, or shows in `state.error`.

## Types [#types]

### AccessTokenUser [#accesstokenuser]

A user read from the access token, made by [`fromAccessToken`](#fromaccesstoken). Pass it as `createAuth`'s `user` option. `C` is the token's claims, and `U` is the user made from them.

### AuthClient [#authclient]

The auth client that `createAuth` returns. It holds the session, saves it, refreshes it, and tells your app when it changes.

### AuthDebug [#authdebug]

What `createAuth`'s `debug` option takes:

- `true`: log every event to the console.
- A function: receive every [`AuthDebugEvent`](#authdebugevent).
- [`AuthDebugOptions`](#authdebugoptions): choose where events go, and whether they include secrets.
- `false`, or leaving it out: no logging.

### AuthDebugEvent [#authdebugevent]

One thing auth did, sent to the `debug` option ([`AuthDebug`](#authdebug)).

### AuthDebugOptions [#authdebugoptions]

The object form of `createAuth`'s `debug` option ([`AuthDebug`](#authdebug)): where events go, and whether they include secrets.

### AuthDebugOptions

The object form of `createAuth`'s `debug` option (AuthDebug):
where events go, and whether they include secrets.

| Prop         | Type       | Description                                                                                                                                                                                     |
| ------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `log?`       | `function` | Receives every event. Default: one `console.info` line per event.                                                                                                                               |
| `sensitive?` | `union`    | Also puts tokens, saved values, user fields, whole deep-link paths and error details in events. Anyone who reads such logs can act as the user, so use it only in development. Default: `false` |

### AuthDebugType [#authdebugtype]

Which part of auth an [`AuthDebugEvent`](#authdebugevent) comes from, such as `refresh` or `storage`. These names don't change between releases, so filter on them.

### AuthErrorCode [#autherrorcode]

What went wrong: the `code` of every [`AuthError`](#autherror). Match on it rather than on the message, which may change in any release.

### AuthErrorOptions [#autherroroptions]

Options for creating an [`AuthError`](#autherror) yourself, such as in a test or a custom storage adapter: the standard `cause`, plus schema `issues`.

### AuthErrorOptions

Options for creating an AuthError yourself, such as in a test or a
custom storage adapter: the standard `cause`, plus schema `issues`.

| Prop      | Type      | Description                                                |
| --------- | --------- | ---------------------------------------------------------- |
| `cause?`  | `unknown` |                                                            |
| `issues?` | `array`   | The schema's issues, for a `USER_VALIDATION_FAILED` error. |

### AuthLocking [#authlocking]

Encrypts the saved tokens with a key your app holds, such as one behind Face ID. Pass it as the `locking` option of [`AuthOptions`](#authoptions).

### AuthOptions [#authoptions]

Options for `createAuth`. The client's user types ([`User`](#user), [`UserInput`](#userinput)) are inferred from the `user` option.

### AuthOptions

Options for `createAuth`. The client's user types (User,
UserInput) are inferred from the `user` option.

| Prop       | Type                                                                  | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| ---------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`     | `string`                                                              | Names this auth, so several can share one storage. It's used in the storage key (`<name>:auth:session`) and in the lock that keeps tabs from refreshing at once. Letters, digits, `_` or `-`, up to 64 characters.                                                                                                                                                                                                                                                                                                                                   |
| `user`     | `Src`                                                                 | Where the user comes from: a schema, or `fromAccessToken(…)`. A Standard Schema schema, such as Zod's, checks the `user` passed to `signIn`. Its output must be a plain JSON object that it accepts again unchanged, as a restored session is checked again. `fromAccessToken` reads the user from the access token instead.                                                                                                                                                                                                                         |
| `storage`  | `AuthStorage`                                                         | Where the session is saved, such as `webStorage()` (AuthStorage).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `refresh?` | `RefreshFn<NoInfer<UserInput<Src>>>`                                  | Exchanges a refresh token for new tokens (RefreshFn). Without it, the user is signed out when the access token expires or your API rejects it.                                                                                                                                                                                                                                                                                                                                                                                                       |
| `revoke?`  | `RevokeFn`                                                            | Asks your backend to revoke the tokens after `signOut()` (RevokeFn).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `maxAge?`  | `number`                                                              | How long a saved session lasts, in seconds. Each save, such as after a refresh, starts it again. Default: 30 days.                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `debug?`   | `union`                                                               | Logs what auth does, for debugging: restores, refreshes, timers, storage and state changes. `true` logs to the console, and a function receives each event instead (AuthDebug). Tokens, user fields, saved values and error details are left out unless you pass `{ sensitive: true }`. Pass a development flag, such as Expo's `__DEV__`, to keep it out of production.                                                                                                                                                                             |
| `locking?` | `Src extends AccessTokenUser<any, any> ? never : true \| AuthLocking` | Restores a saved session as `locked`. Its user shows, but its tokens wait for `unlock()`. `true` saves the tokens as they are, and `{ seal, open }` encrypts them with your app's key (AuthLocking). It's meant for native apps. In a browser, tabs stop following each other, so a sign-in, sign-out or lock in one tab doesn't reach the others. With rotating refresh tokens, two tabs that refresh the same session can sign one of them out. It needs a user schema, as a user read from the access token can't show while the token is locked. |

### AuthState [#authstate]

The current auth state, from `state.get()` or `useAuth()`. It holds no tokens.

### AuthStatus [#authstatus]

Where the session stands: `state.status` ([`AuthState`](#authstate)).

- `initializing`: the saved session hasn't been read yet.
- `authenticated`: signed in, with an access token that hasn't expired or been rejected.
- `refreshing`: signed in, and replacing an access token that expired or was rejected.
- `locked`: signed in, but the tokens wait for `unlock()` (with `locking`).
- `unauthenticated`: signed out.
- `unavailable`: the access token expired or was rejected and couldn't be refreshed, or the saved session couldn't be read. `state.error` usually says why. On a client, `retry()` tries again.

### AuthStorage [#authstorage]

Where auth saves the session: `createAuth`'s `storage` option. Use [`webStorage`](#webstorage) in browsers, `secureStorage()` from `@monarcode/session-kit/expo` in Expo apps, and [`memoryStorage`](#memorystorage) in tests. Implement it yourself for another store.

### AuthStorage

Where auth saves the session: `createAuth`'s `storage` option. Use
webStorage in browsers, `secureStorage()` from
`@monarcode/session-kit/expo` in Expo apps, and memoryStorage in
tests. Implement it yourself for another store.

Values are strings in a format auth owns. Methods may return promises. Auth
runs them one at a time, in order, so a store that answers out of order is
still safe.

| Prop         | Type       | Description                                                                                                                                                                                                                                                                                                                              |
| ------------ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `get`        | `function` | Returns the value saved under `key`, or `null` when there's none. If it answers synchronously, a saved session shows before the first render.                                                                                                                                                                                            |
| `set`        | `function` | Saves `value` under `key`. `meta.expiresAt` is when the saved session stops being valid, in Unix milliseconds, for a store that can expire entries itself.                                                                                                                                                                               |
| `remove`     | `function` | Removes the value saved under `key`.                                                                                                                                                                                                                                                                                                     |
| `subscribe?` | `function` | Calls `onChange` when another tab changes `key`, and returns a function that stops listening. Leave it out when nothing else shares the store.                                                                                                                                                                                           |
| `lock?`      | `function` | Runs `work` while holding the lock `name` in every tab that shares the store, so only one tab refreshes at a time. Aborting `signal` stops waiting for the lock. Leave it out when nothing else shares the store.                                                                                                                        |
| `debug?`     | `function` | Lets your adapter add its own events to the debug log, such as why it discarded a saved value. Each `createAuth` with `debug` on calls it with the key it saves under and a `report` function for that key. One adapter can serve several auths, so keep a `report` per key. `sensitive` says whether saved values may appear in `data`. |

### ClientCredentials [#clientcredentials]

The access token as your server gives it to the browser, from `serverAuth.clientCredentials` in `@monarcode/session-kit/server`. `expiresIn` counts from when the server answered, so the browser's clock doesn't matter.

### Credentials [#credentials]

The current access token, from `credentials.get()`, to send with your API requests. `createAuthFetch` from `@monarcode/session-kit/http` does this for you.

### FromAccessTokenOptions [#fromaccesstokenoptions]

Options for [`fromAccessToken`](#fromaccesstoken).

### FromAccessTokenOptions

Options for fromAccessToken.

| Prop      | Type       | Description                                                                                                                                                                                                                                                                                                                                   |
| --------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `decode?` | `function` | Reads the claims from the access token. It may return a promise, but then a saved session can't show before the first render. The default doesn't verify the signature. That's fine in a browser, which trusts its own backend's responses. On a server, pass a function that verifies the token. Default: the JWT's payload, **unverified**. |

### MirrorAuth [#mirrorauth]

The browser client that [`createMirrorAuth`](#createmirrorauth) returns. It mirrors a session your server keeps in a cookie.

### MirrorAuthOptions [#mirrorauthoptions]

Options for [`createMirrorAuth`](#createmirrorauth). Each function is your own server function, action, or `fetch` to a route handler, which calls `serverAuth` from `@monarcode/session-kit/server`.

### MirrorAuthOptions

Options for createMirrorAuth. Each function is your own server
function, action, or `fetch` to a route handler, which calls `serverAuth`
from `@monarcode/session-kit/server`.

| Prop           | Type                | Description                                                                                                                                                                                                                                               |
| -------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`         | `string`            | Names this auth. Tabs tell each other about changes on the `BroadcastChannel` `<name>:auth`. Letters, digits, `_` or `-`, up to 64 characters.                                                                                                            |
| `session`      | `union`             | The session the page was rendered with, from `serverAuth.getSession`, or `null`. The client starts from it, so there's no loading state.                                                                                                                  |
| `revalidate`   | `function`          | Reads the session on the server again, with `serverAuth.getSession`.                                                                                                                                                                                      |
| `signOut`      | `function`          | Signs out on the server, with `serverAuth.signOut`.                                                                                                                                                                                                       |
| `signIn?`      | `function`          | Signs in on the server with `input`, and resolves the new session. Use `serverAuth.signIn`, or your own sign-in that ends with it. Without this option, the client has no `signIn`. Call your function, then pass its result to `adopt`.                  |
| `credentials?` | `MirrorCredentials` | Gets the access token from your server (MirrorCredentials), so page scripts can call your API with `createAuthFetch` or `sessionBearer`. Leave it out if they never do. `credentials.get()` and `credentials.renew()` then reject with `INVALID_OPTIONS`. |
| `debug?`       | `union`             | Logs what the client does, like `createAuth`'s `debug`.                                                                                                                                                                                                   |

### MirrorCredentials [#mirrorcredentials]

How a [`MirrorAuth`](#mirrorauth) gets the access token from your server. It's the `credentials` option of [`MirrorAuthOptions`](#mirrorauthoptions).

### RefreshFn [#refreshfn]

Exchanges a refresh token for new tokens. It's the `refresh` option of [`AuthOptions`](#authoptions).

### RefreshResult [#refreshresult]

What your refresh callback ([`RefreshFn`](#refreshfn)) returns:

- [`Tokens`](#tokens): the new tokens. They must last at least five seconds. Leave out `refreshToken` or `user` to keep the current one.
- `null`: your backend rejected the refresh token. The user is signed out.

### RevokeFn [#revokefn]

Asks your backend to revoke the tokens of a session that just signed out. It's the `revoke` option of [`AuthOptions`](#authoptions).

### SafeReturnToOptions [#safereturntooptions]

Options for [`safeReturnTo`](#safereturnto).

### SafeReturnToOptions

Options for safeReturnTo.

| Prop         | Type    | Description                                                                                                                                                                                                      |
| ------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `loginPath?` | `union` | Your sign-in page's path, or several. A path to it is replaced with `"/"`, so signing in never sends the user back to sign in. Matched ignoring case, percent-encoding and trailing slashes. Default: `"/login"` |

### Session [#session]

Who is signed in: the session ID and the user, from `getSession()`. It holds no tokens, so it's safe to keep in route context or pass around.

### SignInInput [#signininput]

What `signIn` takes: the [`Tokens`](#tokens), plus the `user` when a schema validates it. With `fromAccessToken` (`I` is `never`), it takes tokens only.

### Tokens [#tokens]

The tokens your backend issues. Pass them to `signIn`, and return them from your refresh callback ([`RefreshFn`](#refreshfn)).

### Tokens

The tokens your backend issues. Pass them to `signIn`, and return them from
your refresh callback (RefreshFn).

When the access token expires comes from the first of these that is set:
1. `expiresIn` or `expiresAt`. Pass one, not both.
2. A JWT access token's `exp - iat`, counted from when auth receives it.
3. A JWT access token's `exp` alone, compared with the device's clock.

With none of them, the token never expires on its own. It's replaced only
after your API rejects it.

Prefer `expiresIn`, or a JWT with `iat`. Device clocks can be minutes off,
and a clock that runs fast makes a fixed deadline look already passed, so
`signIn` would reject the tokens.

| Prop            | Type     | Description                                                                                                                                                                                               |
| --------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `accessToken`   | `string` | The token your API accepts. `createAuthFetch` sends it as `Authorization: Bearer <accessToken>`.                                                                                                          |
| `refreshToken?` | `string` | The token your refresh callback exchanges for new tokens. Without one, the user is signed out when the access token expires or is rejected. A refresh that returns none keeps the current one.            |
| `expiresIn?`    | `number` | How long the access token lasts, in **seconds**, like OAuth's `expires_in` (`900` is 15 minutes). It's counted from when auth receives the token, so a wrong device clock doesn't matter.                 |
| `expiresAt?`    | `number` | When the access token expires, as Unix time in **milliseconds**, such as `Date.parse("2026-10-02T12:15:00Z")`. It's compared with the device's clock, so use it only when your backend gives no lifetime. |

### User [#user]

The signed-in user's type, inferred from the `user` option: what `state.user` and `session.user` hold.

### UserInput [#userinput]

The user that `signIn` and `updateUser` accept, inferred from the `user` option. It differs from [`User`](#user) when the schema has defaults or transforms.

### UserSource [#usersource]

What `createAuth`'s `user` option takes: a schema, such as Zod's, that checks the `user` passed to `signIn`, or [`fromAccessToken`](#fromaccesstoken), which reads the user from the access token.

### WebStorageOptions [#webstorageoptions]

Options for [`webStorage`](#webstorage).

### WebStorageOptions

Options for webStorage.

| Prop    | Type    | Description                                                                                                                                                                                                                                                                                                                                               |
| ------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `area?` | `union` | Which browser storage to use. `"local"` keeps the session across browser restarts and shares it with every tab. `"session"` gives each tab its own session, which ends with the tab. Avoid `"session"` with rotating refresh tokens. A duplicated tab starts with the same refresh token, and the first to use it signs the other out. Default: `"local"` |