sveltekit-auth
Auth.js's SvelteKit example
— a home page, a sign-in page, a page only a signed-in visitor can read and a
sign-out, over @auth/sveltekit
with the example's 26 OAuth providers — running on Cloudflare Workers +
Static Assets through SvelteKit's own
@sveltejs/adapter-cloudflare,
and packaged as an Orun baseline: one command takes a new site from
nothing to live on stage and prod, in its own repository, under its own
name, in ONE landing.
Sessions are the example's: Auth.js's encrypted JWT cookie, so there is no
database. Each provider is offered once its keys are stored as the site's
secrets, so the site goes live with none connected and its sign-in page
says what to connect; the AUTH_SECRET that seals the sessions is generated
on each environment's Worker by its first deploy, so nothing is typed. What
the baseline adds is everything needed to make a copy of it somebody
else's, built the way cirrus-baseline
is. The design, the milestones and the as-built status are in
specs/epics/sveltekit-auth.
ISC, © 2022-2024 Balázs Orbán (apps/web/LICENSE).
Instantiating a site
git clone --depth 1 --branch <baseline-tag> https://github.com/sourceplane/sveltekit-auth
cd sveltekit-auth
orun new --blueprint repo-blueprint.yaml --out ~/sites/acme-accounts --run-hooks --resume \
--set reponame=acme-accounts --set productname="Acme Accounts" \
--set githuborg=acme-inc --set subdomain=<workers-dev-subdomain>
Or, once the platform's registry lists it, from the Orun console (Baselines →
sveltekit-auth → Build). Two phases: 01-product creates the
repository and lands the whole site as ONE pull request — intent, CI,
tooling, the site and its tests — and one convergence builds it, gives each
environment's Worker its AUTH_SECRET and deploys it to stage and prod;
03-docs records the live deployment from probed facts.
BOOTSTRAP.md is the operator guide;
docs/phases/ has a page per phase.
The new repository receives the site only — the app and its tests, its
CI, its tooling, a README of its own and its operating contract — renamed
throughout to the site's name, repository and Cloudflare Worker, with
Auth.js's own names (SvelteKitAuth, sveltekit-auth-example) and the
example's licence left as they are. None of this repository's machinery
ships.
| What makes it a baseline | Where |
|---|---|
| The console card (inputs, secrets, programme) | blueprint.yaml |
| The build document (modules, phases, hooks) | repo-blueprint.yaml |
| This tree's identity, and the bootstrap's task contracts | .baseline/ |
| The rename engine | tooling/rebrand/rebrand.mjs |
| The bootstrap's helpers (deferrals, redeploy marker, work-tree strip) | tooling/bootstrap/ |
| The deployment-record renderer | hooks/render-deployment-docs.sh |
| The site's README and context pack | .baseline/product/README.md, ai/context/ |
| The baseline's tests: contract, leak, offline bootstrap, end to end | testing/, .github/workflows/baseline.yml |
Cutting a baseline-vN tag | .github/workflows/tag.yml |
What is here (the site)
| Surface | Where |
|---|---|
The site's name (the home page's heading, every page's <title>) | apps/web/src/site.ts |
/, /signin (the connected providers, or what to connect), /protected, /signout | apps/web/src/routes |
| Auth.js, configured per request from the Worker's secrets | apps/web/src/auth.ts, apps/web/src/hooks.server.ts, apps/web/src/server/env.ts |
| The 26 providers and the keys each needs | apps/web/src/server/providers.ts |
| The header (who is signed in) and the footer | apps/web/src/components |
| The deploy step that gives each Worker its secrets | tooling/wire/worker-secrets.mjs |
| Adapter, Worker config, deploy contract | apps/web/svelte.config.js, apps/web/wrangler.jsonc, apps/web/component.yaml |
| Tests (the providers, the bindings, the site's name, the secret step) | apps/web/src/**/*.test.ts (vitest) |
Getting started
pnpm install # runs `svelte-kit sync`
pnpm typecheck # svelte-check
pnpm lint # prettier --check
pnpm test # vitest
pnpm build # vite build → apps/web/.svelte-kit/cloudflare (_worker.js + the static output)
pnpm --filter @app/web secret:dev # a generated AUTH_SECRET in apps/web/.env (git-ignored)
pnpm --filter @app/web dev # http://localhost:3000
pnpm --filter @app/web preview # wrangler dev over the built Worker
Both read apps/web/.env; .env.example beside it, the example's own,
lists every key the site takes. Add a provider's keys there (GitHub: an OAuth app whose
callback is http://localhost:3000/auth/callback/github) and its button
appears on /signin.
Deploying
The Orun pipeline (.github/workflows/ci.yml) plans nothing while
intent.yaml names the placeholder workspace ws_CHANGE_ME. Link the
repository to an Orun Cloud workspace (orun cloud link), set
execution.state.workspace to it, connect Cloudflare in the workspace, and
every merge to main then deploys sveltekit-auth-web-stage, then
-prod: built, its secrets pushed to the Worker (wrangler secret bulk,
the AUTH_SECRET generated on the first deploy and kept after), deployed and
smoke-tested on / and /auth/session. A pull request verifies the same
lanes and deploys nothing. A manual run of ci.yml (Run workflow on
main, or Orunbase's Deploy button) redeploys the components it names —
which is how a provider's newly stored keys reach the Worker.
Sign-in providers
None is connected at first. A provider appears once every key it takes
is set: AUTH_GITHUB_ID + AUTH_GITHUB_SECRET for GitHub, and the same
shape for the others (Auth0 adds AUTH_AUTH0_ISSUER). Deployed, they are
optional Orun secrets per environment (orun secrets set AUTH_GITHUB_ID --env stage), pushed to the Worker by its next deploy; the OAuth app's
callback URL is <origin>/auth/callback/<provider>. The component carries
secret refs for the nine providers upstream's .env.example names; the
site's README ("Sign-in providers") says how to deploy the others.
How it maps to Vercel
| The example on Vercel | Here |
|---|---|
@sveltejs/adapter-auto (→ adapter-vercel) | @sveltejs/adapter-cloudflare: the Worker at .svelte-kit/cloudflare/_worker.js, the static output beside it (wrangler.jsonc) |
"@auth/sveltekit": "latest" | 1.11.3, exact; SvelteKit, Svelte and Vite at upstream's versions, exact, and upstream's cookie@0 override |
AUTH_SECRET typed into Vercel's environment variables | generated on each environment's Worker by its first deploy (tooling/wire/worker-secrets.mjs), kept by every later one; an Orun secret of the same name wins |
| provider keys in Vercel's environment variables, all 26 providers always registered | optional Orun secrets pushed as Worker secrets; a provider is registered only when its keys are set, and /signin says what to connect |
$env/dynamic/private from the platform's env | the Worker's bindings (platform.env), read per request; .env locally, as upstream, for vite dev and wrangler dev alike |
| sessions: Auth.js's JWT cookie | the same; no database |
| Deploy on push | Orun deploys <repo>-web-{stage,prod} on merge to main (apps/web/component.yaml), smoke-tested |
| "Deploy with Vercel" (clone the example) | orun new --blueprint repo-blueprint.yaml — a new repository, branded, deployed |
CI
| Workflow | What it runs | Ships to a site |
|---|---|---|
ci.yml | the Orun pipeline, and the only workflow a site carries: orun plan --changed, then one job per lane. A pull request runs the verify lanes (the site built and dry-deployed per environment, no secret pushed; they do not typecheck, lint or run the tests), except the bootstrap's own landings (orun/BASE-*), where plan alone is the check; a merge deploys stage → prod. It plans nothing while intent.yaml names the placeholder workspace ws_CHANGE_ME, as this repository does. A manual run (Orunbase's Deploy button, or Run workflow on main) plans the environment and components it names under the push-to-main trigger, so they deploy as a merge deploys them | yes |
baseline.yml | the baseline's own tiers: contract tests, the blueprint read by the pinned orun, the leak gate, the offline bootstrap with the site's own plan, the site installed, type-checked, linted, tested, built and dry-deployed in the lane's tree and served — with no secret (the smoke refuses it), with one (every page), and with GitHub's keys (the authorize URL, a session, sign-out) (testing/e2e.test.sh, before every tag) | no |
tag.yml | cuts a baseline-vN tag (manual) | no |
Build from the console
Press Build: SvelteKit Auth goes into the workspace you choose (or a new one), you connect Cloudflare, and an agent builds it.
Build from the CLI
# check providers, then build
orun baseline check sveltekit-auth
orun baseline new sveltekit-auth --via-platform --repo acme/sveltekit-auth