A complete, production-ready authentication and authorization starter for Svelte 5 and SvelteKit 2. Skip the boilerplate — get secure local accounts, Google OAuth, MFA, email verification, role-based access control, OWASP-compliant password hashing, and bot protection out of the box.
| ✅ Local accounts (email + password) | ✅ Sign in with Google / Google One Tap |
| ✅ Multi-factor authentication (MFA via email) | ✅ Email verification |
| ✅ Forgot password / email reset (Brevo) | ✅ User profile management |
| ✅ Session management + timeout | ✅ Rate limiting |
| ✅ Role-based access control | ✅ Password complexity enforcement |
| ✅ Content Security Policy (CSP) | ✅ OWASP-compliant password hashing |
| ✅ Cloudflare Turnstile CAPTCHA (bot protection) |
# Clone the repo to your current directory
git clone https://github.com/nstuyvesant/sveltekit-auth-example.git
# Install the dependencies
cd sveltekit-auth-example
yarn install
# Create PostgreSQL database (only works if you have PostgreSQL installed)
bash db_create.sh
Create a Google API client ID per these instructions. Make sure you include http://localhost:3000 and http://localhost in the Authorized JavaScript origins, and http://localhost:3000/auth/google/callback in the Authorized redirect URIs for your Client ID for Web application. Do not access the site using http://127.0.0.1:3000 — use http://localhost:3000 or it will not work.
Create a free Brevo account and generate an API Key under SMTP & API settings. Set EMAIL to the sender address verified in your Brevo account.
Create a .env file at the top level of the project with the following values (substituting your own id and PostgreSQL username and password):
DATABASE_URL=postgres://user:password@localhost:5432/auth
DATABASE_SSL=false
DOMAIN=http://localhost:3000
JWT_SECRET=replace_with_your_own
BREVO_KEY=replace_with_your_own
EMAIL=replace_with_your_own
PUBLIC_GOOGLE_CLIENT_ID=replace_with_your_own
PUBLIC_TURNSTILE_SITE_KEY=replace_with_your_own
TURNSTILE_SECRET_KEY=replace_with_your_own
# Start the dev server and open the app in a new browser tab
yarn dev -- --open
# Build for production
yarn build
# Preview the production build
yarn preview
The db_create.sql script adds three users to the database with obvious roles:
| Password | Role | |
|---|---|---|
| admin@example.com | Admin1234! | admin |
| teacher@example.com | Teacher1234! | teacher |
| student@example.com | Student1234! | student |
MFA note: Local account logins require a 6-digit code sent to the user's email address. To successfully log in with the seed accounts above, either update their email addresses in the database to your own (
UPDATE users SET email = '[email protected]' WHERE email = '[email protected]';), or retrieve the code directly from themfa_codestable after submitting the login form (SELECT code FROM mfa_codes;).
The website supports two types of authentication:
appState (see /src/lib/app-state.svelte.ts).appState (see /src/lib/app-state.svelte.ts).There is some overhead to checking the user session in a database each time versus using a JWT; however, validating each request avoids problems discussed in this article. For a high-volume website, I would use Redis or the equivalent.
The forgot password / password reset functionality uses a JWT and Brevo to send the email. You would need to have a Brevo account and set the BREVO_KEY and EMAIL environment variables (see setup instructions above). Email sending is in src/lib/server/brevo.ts and the email templates are in src/lib/server/email/. This code could easily be replaced by nodemailer or something similar.