
# createJWSSession() / createJWESession()

> Open a session manager from Elysia's `cookie` and `request` yourself, for a `resolve`, `derive` or guard you write by hand.

```ts
import { Elysia } from "elysia";
import { createJWSSession, generateJWK } from "unjwt/adapters/elysia";

const key = await generateJWK("HS256");
const config = { key, maxAge: "1h" };

const app = new Elysia()
  .resolve(async ({ cookie, request }) => ({
    session: await createJWSSession({ cookie, request }, config),
  }))
  .get("/login", async ({ session }) => {
    await session.update({ user: "alice" });
    return { id: session.id }; // { id: "fee86981-…" }
  })
  .get("/me", ({ session }) => ({ id: session.id ?? null, data: session.data }));
// GET /me with the cookie: { id: "fee86981-…", data: { user: "alice" } }
```

## Signature

```ts
function createJWSSession<
  T extends Record<string, any> = SessionClaims,
  MaxAge extends ExpiresIn | undefined = ExpiresIn | undefined,
>(context: SessionContext, config: SessionConfigJWS<T, MaxAge>): Promise<SessionManager<T, MaxAge>>;

function createJWESession<
  T extends Record<string, any> = SessionClaims,
  MaxAge extends ExpiresIn | undefined = ExpiresIn | undefined,
>(context: SessionContext, config: SessionConfigJWE<T, MaxAge>): Promise<SessionManager<T, MaxAge>>;

interface SessionContext {
  cookie: ChunkableCookieJar; // Elysia's reactive `cookie` context property
  request: { headers: { get(name: string): string | null } };
}
```

## Options

`config` is the same object [`jwsSession()`](/adapters/elysia#options) and `jweSession()` take. `contextKey` has no effect here, because you choose where the manager goes. The returned manager is the one described under [the session object](/adapters#the-session-object).

## When to use it

- You want the session under a key, or with a typing, that the plugin does not give you.
- You open the session only on some routes, or only after another check, instead of on every request.
- You need the manager inside a `derive` or `beforeHandle` of an app that does not mount the plugin.
- You write a guard with its own rule, for example a role check, in place of `requireSession`.

The plugins are thin wrappers over these functions: a scoped `resolve` that calls `createJWSSession({ cookie, request }, config)` and a macro that answers `401` while `session.id` is unset.

## The context argument

Destructure `{ cookie, request }` in the hook signature, as above. Elysia decides which context fields to build by reading the hook's source, and naming `cookie` there keeps the jar in place.

The adapter reads cookies from the jar and writes back through each reactive cookie's `set()`. A `cookie` object that is not Elysia's jar fails on the first write:

```ts
const session = await createJWSSession({ cookie: {}, request }, { key });
await session.update({ a: 1 });
// JWTError ERR_SESSION_CONFIG_INVALID: [unjwt/elysia] Session cookie jar must expose a reactive cookie at "elysia-jws" with a set() method — pass Elysia's own `cookie` context property.
```

## Shared state within a request

The session state lives on the `request` object. Every call of the same family with the same `name` during one request returns a manager over the same state, whether it comes from a plugin, a handler or a hook. A `clear()` in a hook therefore empties `ctx.session` too, and an `update()` in a hook hands the handler the new session. Calling `createJWSSession()` again inside the `onRead` hook of the same session fires `onRead` again and recurses, so leave sliding expiration to the handler or a `beforeHandle`.

Hooks receive the context you passed as `context`:

```ts
hooks: {
  onUpdate: ({ session, context }) =>
    console.log("onUpdate", session.id.slice(0, 8), "has request:", "request" in context, "has cookie:", "cookie" in context),
}
// onUpdate fee86981 has request: true has cookie: true
```

## Errors

The same codes as the [plugins](/adapters/elysia#errors). Key and config errors throw from `createJWSSession()` itself. A jar without reactive cookies throws `ERR_SESSION_CONFIG_INVALID` from the first `update()` or `clear()`.
