# Core (https://session-kit.pages.dev/docs/reference/core)

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

Guide: [Getting started](https://session-kit.pages.dev/docs/getting-started).

## Functions

### 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

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

### fromAccessToken

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

### isSignedIn

Whether someone is signed in: `true` while `authenticated` or `refreshing`. It narrows `state`, so `state.user` is set when it's `true`.

### loginHref

Builds the sign-in page's URL, with `?redirectTo=` set to `returnTo`, so the user comes back after signing in. The guards use it. Use it in a guard of your own, such as in a route handler.

### 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

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

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

## Classes

### AuthError

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

## Types

### 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

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

### 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

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

### 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

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

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

### 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

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

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 whole seconds. Each save, such as after a refresh, starts it again. A session saved longer ago isn't restored, and the user is signed out without an error. So is a session saved by another version of session-kit. 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. Default: `false`                                                                                                                                                            |
| `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

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

### 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

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

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

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

### 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

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

### MirrorAuthOptions

Options for [`createMirrorAuth`](#createmirrorauth). The client talks to your server through `endpoint`, your session route, or through functions of your own, such as server functions, which call `serverAuth` from `@monarcode/session-kit/server`. Pass `endpoint`, or `revalidate` and `signOut`.

### MirrorAuthOptions

Options for createMirrorAuth. The client talks to your server
through `endpoint`, your session route, or through functions of your own,
such as server functions, which call `serverAuth` from
`@monarcode/session-kit/server`. Pass `endpoint`, or `revalidate` and
`signOut`.

| 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.                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `endpoint?`    | `string`            | The path of your session route on this site, such as `"/api/session"`, which answers with `sessionRoute` or `sessionHandler` from the server entry points. The client reads the session, signs out and gets the access token through it. Pass it, or `revalidate` and `signOut`. `revalidate`, `signOut` and `credentials` win when you pass them too. It's the full path, with your app's base path, such as React Router's `basename` or Next's `basePath`. It's called from the browser only: on the server, a call through it rejects with `INVALID_OPTIONS`. |
| `revalidate?`  | `union`             | Reads the session on your server again, with `serverAuth.getSession`, such as through a server function. Required without `endpoint`. The client calls it when the tab becomes visible again, unless the server answered in the last 10 seconds, when another tab signs in or out, and from `retry()` and `refresh()`. Pass one when the session is also read while the server renders, where `endpoint` can't be called, as in TanStack Start. Default: a `GET` to `endpoint`.                                                                                   |
| `signOut?`     | `union`             | Signs out on your server, with `serverAuth.signOut`. The client's `signOut()` calls it, then signs out this tab and the others. Required without `endpoint`. Default: a `POST` to `endpoint`.                                                                                                                                                                                                                                                                                                                                                                     |
| `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`. Default: through `endpoint`, which serves it when `createServerAuth` has `clientCredentials`. Without either, `credentials.get()` and `credentials.renew()` reject with `INVALID_OPTIONS`.                                                                                                                                                                                                                               |
| `debug?`       | `union`             | Logs what the client does, like `createAuth`'s `debug`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |

### MirrorCredentials

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

### RefreshFn

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

### 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.

### Register

Register your client's type here, once, so the hooks from `@monarcode/session-kit/react` and the Effect service carry your user. Without it, the user is typed `unknown`.

### RegisteredAuth

The client registered in [`Register`](#register), or a client with an `unknown` user when none is. It's `never` when what's registered isn't a client.

### RevokeFn

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

### 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 by path, ignoring case, percent-encoding, trailing slashes and any query. Default: `"/login"` |

### 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.

### SessionOf

The session type of a client: what its `getSession` resolves, without `null`. It takes any client: one from `createAuth` or `createMirrorAuth`, the server's from `createServerAuth`, or a request's session from it.

### 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

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

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

### 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.

### UserOf

The user type of a client, as [`SessionOf`](#sessionof) finds it: the `user` of its session.

### 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

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"` |