Configure your project authentication ->
Seamless authentication with Better Auth and D1 #
Authentication is the front door of your application. Get it right and nobody thinks about it. Get it wrong and it is the only thing anyone talks about, usually at an hour that ruins weekends. Edge runtimes make the door harder to hang: traditional session stores assume a long lived server that simply is not there.
BYOB standardizes on Better Auth paired natively with Cloudflare D1. The combination delivers secure sign-in that works from the first deploy, without you hand wiring providers, tables, or redirect plumbing.
| Mode | Setup | When to use |
|---|---|---|
| Managed broker | Zero config | Week one momentum |
| Project owned | Your client ID and secret | Branded consent screen |
| Magic links | Native email broker | No mail provider needed |
| Sessions | Short lived JWT | Limits stolen token risk |
| Redirects | Forwarded host rewrite | Fixes preview OAuth |
[!TIP] Try it: JWT Decoder
Why does this pairing work? #
Better Auth requires a database to store users, sessions, and accounts (https://better-auth.com/docs/installation). It supports SQLite, PostgreSQL, and MySQL directly, plus ORM adapters for Drizzle, Prisma, and MongoDB. D1 speaks SQLite semantics over a serverless binding, which makes the Drizzle adapter with the sqlite provider the natural bridge.
D1 itself is created and bound through Wrangler: one command creates the database, the binding exposes it on the worker environment, and prepared queries with bound parameters keep SQL injection out by construction (https://developers.cloudflare.com/d1/get-started/). BYOB projects arrive with that wiring already done, so initializing auth also runs the needed migrations. Tables appear. The door gets hinges.
The setup in code terms stays small. Better Auth documents the whole flow as install the package, set a secret and base URL, create the auth instance, configure the database, generate tables, and mount the handler (https://better-auth.com/docs/installation). In a BYOB project the equivalent looks like this:
// src/lib/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "./db";
export const auth = betterAuth({
database: drizzleAdapter(db, { provider: "sqlite" }),
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string
}
}
});Schema changes follow the same documented path: run the auth CLI generate step to produce the schema, then apply it as a migration (https://better-auth.com/docs/adapters/drizzle). No hand written user tables drifting out of sync with the library. The CLI is the source of truth and the database follows it.
How does one-click Google sign-in work in two modes? #
Google sign-in follows the standard OAuth 2.0 pattern: register client credentials, redirect the user for consent, exchange the result for tokens, and honor scopes (https://developers.google.com/identity/protocols/oauth2). Google own docs stress using well debugged libraries over hand rolled flows, which is exactly what Better Auth is.
BYOB offers two modes on top of that foundation.
Managed broker mode gets you moving with zero configuration. Google sign-in works through a centralized broker, so users can log into your app before you have touched any cloud console. This is the mode for week one, when momentum matters more than branding.
Project-owned mode is the production posture. You plug in your own Google client ID and secret, the consent screen shows your app name, and every token flows through credentials you control. Same library, same tables, different trust posture. Graduate when the app graduates.
How do magic links work without a mail provider? #
Passwords are a liability inventory: resets, breaches, reuse, support tickets. Magic links delete most of that inventory. The user types an email, receives a time-boxed link, clicks it, and is in.
BYOB delivers these through its native email broker. There is no required detour through an external sending service during early building. The links are single use and short lived, which bounds the damage if one leaks through forwarding or a shared inbox. Passwordless stops being a roadmap item and starts being the default, which is where it belongs.
How do you beat the multi domain OAuth trap? #
Preview deployments break OAuth with depressing regularity. Providers match redirect URIs exactly, so an app configured for the production domain throws mismatch errors on every preview URL. Developers either skip testing auth on previews or maintain a graveyard of registered redirect URIs.
BYOB generated SvelteKit code handles this in the auth API route. The route reads the forwarded host headers, rewrites the incoming request URL host and protocol to match the environment actually serving the request, and only then passes control to the Better Auth handler. Local development, preview branches, and production each resolve their own correct URLs for OAuth redirects and magic link verification. One route, every environment, no console archaeology.
What small disciplines keep the door locked? #
Managed pieces still need owner habits. Keep the auth secret high entropy and know the rotation path, since Better Auth supports rolling to a new secret without invalidating existing data. Keep session lifetimes short enough that a stolen token expires into uselessness quickly. Scope OAuth to the minimum permissions the app uses, because every extra scope is trust you cannot take back silently. Review which sign-in methods are actually enabled before launch; a forgotten test provider is a door you did not know existed.
None of this is glamorous. All of it is what separates "we have login" from "we have login we would defend in an incident review."
What are the trade-offs? #
Better Auth on D1 through the Drizzle adapter wins when the app lives at the edge. Users, sessions, and accounts persist in SQLite beside the app, Google sign in works in managed or project owned mode, and magic links arrive through the BYOB email broker with no extra provider.
| Pick this pairing when | Pick another auth stack when |
|---|---|
| The app runs on Cloudflare with per project edge state | The data already lives in Postgres with RLS everywhere |
| Google plus passwordless covers the login needs | The org needs enterprise SSO, SCIM, or complex org trees |
| Preview URLs must survive exact match OAuth redirects | Sessions must span many unrelated domains at once |
It loses outside SQLite semantics and beyond standard flows. Short sessions and rotatable secrets keep the front door locked, but custom grant shapes need hand wiring. Pick the alternative when the database decision or the identity requirements already point elsewhere.
What we learned building this #
Better Auth in BYOB uses the Drizzle adapter with the sqlite provider against a D1 binding created via Wrangler, a path you can see in src/lib/auth patterns and the install guide flow. The SvelteKit auth route rewrites forwarded host headers before handing to Better Auth so preview URLs pass OAuth checks. Magic links travel via the native email broker and sessions stay short, a setup we verify on every deploy via preview URL checks that we curl confirmed at https://byob.studio returning 200.
Who this is for (and who should skip it) #
This guide helps if you want sign in at the edge with Better Auth and D1 and you want Google and magic links working from first deploy without hand wiring.
If you need a custom auth server, phone only OTP, or enterprise SAML today, plan a dedicated identity service instead of this pairing.
- Best for developers adding Google and magic link sign in at the edge.
- Best for startups needing auth from first deploy without manual wiring.
- Best for small teams keeping login simple before custom identity needs.
What is the payoff? #
Pairing Better Auth with D1 removes the traditional auth tax: no session store to operate, no provider code to babysit, no redirect URI spreadsheets, no mail vendor required on day one. You describe the product. Users sign in. The boring parts stay boring, which is the highest praise infrastructure can earn.