Skip to main content
Svelte Fundamentals
CHAPTER 20 Beginner

Authentication and Authorization

Updated: May 18, 2026
5 min read

# CHAPTER 20

Authentication and Authorization

1. Chapter Introduction

Authentication (verifying who you are) and authorization (what you can access) are fundamental to any production application. This chapter builds a complete JWT-based auth system in Svelte, using auth stores for state management and route guards for protection.

2. Learning Objectives

  • Build an AuthStore for reactive auth state.
  • Implement login and logout with JWT.
  • Protect routes using auth checks.
  • Implement role-based access.
  • Build a Login Application.

3. Auth Store (Complete)

javascript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
// src/lib/stores/authStore.js
import { writable, derived } from 'svelte/store';

const TOKEN_KEY = 'auth_token';
const USER_KEY = 'auth_user';

function createAuth() {
  const storedToken = typeof localStorage !== 'undefined' ? localStorage.getItem(TOKEN_KEY) : null;
  const storedUser = typeof localStorage !== 'undefined' ? JSON.parse(localStorage.getItem(USER_KEY) || 'null') : null;

  const { subscribe, set, update } = writable({
    user: storedUser,
    token: storedToken,
    loading: false,
    error: null
  });

  return {
    subscribe,
    login: async (email, password) => {
      update(s => ({ ...s, loading: true, error: null }));
      try {
        const res = await fetch('/api/auth/login', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ email, password })
        });
        if (!res.ok) throw new Error('Invalid credentials');
        const { user, token } = await res.json();
        localStorage.setItem(TOKEN_KEY, token);
        localStorage.setItem(USER_KEY, JSON.stringify(user));
        set({ user, token, loading: false, error: null });
        return true;
      } catch (err) {
        update(s => ({ ...s, loading: false, error: err.message }));
        return false;
      }
    },
    logout: () => {
      localStorage.removeItem(TOKEN_KEY);
      localStorage.removeItem(USER_KEY);
      set({ user: null, token: null, loading: false, error: null });
    },
    clearError: () => update(s => ({ ...s, error: null }))
  };
}

export const auth = createAuth();
export const isLoggedIn = derived(auth, $auth => !!$auth.token);
export const currentUser = derived(auth, $auth => $auth.user);
export const authToken = derived(auth, $auth => $auth.token);

4. Login Page

svelte
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
<!-- routes/login/+page.svelte (SvelteKit) or Login.svelte -->
<script>
  import { auth, isLoggedIn } from &#039;$lib/stores/authStore.js';
  import { goto } from &#039;$app/navigation';
  import { onMount } from &#039;svelte';

  let email = &#039;';
  let password = &#039;';
  let loading = false;

  onMount(() => {
    if ($isLoggedIn) goto(&#039;/dashboard');
  });

  async function handleLogin() {
    const success = await auth.login(email, password);
    if (success) goto(&#039;/dashboard');
  }
</script>

<div class="login-page">
  <div class="login-card">
    <h1>Welcome Back</h1>
    <p>Sign in to your account</p>

    <form on:submit|preventDefault={handleLogin}>
      <div class="field">
        <label>Email</label>
        <input type="email" bind:value={email} placeholder="you@example.com" required />
      </div>

      <div class="field">
        <label>Password</label>
        <input type="password" bind:value={password} placeholder="••••••••" required />
      </div>

      {#if $auth.error}
        <div class="error-banner">❌ {$auth.error}</div>
      {/if}

      <button type="submit" disabled={$auth.loading}>
        {$auth.loading ? &#039;Signing in...' : 'Sign In'}
      </button>
    </form>
  </div>
</div>

5. Protected Route Component

svelte
12345678910111213141516171819
<!-- ProtectedRoute.svelte -->
<script>
  import { isLoggedIn, currentUser } from &#039;$lib/stores/authStore.js';
  import { goto } from &#039;$app/navigation';
  import { onMount } from &#039;svelte';

  export let requiredRole = null;

  onMount(() => {
    if (!$isLoggedIn) goto(&#039;/login');
    else if (requiredRole && $currentUser?.role !== requiredRole) goto(&#039;/unauthorized');
  });
</script>

{#if $isLoggedIn && (!requiredRole || $currentUser?.role === requiredRole)}
  <slot />
{:else}
  <div class="loading">Checking authorization...</div>
{/if}
svelte
1234567891011
<!-- Usage in a page -->
<script>
  import ProtectedRoute from &#039;$lib/ProtectedRoute.svelte';
</script>

<ProtectedRoute requiredRole="admin">
  <div class="admin-panel">
    <h1>Admin Dashboard</h1>
    <!-- Only admins see this -->
  </div>
</ProtectedRoute>

6. HTTP Interceptor (Auto Token)

javascript
12345678910111213141516171819202122232425
// src/lib/services/api.js
import { get } from &#039;svelte/store&#039;;
import { authToken, auth } from &#039;$lib/stores/authStore.js&#039;;

export async function apiRequest(url, options = {}) {
  const token = get(authToken);

  const response = await fetch(url, {
    ...options,
    headers: {
      &#039;Content-Type&#039;: &#039;application/json&#039;,
      ...(token && { Authorization: `Bearer ${token}` }),
      ...options.headers
    }
  });

  if (response.status === 401) {
    auth.logout();
    window.location.href = &#039;/login&#039;;
    return;
  }

  if (!response.ok) throw new Error(`API Error: ${response.status}`);
  return response.json();
}

7. MCQs

Question 1

Where should JWT tokens be stored in a Svelte app?

Question 2

What makes the auth store reactive across components?

Question 3

How do you read a store's current value outside a Svelte component (in a JS file)?

Question 4

What is the correct way to include JWT in API requests?

Question 5

What HTTP status indicates an expired/invalid JWT?

Question 6

How do you redirect to login after failed auth check in SvelteKit?

Question 7

What is role-based access control (RBAC)?

Question 8

When should you check auth redirect in onMount vs at load time?

Question 9

What derived store is useful for checking login status?

Question 10

How do you initialize auth state from localStorage on app load?

8. Interview Questions

  • Q: Walk through a complete JWT authentication flow in Svelte from login to API request.
  • Q: How do you handle token expiration gracefully?

9. Summary

Svelte auth with a custom store factory provides a clean, reactive, and maintainable solution. The auth store centralizes all authentication logic, derived stores provide convenient reactive getters, and the ProtectedRoute component declaratively guards any page or feature.

10. Next Chapter Recommendation

In Chapter 21: Svelte with Firebase, we integrate Svelte with Google's Firebase platform for serverless authentication, Firestore database, and cloud hosting.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·