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 β
| Area | 0.1.x | 0.2.x |
|---|---|---|
| Transport | authToken cookie + Authorization: Bearer <JWT> | HttpOnly session cookie (sid_app / sid_workbench) |
| Login / logout | JWT issue / clear | POST /auth/login, POST /auth/logout |
| Session store | Client-held JWT | Valkey (opaque session id) |
| Request identity | req.user | req.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 β
{
"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).
| Stack | Cookie name |
|---|---|
| Product / main app | sid_app (core default) |
| Workbench | sid_workbench (workbench default) |
Add an explicit auth block in your app raclette.config (YAML or JS). Example from the playground:
auth:
cookie:
name: "sid_app"
global:
requireAuthentication: trueEquivalent 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_SECRETRACLETTE_SERVER_TOKEN_SECRET
Ensure (production and OAuth):
| Variable | Role |
|---|---|
RACLETTE_FRONTEND_URLS | Comma-separated app + workbench origins (CORS, OAuth return-to) |
CACHE_URL / RACLETTE_CACHE_URL | Valkey used for sessions (default cache instance) |
Optional hardening:
| Variable | Role |
|---|---|
RACLETTE_VALKEY_PASSWORD | Valkey requirepass |
RACLETTE_SECRET_ENCRYPTION_KEY | Encrypt OAuth clientSecret and similar secrets at rest (openssl rand -base64 32) |
RACLETTE_AUTH_COOKIE_NAME | Override 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
authTokencookie - 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:
// fetch
fetch("/auth/session", { credentials: "include" })
// axios
axios.create({ withCredentials: true })5. Landing page seeds (compositions / interaction links) β
/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):
<app>/config/compositions.js
<app>/config/interactionLinks.jsMark exactly one interaction link as the landing page:
// config/compositions.js
export default [
{
_id: "home",
pathname: { default: "home" },
widgetsLayout: [
[
{
column: 12,
widget: {
uuid: "main",
name: "Main",
pluginKey: "your__plugin-key",
},
},
],
],
},
]// 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:
| Before | After |
|---|---|
req.user._id | req.authUser!.userId |
req.user.isAdmin | req.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:
cache:
db: 0
dbs:
workbench: 1Most apps omit this (app and workbench share DB 0). Revisit only if you previously isolated Redis DBs.
Asset download links β
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
/logincatch-all) - [ ] App and workbench sessions do not overwrite each other (
sid_appvssid_workbench) - [ ] Protected API calls succeed with cookies (no Bearer JWT to raclette)
- [ ] Plugin creates/updates still attribute
owner/updatedBycorrectly - [ ] 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):
package.jsonβ bump@raclettejs/coreand@raclettejs/workbenchto0.2.xraclette.config.*β addauth.cookie.name: "sid_app"; keepglobal.requireAuthenticationunless intentional.env/.env.example/ compose env β remove*TOKEN_SECRET; setRACLETTE_FRONTEND_URLS; wireCACHE_URL- Grep and fix
req.userβreq.authUser(see plugin migration guide)authToken,Authorization: Bearerused against raclette APIs β removeSERVER_TOKEN_SECRET,RACLETTE_SERVER_TOKEN_SECRETβ remove@m/authenticationβ remove imports; usefastify.authenticate
config/compositions.js+config/interactionLinks.jsβ ensure one link hasisLandingPage: true- 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).