Docs/Authentication & Authorization/Authentication

Authentication & Authorization

Authentication

Authentication — Authentication & Authorization documentation for BCP Framework.

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

Authentication

BCP Framework 0.2.5 — Authentication Platform v2 extends the server-only bcp/auth entrypoint with optional server-side session state, revocation, idle timeout, logout-all, and guest route guards while preserving the existing signed JWT-cookie mode.

Environment

Set a session secret with at least 32 bytes:

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

The default cookie is bcp_session. It is HttpOnly, uses SameSite=Lax, has a 12-hour lifetime, and is Secure automatically when NODE_ENV=production.

Basic usage

TypeScript
import {
    auth,
    login,
    logout,
} from "bcp/auth";

export async function POST() {
    await login({
        id: 42,
        email: "[email protected]",
        role: "admin",
    });

    return Response.json({
        ok: true,
    });
}

Read the current authenticated session:

TypeScript
import {
    auth,
} from "bcp/auth";

const session =
    await auth<{
        id: number;
        email: string;
        role: string;
    }>();

if (!session) {
    // Not authenticated.
}

getSession() remains an alias for auth().

Typed auth factory

For application-wide types and cookie settings, create a typed auth instance:

TypeScript
import {
    createAuth,
} from "bcp/auth";

interface AppUser {
    id: number;
    email: string;
    role: "admin" | "user";
}

interface AppSessionData {
    tenantId: string;
}

export const appAuth =
    createAuth<
        AppUser,
        AppSessionData
    >({
        cookieName:
            "app_session",
        expiresIn:
            60 * 60 * 8,
        issuer:
            "my-app",
        audience:
            "web",
    });

Login with typed session data:

TypeScript
await appAuth.login(
    {
        id: 42,
        email: "[email protected]",
        role: "admin",
    },
    {
        data: {
            tenantId:
                "tenant-1",
        },
    }
);

Stateless mode remains the default

Without a server-side store, authentication remains a signed JWT cookie:

text
browser cookie
   ↓
HS256 signature + expiry validation
   ↓
authenticated session

This is backward-compatible with earlier BCP versions.

A stateless JWT cannot normally be invalidated on another device before expiry. Applications that need revocation can enable the 0.2.5 session-store contract.

Revocable sessions

TypeScript
import {
    createAuth,
    createMemoryAuthSessionStore,
} from "bcp/auth";

const store =
    createMemoryAuthSessionStore();

export const appAuth =
    createAuth<AppUser>({
        store,
    });

With a store configured, authentication requires both a valid signed cookie and an active server-side sid record.

The built-in memory store is intended for development and tests. Multi-instance production applications should implement AuthSessionStore using a shared database or Redis-like service.

See Auth Session Stores.

Logout

TypeScript
await appAuth.logout();

In stateless mode this expires the browser cookie.

When a store is configured, BCP also revokes the current sid before expiring the cookie.

Logout from all sessions

With a session store:

TypeScript
const revokedCount =
    await appAuth.logoutAll();

This revokes every stored session for the current user and expires the current browser cookie.

logoutAll() intentionally requires a server-side store because stateless JWTs held by other devices cannot be centrally invalidated.

Explicit revocation

A factory configured with a store can revoke a known session:

TypeScript
await appAuth.revokeSession(
    sid
);

Or revoke every stored session for a user:

TypeScript
await appAuth.revokeUserSessions(
    userId
);

Low-level forms are also exported:

TypeScript
import {
    revokeSession,
    revokeUserSessions,
} from "bcp/auth";

Idle timeout

Server-side session state can enforce inactivity expiration:

TypeScript
const appAuth =
    createAuth<AppUser>({
        store,
        idleTimeout:
            60 * 30,
    });

idleTimeout is measured in seconds. Each successful auth() check updates lastSeenAt.

If the session has been inactive for at least the configured duration, BCP revokes it and returns null.

BCP rejects idleTimeout when no store is configured so an application cannot accidentally believe it is enforcing server-side inactivity policy when it is not.

Session rotation

Each login receives a unique sid. rotateSession() keeps the current user/session data but issues a new session identifier, JWT, expiry window, and cookie.

TypeScript
const rotated =
    await appAuth.rotateSession();

When a session store is configured, the previous sid is revoked as part of rotation.

Good rotation points include successful re-authentication, password changes, permission elevation, or other security-sensitive account changes.

Guest-only pages

Authentication Platform v2 adds requireGuest() / createGuestGuard() for routes such as login and registration pages.

TypeScript
import {
    createGuestGuard,
} from "bcp/auth";

export const guard =
    createGuestGuard({
        redirectTo:
            "/dashboard",
    });

Anonymous users continue to the page. Authenticated users are redirected with 303 by default.

See Auth Route Guards.

Session shape

An authenticated session contains the user, optional application data, and signed JWT claims:

TypeScript
{
    sid: string;
    user: AppUser;
    data?: AppSessionData;
    iat: number;
    exp: number;
    iss?: string;
    aud?: string | string[];
}

Server-side session-store metadata is not embedded as application payload data.

Security notes

  • bcp/auth is server-only and must not be imported into browser/client graphs.
  • JWT cookie payloads are signed, not encrypted. Do not store passwords, password hashes, API secrets, access keys, or private credentials in the auth payload.
  • Keep BCP_SESSION_SECRET outside source control and use a strong random value of at least 32 bytes.
  • Use HTTPS in production so Secure cookies travel only over encrypted connections.
  • The memory session store is process-local; use a shared durable store when revocation must work across multiple processes/containers.
  • Authentication establishes identity/session state. Fine-grained authorization remains a route guard, action, API, or application policy concern.

create-bcp-app

When JWT Cookie authentication is selected, generated applications use createAuth() internally and expose application helpers from lib/auth.ts.

The generated authenticateCredentials() intentionally returns null until the application implements its own user lookup and password verification strategy.

Generated projects stay stateless by default. Applications can opt into a session store explicitly without changing the public auth entrypoint.