Authentication
The dashboard (packages/cf-app) uses WorkOS AuthKit for merchant authentication. AuthKit is a hosted login UI — no custom login forms. Users are invited via the WorkOS admin console; sign-up is disabled.
Auth flow
Section titled “Auth flow”/stats/fmdf │ ▼ beforeLoad → checkSession() │ ├─ session cookie valid → load dashboard │ └─ no session → redirect: /auth/workos/login?return_to=/stats/fmdf │ ▼ encode return_to in WorkOS state param │ AuthKit hosted login (Google, email+password, magic link) │ ▼ WorkOS redirects back │ /auth/workos/callback?code=...&state=... │ ▼ exchange code → sealed session → set wos-session cookie │ redirect to return_to (decoded from state)Key files
Section titled “Key files”| File | Purpose |
|---|---|
src/lib/workos-session.ts | Session helpers — getSession(), getAuthorizationUrl(), handleAuthCallback(), getLogoutUrl(), getUserStores() |
src/routes/auth/workos/login.tsx | Reads ?return_to, redirects to AuthKit |
src/routes/auth/workos/callback.tsx | Exchanges code for sealed session, sets cookie, redirects |
src/routes/auth/workos/logout.tsx | Clears cookie, redirects to WorkOS logout |
src/routes/stats/$hash.tsx | beforeLoad calls checkSession() server function |
Session cookie
Section titled “Session cookie”- Name:
wos-session - Format: WorkOS sealed session (encrypted with
WORKOS_COOKIE_PASSWORD) - Attributes:
HttpOnly,Secure,SameSite=Lax,Path=/, 30-day max-age - Refresh: Access tokens expire after 5 minutes.
getSession()auto-refreshes viasession.refresh()and updates the cookie transparently.
Access control
Section titled “Access control”Two tiers:
- Admin users — hardcoded in
ADMIN_USER_IDSset inworkos-session.ts. Full access to all clients.getUserStores()returns"all". - Merchant users — per-user KV mapping. Key:
user-store:{workos_user_id}, value:["fmdf", ...]. Users can only access slugs in their list.
Adding a merchant user
Section titled “Adding a merchant user”- Invite them via the WorkOS dashboard (Users → Send invitation)
- After they accept, note their WorkOS user ID (
user_...) - Seed KV:
Terminal window wrangler kv put "user-store:{user_id}" '["fmdf"]' \--binding LAYERKICK_KV --preview false
Environment variables
Section titled “Environment variables”| Variable | Secret? | Where |
|---|---|---|
WORKOS_CLIENT_ID | No | wrangler.jsonc vars |
WORKOS_API_KEY | Yes | .dev.vars + wrangler secret put |
WORKOS_COOKIE_PASSWORD | Yes | .dev.vars + wrangler secret put (min 32 chars) |
DEV_BYPASS_AUTH | — | .dev.vars only (local dev) |
Production secrets
Section titled “Production secrets”cd packages/cf-appnpx wrangler secret put WORKOS_API_KEY --name lk-dashboardnpx wrangler secret put WORKOS_COOKIE_PASSWORD --name lk-dashboardWorkOS dashboard config
Section titled “WorkOS dashboard config”Three redirect URIs must be registered under Redirects in the WorkOS dashboard:
| Setting | Local | Production |
|---|---|---|
| Redirect URI | http://localhost:3051/auth/workos/callback | https://app.layerkick.com/auth/workos/callback |
| Login URL | http://localhost:3051/auth/workos/login | https://app.layerkick.com/auth/workos/login |
| Logout URL | http://localhost:3051/auth/workos/logout | https://app.layerkick.com/auth/workos/logout |
Sign-up is disabled — screenHint: "sign-in" is passed to the authorization URL. Users must be invited from the WorkOS admin console.
Local development
Section titled “Local development”Set DEV_BYPASS_AUTH=1 in packages/cf-app/.dev.vars to skip WorkOS entirely. getSession() returns a fake admin session with full client access. Remove or unset to test the real auth flow locally.