Deep DivesAdmin

Authentication

How authentication works in the RawStack Admin application.

The Admin application is a React SPA built with Vite. Because it runs entirely in the browser, it uses a different authentication strategy to the Web app. Rather than managing tokens server-side, the Admin uses the API's browser context to obtain tokens. The refresh token is stored in an HttpOnly cookie scoped to the token endpoint, and the access token is held in memory.

This pattern is a well-established approach for SPAs. It keeps the refresh token out of reach of JavaScript entirely, while the short-lived access token lives only in application memory — never in localStorage or sessionStorage.

Overview

When a user signs in, the Admin calls the token endpoint with an Auth-Context: browser header. This tells the API to deliver the refresh token as an HttpOnly cookie rather than in the response body. The access token is returned in the response body as normal.

POST v1/auth/tokens
Auth-Context: browser
Content-Type: application/json
{
  "email": "[email protected]",
  "password": "supersecret"
}
{
  "item": {
    "accessToken": "eyJhbG...",
    "ttlSeconds": 1500,
    "expiresAt": "2026-04-30T13:02:19.287Z"
  }
}

The refresh token is not in the response body. The API has set it as an HttpOnly cookie on the response instead.

At a high level, the sign-in flow looks like this:

  1. The user submits their credentials.
  2. The Admin calls POST v1/auth/tokens with Auth-Context: browser.
  3. The API returns the access token in the response body and sets the refresh token as an HttpOnly cookie scoped to v1/auth/tokens.
  4. The Admin stores the access token in memory.
  5. The browser holds the refresh token cookie. JavaScript cannot read it.
  6. Subsequent API requests attach the in-memory access token as a Bearer token in the Authorization header.

Access token in memory

The access token is stored in application memory — typically in a React context or an auth store — and attached to every authenticated API request via the Authorization header.

Keeping the token in memory rather than in localStorage or sessionStorage means it cannot be read by injected scripts. The trade-off is that the token is lost if the user refreshes the page. That is handled by the silent refresh flow described below.

The refresh token is an HttpOnly cookie set directly by the API. It has two important properties:

  • HttpOnly: JavaScript cannot read or access the cookie value. It is attached to requests automatically by the browser.
  • Scoped to v1/auth/tokens: the cookie is only sent when the browser makes a request to the token endpoint. It is never attached to regular API requests.

This means that even if an attacker can execute JavaScript in the Admin app, they cannot read or exfiltrate the refresh token.

Silent refresh on page load

Because the access token is in memory, it does not survive a page refresh. On startup, the Admin attempts a silent token refresh to restore the session without asking the user to sign in again.

The flow works like this:

  1. The page loads and the in-memory access token is empty.
  2. The Admin calls POST v1/auth/tokens/refresh. The browser automatically includes the refresh token cookie.
  3. If the refresh token is valid, the API returns a new access token and rotates the refresh token cookie.
  4. The Admin stores the new access token in memory. The user is now authenticated without having seen a login screen.
  5. If the refresh token is missing, expired, or invalid, the silent refresh fails and the user is redirected to the sign-in page.

This gives the user the experience of a persistent session across page reloads while still keeping the refresh token out of JavaScript's reach.

Sign out

When the user signs out, the Admin clears the in-memory access token and calls the sign-out endpoint. The API invalidates the refresh token and clears the cookie.

After sign-out, neither token remains. The browser no longer has a valid refresh token cookie, so a silent refresh on the next page load will fail and the user will be redirected to sign in.

Why this approach works well

This authentication model is well suited to a browser-based SPA:

  • the refresh token is in an HttpOnly cookie — JavaScript cannot read or steal it
  • scoping the cookie to the token endpoint means it is never sent with regular API calls
  • the access token is in memory — it is not persisted anywhere that survives a script injection attack
  • silent refresh on load restores the session transparently
  • sign-out fully clears both tokens with no residual state

Taken together, this gives the Admin a practical and secure authentication model that follows established best practices for single-page applications.