Authentication
How authentication works in the RawStack Web application.
The Web application authenticates users through the core API and manages sessions using iron-session. Because the Web app is built as a BFF, all communication with the API happens server-side through Next.js Server Actions. Tokens are never passed to the browser. Instead, the Server Actions obtain tokens from the API, encrypt them into an iron-session cookie, and return only that cookie to the browser.
This page explains how authentication flows through the web application and how it maps to the token system provided by the core API.
Overview
When a user signs in, the Web app's Server Action calls the core API using the default context — no Auth-Context header is set. This is correct because the call is server-to-server, not from a browser. The API returns both the access token and the refresh token in the response body.
The Server Action then stores those tokens in an encrypted iron-session cookie and returns that cookie to the browser. From this point on, the browser holds only the iron-session cookie. It never sees the raw tokens.
On subsequent authenticated requests, Server Actions read the tokens back out of the iron-session cookie and attach them to outgoing API calls on the user's behalf.
At a high level, the sign-in flow looks like this:
- The user submits their credentials in the browser.
- A Server Action receives the credentials and calls
POST v1/auth/tokenson the core API with noAuth-Contextheader. - The API returns an access token and a refresh token in the response body.
- The Server Action writes both tokens into an encrypted iron-session cookie.
- The browser receives the cookie and is now authenticated.
- On subsequent requests, Server Actions read the tokens from the session cookie and call the API on the user's behalf.
How the web app differs from other clients
Each client interacts with the token endpoint in the way that suits its environment:
- Web (BFF): uses the default context. The Next.js server receives both tokens, stores them in an iron-session cookie, and manages the session server-side.
- Admin: sets
Auth-Context: browser. The API places the refresh token in anHttpOnlycookie directly, and the access token is returned in the response body. - Mobile: uses the default context. Both tokens are returned in the response body and stored securely on the device.
The web app's approach is appropriate because there is no browser involved in the API call itself. The Next.js server behaves like any other server-side client, and iron-session gives the browser a secure, opaque session cookie to carry.
Session management with iron-session
iron-session is a lightweight session library that stores session data in an encrypted, signed cookie. The Web app uses it to hold the access token and refresh token server-side, without ever exposing them to the browser.
When a user signs in, the Server Action writes the tokens into the session:
import { getIronSession } from 'iron-session';
import { cookies } from 'next/headers';
const session = await getIronSession<SessionData>(await cookies(), sessionOptions);
session.accessToken = data.item.accessToken;
session.refreshToken = data.item.refreshToken;
session.expiresAt = data.item.expiresAt;
await session.save();On every subsequent authenticated Server Action, the session is read back and the access token is attached to the outgoing API call:
const session = await getIronSession<SessionData>(await cookies(), sessionOptions);
const token = session.accessToken;When the access token has expired, the Server Action uses the stored refresh token to obtain a new token pair, updates the session, and continues with the original request. This token refresh is invisible to the browser.
When the user signs out, the session is destroyed:
session.destroy();The iron-session cookie is HttpOnly, Secure, and SameSite=Lax. Its contents are encrypted, so the browser cannot read the tokens even if it inspects the cookie value.