Build a Fullstack SvelteKit App with Supabase Authentication
Introduction
SvelteKit is a powerful framework for building web applications with Svelte. Supabase provides a batteries-included backend with features like authentication, database, and storage. This article will guide you through setting up a fullstack SvelteKit application with Supabase authentication.
Prerequisites
- Node.js and npm installed
- A Supabase account and project created
Setup SvelteKit
First, let's create a new SvelteKit project:
npm create svelte@latest my-sveltekit-app
cd my-sveltekit-app
npm install
Choose the skeleton project option for a minimal setup.
Install Supabase Client
Install the Supabase JavaScript client:
npm install @supabase/supabase-js
Configure Supabase
Create a .env
file in your project root and add your Supabase URL and API key:
VITE_SUPABASE_URL="YOUR_SUPABASE_URL"
VITE_SUPABASE_ANON_KEY="YOUR_SUPABASE_ANON_KEY"
Replace YOUR_SUPABASE_URL
and YOUR_SUPABASE_ANON_KEY
with your actual Supabase credentials. You can find these in your Supabase project settings.
Initialize the Supabase client in src/lib/supabaseClient.js
:
// src/lib/supabaseClient.js
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
Implement Authentication
Let's create a simple login form. Create src/routes/login/+page.svelte
:
// src/routes/login/+page.svelte
<script>
import { supabase } from '$lib/supabaseClient';
import { goto } from '$app/navigation';
import { auth } from '$lib/stores';
let email = '';
let password = '';
let loading = false;
async function handleLogin() {
loading = true;
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
alert(error.message);
} else {
$auth = data.user;
goto('/');
}
loading = false;
}
</script>
<svelte:head>
<title>Login</title>
</svelte:head>
<h1>Login</h1>
<input type="email" bind:value={email} placeholder="Email" />
<input type="password" bind:value={password} placeholder="Password" />
<button on:click={handleLogin} disabled={loading}>
{#if loading}
Logging in...
{:else}
Login
{/if}
</button>
Create a similar src/routes/register/+page.svelte
component for user registration, using supabase.auth.signUp
.
// src/routes/register/+page.svelte
<script>
import { supabase } from '$lib/supabaseClient';
import { goto } from '$app/navigation';
let email = '';
let password = '';
let loading = false;
async function handleRegister() {
loading = true;
const { data, error } = await supabase.auth.signUp({
email,
password,
});
if (error) {
alert(error.message);
} else {
// Optionally, send a confirmation email
goto('/login'); // Redirect to login after registration
}
loading = false;
}
</script>
<svelte:head>
<title>Register</title>
</svelte:head>
<h1>Register</h1>
<input type="email" bind:value={email} placeholder="Email" />
<input type="password" bind:value={password} placeholder="Password" />
<button on:click={handleRegister} disabled={loading}>
{#if loading}
Registering...
{:else}
Register
{/if}
</button>
Create an Auth store in src/lib/stores.js
:
// src/lib/stores.js
import { writable } from 'svelte/store';
export const auth = writable(null);
Protect Routes
Create a root +layout.js
file in the src/routes
directory to implement route protection:
// src/routes/+layout.js
import { supabase } from '$lib/supabaseClient';
import { auth } from '$lib/stores';
import { redirect } from '@sveltejs/kit';
export const load = async ({ url }) => {
supabase.auth.getSession().then(({ data: { session } }) => {
auth.set(session?.user ?? null)
})
const { data: { user } } = await supabase.auth.getUser();
if (user == null && url.pathname !== '/login' && url.pathname !== '/register') {
throw redirect(302, '/login');
}
return {
supabase,
url: url.origin,
};
};
Create a home page src/routes/+page.svelte
:
<script>
import { supabase } from '$lib/supabaseClient';
import { auth } from '$lib/stores';
import { goto } from '$app/navigation';
async function handleLogout() {
const { error } = await supabase.auth.signOut()
if(!error) {
$auth = null;
goto('/login');
}
}
</script>
{#if $auth}
<h1>Welcome, {$auth.email}!</h1>
<button on:click={handleLogout}>Logout</button>
{:else}
<p>You are not logged in.</p>
<a href="/login">Login</a> | <a href="/register">Register</a>
{/if}
Conclusion
This article provided a quick start to building a fullstack SvelteKit application with Supabase authentication. You can expand upon this foundation by adding database interactions, storage, and more complex UI elements. Remember to handle errors gracefully and implement proper security measures in a production environment.