Skip to content

Authentication

Document where Clerk authentication is enforced and where downstream services trust verified upstream identity.

  • Clerk issues sessions and JWTs.
  • Brisket validates user-facing requests with @clerk/nextjs middleware and auth().
  • Strip validates sessions with custom Fiber middleware and clerk-sdk-go/v2.
  • Brain uses a NestJS Passport guard backed by @clerk/backend.
  • Sirloin generally trusts upstream auth and uses the Clerk SDK for lookups.
  • Round has no auth and is internal-only.
sequenceDiagram
  participant User
  participant Clerk
  participant Brisket
  participant Strip
  participant Brain
  participant Sirloin
  participant Round
  User->>Clerk: Sign in
  Clerk-->>Brisket: Session/JWT
  Clerk-->>Strip: Session/JWT
  Brisket->>Sirloin: Request with verified user context
  Strip->>Sirloin: Request with verified user context
  Brain->>Brain: Guard checks Clerk unless route is public/API-key
  Brain->>Round: Internal gRPC call
  Sirloin->>Clerk: Lookup user metadata when needed

Until funnels launch, the main app layout keeps its existing IntroFunnelRedirect: signed-in users without a subscription or completed welcome quiz enter one simplified /welcome quiz, followed by its skippable paywall. This includes returning sign-ins who have not finished it. skip-post-signup-quiz ON bypasses the quiz; OFF shows it for eligible users. The redirect and welcome entry wait for the existing flag grace period when the flag is unresolved; if still unavailable afterward, they keep the quiz.

Email and OAuth authentication keep their existing destinations and callbacks. The app-entry redirect passes the current path and query through a sanitized return_to; closing the quiz paywall resumes that destination. Missing, unsafe or recursive returns use Explore. A direct welcome visit also honors the skip flag. Bypassing neither marks the quiz complete nor consumes funnel inputs. See the app-entry redirect, quiz entry and continuation helpers.

Quiz completion retains the existing starter-character behavior when characters-v2 is off; it does not use the saved funnel inputs.

At funnel launch, remove IntroFunnelRedirect from the main layout and retire the temporary welcome entry, skip flag and continuation helpers. Authentication has no quiz-specific wrappers to remove. Keep the auth return validation and /hop ownership checks. Existing character welcome, payment, credit, KYC and app-tour entry points remain unchanged.

A visitor already signed in on arrival at /f goes straight to Explore (/), without loading funnel progress or recording a funnel opening. A visitor who starts anonymously keeps the funnel session when authentication completes: it saves current answers and files before email, OAuth or sign-in departure. Authentication carries the exact funnel/publication reference to protected /hop, outside the main app layout. The hop resolves first; the main-layout quiz gate runs when the user reaches the resulting app destination. Server initialization completes funnel attribution before profile queries and authenticated analytics/flags mount; timeouts and transient failures log a warning, clear the pending attribution cookie, and silently redirect to Explore. Saved browser inputs are retained; failed attribution may remain unrecorded. /hop then validates browser ownership and the current publication and chooses a fixed internal destination. An unavailable character handler falls back to Explore without consuming saved data.

See funnel storage and routing, auth return policy, and hop route.

  • apps/brisket/src/middleware.ts
  • apps/strip/internal/app/middleware/auth.go
  • apps/brain/src/modules/application/auth/guards/clerk-auth.guard.ts
  • apps/sirloin/internal/pkg/clerk/

Unauthenticated browser requests become authenticated app requests after Clerk validation at the frontend/service edge. Sirloin receives user identifiers from trusted callers rather than revalidating every JWT.

  • User-facing services must validate Clerk identity before calling trusted backend paths.
  • Sirloin trust depends on upstream callers preserving verified user identity.
  • Round must remain internal-only unless an auth boundary is added.

Invalid or missing Clerk sessions are rejected by Brisket, Strip, or Brain before protected work starts. Strip also protects return_to redirects and token size.

  • Brisket: cd apps/brisket && pnpm test
  • Strip: cd apps/strip && make run-tests
  • Brain: cd apps/brain && pnpm test