Users & Auth
How It Works
The Gateway handles signup, login, and sessions. Your app receives session tokens and verifies them. On first access, you create a local user record so you have somewhere to associate data.
The ensureUser Pattern
On every authenticated request, check if the user exists locally. If not, create them:
export const ensureUser = createMiddleware().server(async ({ next }) => { const session = await authenticateRequest(getAuthConfig()); if (!session?.sub) throw new Error("Unauthorized");
// Create user if they don't exist (upsert) await UserService.ensureUser({ id: session.sub, email: session.email, });
return next();});The user ID (session.sub) comes from the Gateway - use this same ID so data stays linked across both systems.
Authenticating Requests
Client side: The SDK middleware adds the session token to every request automatically.
export const getAllRecipes = createServerFn({ method: "GET" }) .middleware([useSessionTokenClientMiddleware]) // Adds Authorization header .handler(async () => { const session = await authenticateRequest(authConfig); return RecipeService.getAll(session.sub); });Server side: authenticateRequest verifies the JWT using the Gateway’s public keys (JWKS) and returns the decoded payload with the user ID.
See the SDK docs for more details on how session tokens work.