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:
BCP_SESSION_SECRET=replace-with-a-long-random-secret-at-least-32-bytesThe 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
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:
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:
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:
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:
browser cookie
↓
HS256 signature + expiry validation
↓
authenticated sessionThis 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
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
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:
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:
await appAuth.revokeSession(
sid
);Or revoke every stored session for a user:
await appAuth.revokeUserSessions(
userId
);Low-level forms are also exported:
import {
revokeSession,
revokeUserSessions,
} from "bcp/auth";Idle timeout
Server-side session state can enforce inactivity expiration:
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.
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.
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:
{
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/authis 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_SECREToutside 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.