Skip to content

Upgrading Custom Apps: 0.1.x β†’ 0.2.x ​

This is part 1 of the core 0.1.x β†’ 0.2.x upgrade (session auth). It covers the custom app root: packages, config, env, landing routes, and frontend cookies.

Part 2: Plugin auth (JWT β†’ sessions) β€” migrate plugin route handlers (req.user β†’ req.authUser) after the app-root steps below.

Fresh 0.2.x apps can skip both guides.

What Changed ​

Area0.1.x0.2.x
TransportauthToken cookie + Authorization: Bearer <JWT>HttpOnly session cookie (sid_app / sid_workbench)
Login / logoutJWT issue / clearPOST /auth/login, POST /auth/logout
Session storeClient-held JWTValkey (opaque session id)
Request identityreq.userreq.authUser (userId, isAdmin, provider)
Reserved frontend pathsβ€”/login, /logout (not composition pages)

After cutover, every user must log in again. Old JWT sessions are invalid.

Required Steps (in order) ​

1. Bump packages ​

json
{
  "dependencies": {
    "@raclettejs/core": "0.2.x",
    "@raclettejs/workbench": "0.2.x"
  }
}

Reinstall and regenerate (restart the app so .raclette/ and generated-config.ts rebuild).

2. Auth config ​

Browsers store one cookie per name per host (port is ignored). Product app and workbench must use different cookie names when they share a hostname (typical local setup: both on localhost).

StackCookie name
Product / main appsid_app (core default)
Workbenchsid_workbench (workbench default)

Add an explicit auth block in your app raclette.config (YAML or JS). Example from the playground:

yaml
auth:
  cookie:
    name: "sid_app"
global:
  requireAuthentication: true

Equivalent JS:

js
export default {
  auth: {
    cookie: {
      name: "sid_app",
      // secure: false, // typical for local HTTP
      // sameSite: "lax",
    },
  },
  global: {
    requireAuthentication: true,
  },
}

Defaults already use sid_app. Set the name explicitly when documenting or co-hosting with workbench. Keep global.requireAuthentication: true unless you intentionally allow anonymous product access.

See Authentication for session TTL, cookie hardening, and OAuth.

3. Environment cleanup ​

Remove (unused under session auth):

  • SERVER_TOKEN_SECRET
  • RACLETTE_SERVER_TOKEN_SECRET

Ensure (production and OAuth):

VariableRole
RACLETTE_FRONTEND_URLSComma-separated app + workbench origins (CORS, OAuth return-to)
CACHE_URL / RACLETTE_CACHE_URLValkey used for sessions (default cache instance)

Optional hardening:

VariableRole
RACLETTE_VALKEY_PASSWORDValkey requirepass
RACLETTE_SECRET_ENCRYPTION_KEYEncrypt OAuth clientSecret and similar secrets at rest (openssl rand -base64 32)
RACLETTE_AUTH_COOKIE_NAMEOverride cookie name when a backend loads another stack’s generated config

4. Frontend auth plumbing ​

Stock orchestrator login/logout needs no rewrite. Core already uses cookie sessions (credentials / withCredentials).

Remove any custom app code that:

  • Sets an authToken cookie
  • Sends Authorization: Bearer <JWT> to raclette APIs
  • Calls legacy check-token endpoints for session validity

Keep Bearer tokens for upstream APIs (third-party OAuth access tokens, external portals, etc.).

Custom fetch / axios clients that talk to the raclette backend must include cookies:

ts
// fetch
fetch("/auth/session", { credentials: "include" })

// axios
axios.create({ withCredentials: true })

/login and /logout are reserved auth routes. After login, the app navigates to / (or a safe ?redirect= path). Without a landing composition, that path can 404.

Ship default seeds under the app root (installable from workbench: Project β†’ install default config):

text
<app>/config/compositions.js
<app>/config/interactionLinks.js

Mark exactly one interaction link as the landing page:

js
// config/compositions.js
export default [
  {
    _id: "home",
    pathname: { default: "home" },
    widgetsLayout: [
      [
        {
          column: 12,
          widget: {
            uuid: "main",
            name: "Main",
            pluginKey: "your__plugin-key",
          },
        },
      ],
    ],
  },
]
js
// config/interactionLinks.js
import compositions from "./compositions.js"

export default [
  {
    _id: "homeLink",
    composition: compositions[0]._id,
    slotType: "page",
    triggers: [
      {
        type: "page-navigation",
        settings: {
          icon: "mdi-home",
          title: { default: "Home" },
          sortOrder: 0,
          navigationBarType: "navItem",
        },
      },
    ],
    isLandingPage: true,
  },
]

Alternatively, mark a Landing page in the workbench UI if you do not seed files.

6. Migrate plugin routes ​

In every plugin route that reads the authenticated user:

BeforeAfter
req.user._idreq.authUser!.userId
req.user.isAdminreq.authUser!.isAdmin

Remove import { authenticate } from "@m/authentication" β€” use fastify.authenticate in route config.

Full checklist (asset tokens, permissions, work sessions): Plugin auth (JWT β†’ sessions).

Optional / Conditional ​

Dual Valkey (ephemeral auth + persistent plugin data) ​

Only if 0.1.x used one persistent Valkey for both sessions and durable plugin snapshots.

Split into ephemeral cache (sessions) + persistent cachePersistent (snapshots). Follow:

Apps that only use short-lived cache can keep a single ephemeral cache instance.

Cache DB indices ​

Optional. Playground documents an optional split:

yaml
cache:
  db: 0
  dbs:
    workbench: 1

Most apps omit this (app and workbench share DB 0). Revisit only if you previously isolated Redis DBs.

If you previously minted JWT-backed download URLs, switch to session asset tokens (mintAssetToken / mintSessionAssetToken or the raclette__core assetLink datatype). See Asset Downloads and the playground assetLinkExample widget.

Verification Checklist ​

  • [ ] Login and logout round-trip (cookie set / cleared)
  • [ ] Post-login lands on a real page (not 404 / blank /login catch-all)
  • [ ] App and workbench sessions do not overwrite each other (sid_app vs sid_workbench)
  • [ ] Protected API calls succeed with cookies (no Bearer JWT to raclette)
  • [ ] Plugin creates/updates still attribute owner / updatedBy correctly
  • [ ] Work session guest links still work (x-work-session-id), if used
  • [ ] OAuth login + return-to, if configured
  • [ ] Users re-authenticated after deploy

For Coding Agents β€” Apply This Migration ​

Search and edit in the app root (never edit .raclette/ or generated-config.ts by hand):

  1. package.json β€” bump @raclettejs/core and @raclettejs/workbench to 0.2.x
  2. raclette.config.* β€” add auth.cookie.name: "sid_app"; keep global.requireAuthentication unless intentional
  3. .env / .env.example / compose env β€” remove *TOKEN_SECRET; set RACLETTE_FRONTEND_URLS; wire CACHE_URL
  4. Grep and fix
    • req.user β†’ req.authUser (see plugin migration guide)
    • authToken, Authorization: Bearer used against raclette APIs β†’ remove
    • SERVER_TOKEN_SECRET, RACLETTE_SERVER_TOKEN_SECRET β†’ remove
    • @m/authentication β†’ remove imports; use fastify.authenticate
  5. config/compositions.js + config/interactionLinks.js β€” ensure one link has isLandingPage: true
  6. Conditional β€” if the app persists Valkey snapshots, follow the dual-Valkey migration guide; do not invent a second instance otherwise

Reference implementation: @raclettejs/playground (raclette.config.yaml, config/, plugin routes using req.authUser!.userId).