Service 02

Auth Patterns

SSO. SAML. MFA. RBAC. Multi-tenant orgs. Production B2B auth — pre-wired to Clerk on the first commit. No auth code to write.


The problem

Auth is custom for every app. Every B2B deal asks for SSO.

Auth is the first thing every B2B deal interrogates and the last thing most teams invest in. The deal asks for SSO; your app has password auth. The deal asks for SAML; your app has Google sign-in. The deal asks for MFA; you say "next quarter."

By the time auth is done right, it's been rewritten three times. The team that builds custom auth never builds the agentic product they were hired to ship.


How it works

Clerk SSO/SAML + RBAC + middleware patterns, scaffolded by sage init.

Sage wires Clerk in at scaffold time. The frontend uses Clerk's React components (<SignIn />, <UserButton />, <Protect />). The backend validates Clerk JWTs in FastAPI dependencies, surfaces org_id, role, plan, and feature entitlements on every request, and isolates data by org.

SSO, SAML, MFA, magic-link — all toggle in the Clerk dashboard with no app code changes. Clerk Billing plan + features ride in JWT claims for zero-extra-call feature gating. Test fixtures use the +clerk_test@ convention for deterministic e2e tests.

  • Frontend: <SignIn /> + <UserButton /> + <Protect plan='starter'> Clerk components
  • Backend: validate Clerk JWTs in FastAPI dependencies — RBAC + plan/feature checks
  • Multi-tenancy: Clerk org_id + role on every request; data isolated by org
  • Billing: Clerk Billing plan + features embedded in JWT claims — pla / fea
  • Magic-link, SSO, SAML, MFA — all dashboard-toggleable; no app code changes
  • Test fixtures: +clerk_test@ convention bypasses verification with magic code 424242
backend/app/auth/middleware.py python
// backend/app/auth/middleware.py
from fastapi import Depends, HTTPException
from clerk_backend_api import Clerk

async def require_user(token: str = Depends(bearer_token)) -> User:
    """Validates Clerk JWT; raises 401 on failure. Resolves org + role."""
    claims = await clerk.verify_session(token)
    return User(
        id=claims.sub,
        org_id=claims.org_id,
        role=claims.org_role,
        plan=claims.pla,           # Clerk Billing plan
        features=claims.fea,       # entitlements
    )

# Route usage — RBAC built in:
@router.get("/admin/users")
async def list_users(
    user: User = Depends(require_user),
    _: None = Depends(require_role("admin")),
):
    return await user_service.list(user.org_id)

Pricing relevance

Auth Patterns ship in every Sage scaffold. Clerk usage is on the customer's Clerk account — Sage doesn't proxy auth. Enterprise tier includes pre-wired SAML config patterns and migration helpers.

Open-source posture

Auth patterns are OSS (Apache-2.0) — middleware code, route guards, test fixtures, JWT claim shapes. Clerk itself is third-party; the patterns are documented in the scaffold.

Get Started

B2B-ready auth on the first commit.

SSO, SAML, MFA, RBAC, multi-tenant orgs, plan-based feature gating — all pre-wired to Clerk. The first enterprise deal doesn't surprise your auth layer.