Docs/Authentication & Authorization/JWT Sessions

Authentication & Authorization

JWT Sessions

JWT Sessions — Authentication & Authorization documentation for BCP Framework.

Last updated: 2026-08-29T17:13:55

JWT Cookie Sessions

BCP Framework provides server-only JWT cookie session helpers through bcp/server.

The current session implementation uses HS256 with Node.js crypto, requires a secret of at least 32 bytes, stores the token in an HttpOnly cookie by default and validates expiry before returning a session.

Environment

Set a strong session secret in the server environment:

env
BCP_SESSION_SECRET=replace-this-with-a-long-random-secret-at-least-32-bytes

Do not expose this value to browser code or prefix it as a public environment variable.

Create a session

createSession() signs a JWT and stores it in a cookie. The default cookie name is bcp_session and the default lifetime is 12 hours.

TypeScript
import {
    createSession,
    json,
} from "bcp/server";

export async function POST() {
    await createSession(
        {
            userId: 42,
            email: "[email protected]",
            role: "admin",
        },
        {
            issuer: "my-app",
            audience: "my-app-users",
        }
    );

    return json({
        success: true,
    });
}

By default BCP sets:

  • HttpOnly
  • SameSite=Lax
  • Path=/
  • Secure when NODE_ENV=production
  • Max-Age equal to the token lifetime

Cookie and token behavior can be customized:

TypeScript
await createSession(
    {
        userId: 42,
    },
    {
        cookieName: "access_token",
        expiresIn: 60 * 60,
        issuer: "my-app",
        audience: [
            "web",
            "api",
        ],
        sameSite: "strict",
        secure: true,
        path: "/",
    }
);

Read a session

getSession() reads the cookie and verifies the JWT signature, expiration, issuer and audience when those options are provided.

TypeScript
import {
    getSession,
    json,
} from "bcp/server";

export async function GET() {
    const session =
        await getSession<{
            userId: number;
            email: string;
            role: string;
        }>({
            issuer: "my-app",
            audience: "my-app-users",
        });

    if (!session) {
        return json(
            {
                error: "Unauthorized",
            },
            {
                status: 401,
            }
        );
    }

    return json({
        userId:
            session.userId,
        email:
            session.email,
        role:
            session.role,
    });
}

Invalid, expired or tampered session tokens return null instead of throwing.

Destroy a session

destroySession() expires the session cookie:

TypeScript
import {
    destroySession,
    json,
} from "bcp/server";

export async function POST() {
    await destroySession();

    return json({
        success: true,
    });
}

When a custom cookie name, path or domain is used while creating the session, use the same values when destroying it.

Low-level token APIs

BCP also exposes token-only helpers when an application needs to manage storage itself:

TypeScript
import {
    createSessionToken,
    verifySessionToken,
} from "bcp/server";

const token =
    await createSessionToken(
        {
            userId: 42,
        },
        {
            expiresIn: 3600,
            issuer: "my-app",
        }
    );

const claims =
    await verifySessionToken<{
        userId: number;
    }>(
        token,
        {
            issuer: "my-app",
        }
    );

createSessionToken() and verifySessionToken() use BCP_SESSION_SECRET unless an explicit secret option is supplied.

Security model

BCP session tokens use HS256 and reject secrets shorter than 32 bytes. Verification validates the signature with a constant-time comparison and rejects malformed, expired or unsupported JWTs.

JWT payloads are signed, not encrypted. Do not place passwords, API secrets or other confidential values in the session payload.

Session revocation is not automatic for stateless JWTs. Applications that require immediate revocation should store a session identifier in the token and validate it against a server-side session table or another revocation store.

API route boundary

These helpers are exported from bcp/server and remain server-only. In the current 0.1.x page/client pipeline, call them from API routes rather than modules reachable from the browser bundle.