Capabilities/The auth flow

The auth flow

Integration, server-side verification, and protecting routes.

Integration

Authentication is handled in the server/auth/ directory. BionicJS templates support both managed providers (Clerk) and self-hosted solutions (Better Auth).

Each provider is a plugin package composed under the auth key in bionicjs.config.ts. Choose one:

PackageProviderMount
@bionicjs/better-authBetter Auth (self-hosted)/api/auth/[...auth]
@bionicjs/clerkClerk (managed)Client wrappers + server verify
@bionicjs/firebaseFirebaseserver/auth/firebase.ts
@bionicjs/supabaseSupabaseserver/auth/supabase.ts
@bionicjs/workosWorkOSSSO / directory sync

The generated project carries the matching server/auth/ handler, and the framework automatically wires up the necessary middleware to protect API routes and verify JWT tokens before they reach your business logic or the Python RPC boundary.

Server-side verification

The handler in server/auth/ is where tokens are verified. The scaffolded pattern reads credentials from the environment and exposes an auth object on @bionicjs/core/server:

A self-hosted handler
1import { betterAuth } from "better-auth";
2
3const secret = process.env.BETTER_AUTH_SECRET;
4const baseURL = process.env.BETTER_AUTH_URL;
5
6if (!secret) throw new Error("BETTER_AUTH_SECRET is not set");
7if (!baseURL) throw new Error("BETTER_AUTH_URL is not set");
8
9export const auth = betterAuth({
10  secret,
11  baseURL,
12  emailAndPassword: { enabled: true },
13});

Environment variables are the contract - each provider template writes its expected keys into .env.example so a fresh clone can be filled in without guessing names.

Protecting routes

Middleware runs before the route handlers and before the Python RPC boundary. A protected API route never performs work without a verified session:

server/api/me.ts
1import { auth } from "@bionicjs/core/server";
2
3export default defineEventHandler(async (event) => {
4  const session = await auth.getSession(event);
5  if (!session) throw createError({ statusCode: 401 });
6  return session.user;
7});
  • The websocket, /api, and server actions all go through the same session verification.
  • Unverified requests fail in middleware - they never reach a handler or Python.
  • Client-side, the frontend renders based on session state from the same auth boundary.
ⓘ
BionicJS does not define its own auth protocol. It wires the provider you chose - the JWT format, session store, and verification rules belong to Better Auth, Clerk, Firebase, or Supabase. BionicJS makes the wiring automatic and typed.