A full-stack authentication boilerplate using SvelteKit and SurrealDB. This template provides a complete authentication system with user registration, login, and session management.
- 🔑 Login system with JWT session cookiess
- 📝 User registration with email and password
- 🔒 Password hashing using bcrypt
- 📚 Globally available "singleton" database client for server-side and client-side usage
- 🔒 Database is request-isolated in the server, so different users get a unique database connection and client per request
- 🔗 Real-time database connections using WebSocket
- Clone this repository:
git clone https://github.com/AlbertMarashi/surrealdb-svelte-auth-template.git
cd surrealdb-svelte-auth-template
- Install dependencies:
npm install
# or
bun install
# or
pnpm install
- Copy the environment file and configure it:
cp .env.example .env
- Generate a secure AUTH_SECRET:
This will be used to sign and verify JWT tokens by your server, and must be shared with your database so that the database can verify the tokens.
openssl rand -hex 32
- Update your
.env
file with the generated secret and your SurrealDB configuration:
AUTH_SECRET=SHARED_SECRET_HERE
PUBLIC_SURREAL_NAMESPACE=development
PUBLIC_SURREAL_DATABASE=mydb
PUBLIC_SURREAL_HOST=ws://localhost:8000
SURREAL_USER=root
SURREAL_PASSWORD=root
- Start SurrealDB:
surreal start --user root --pass root --allow-guests memory
# --allow-guests allows the database to be accessed by unauthenticated users
- Initialize the database schema:
surreal import --conn http://localhost:8000 --user root --pass root --ns development --db mydb schema.surql
- Configure the database access via Surrealist or the Surreal CLI
DEFINE ACCESS OVERWRITE users ON DATABASE
TYPE RECORD
WITH JWT
ALGORITHM HS256
KEY "YOUR_GENERATED_SECRET"
DURATION FOR TOKEN 1w;
- Start the development server:
pnpm dev
# or
npm run dev
# or
bun run dev
/src/routes
- SvelteKit routes and API endpoints+layout.ts
- Gets the user from the+layout.server.ts
local data, and makes it available to all sub-routes+layout.server.ts
- Gets the user from theevent.locals.user
and passes it to the+layout.ts
component+page.ts
- Loads the currently active user from the database so that it can be used in the+page.svelte
component+page.svelte
- The main page component, which includes the login form and authentication statelogin/+server.ts
- A login API endpoint, which will also set the JWT cookie for future requests
/src/lib
- Sveltekit$lib
alias directorydatabase.ts
- SurrealDB client and database configuration (a user-authenticated database client, universally available on the server and client)utils
- Utility functions and typescookies.ts
- Cookie utilities (for setting and getting cookies)jwt.ts
- JWT utilities (for signing and verifying tokens)
request_data_store.ts
- Request data store for server-side usageadmin_db.ts
- A "root" authenticated database client, for full-permission sensitive operationsdatabase.ts
- A user-authenticated/unauthenticated database client for database-as-a-service paradigm usage
/src/hooks.server.ts
- Server-side hooks for authenticationschema.surql
- SurrealDB schema definition
We use the safe-ssr
package to provide request-level data isolation.
Using the database globally, eg inside of a load function:
import { user_db } from "$lib/database"
export async function load({ data }) {
// load the global server-side database client
const db = await user_db()
// query the database
const [records] = await db.query("SELECT * FROM some_record")
return {
records
}
}
Or inside of .svelte
components:
<script lang="ts">
import { user_db } from "$lib/database"
let records: string[] = $state([])
async function load_records() {
const db = await user_db()
[records] = await db.query("SELECT VALUE id FROM record")
}
async function create_record() {
const db = await user_db()
await db.query("CREATE record")
await do_something_with_db()
}
</script>
<button onclick={load_records}>
Load Records
</button>
<button onclick={create_record}>
Create Record
</button>
{#each records as record}
<p>{record}</p>
{/each}
Read more about safe-ssr
- Registration: Users can register with email, password, and name
- Login: Users receive a JWT token stored in cookies
- Session: Token is verified on each request and passed to the "user" database client.
- Also stores common user-specific data (name, email, etc) in the JWT token so that we don't need to query the database for it on each request
- Protected Routes: Access control based on authentication state via the
event.locals.user
POST /register
- Create a new user accountPOST /login
- Authenticate and receive a session tokenGET /
- Home page with authentication state
To run the project in development mode:
npm run dev
# or
bun run dev
# or
pnpm dev
MIT