How do you handle authentication in Svelte

How do you handle authentication in Svelte

Authentication is a crucial aspect of modern web applications, ensuring that users can securely log in, access their data, and perform actions based on their permissions. Svelte, a modern framework for building user interfaces, provides several ways to handle authentication effectively. In this article, we’ll explore various strategies and best practices for implementing authentication in Svelte applications.

Introduction to Authentication in Svelte

Svelte does not come with built-in authentication mechanisms, which provides flexibility to choose from different strategies and libraries. Common approaches to authentication in Svelte include using JWT (JSON Web Tokens), OAuth, and traditional session-based authentication.

Setting Up a Svelte Project

Before diving into authentication, let’s set up a basic Svelte project.

  1. Create a new Svelte project using the template:

    npx degit sveltejs/template svelte-auth
    cd svelte-auth
    npm install
    
  2. Start the development server:

    npm run dev
    

JWT Authentication

JWT (JSON Web Token) is a popular method for handling authentication in web applications. It involves issuing a token upon successful login, which the client stores and sends with each request to authenticate the user.

Backend Setup

First, we need a backend to issue and validate JWTs. Here’s an example using Node.js with Express and the jsonwebtoken library.

  1. Initialize a new Node.js project:

    mkdir backend
    cd backend
    npm init -y
    npm install express jsonwebtoken body-parser
    
  2. Create an Express server to handle authentication:

    // backend/server.js
    const express = require('express');
    const jwt = require('jsonwebtoken');
    const bodyParser = require('body-parser');
    
    const app = express();
    const PORT = 4000;
    const SECRET_KEY = 'your_secret_key';
    
    app.use(bodyParser.json());
    
    app.post('/login', (req, res) => {
      const { username, password } = req.body;
      // Replace with real user validation
      if (username === 'user' && password === 'pass') {
        const token = jwt.sign({ username }, SECRET_KEY, { expiresIn: '1h' });
        res.json({ token });
      } else {
        res.status(401).json({ error: 'Invalid credentials' });
      }
    });
    
    app.get('/protected', (req, res) => {
      const token = req.headers['authorization'];
      if (token) {
        jwt.verify(token, SECRET_KEY, (err, decoded) => {
          if (err) {
            res.status(401).json({ error: 'Invalid token' });
          } else {
            res.json({ message: 'Protected data', user: decoded });
          }
        });
      } else {
        res.status(401).json({ error: 'No token provided' });
      }
    });
    
    app.listen(PORT, () => {
      console.log(`Server running on http://localhost:${PORT}`);
    });
    
  3. Start the backend server:

    node server.js
    

Frontend Setup

Next, we’ll integrate JWT authentication into our Svelte frontend.

  1. Install necessary dependencies:

    npm install axios
    
  2. Create a login component:

    <!-- src/Login.svelte -->
    <script>
      import { writable } from 'svelte/store';
      import axios from 'axios';
    
      const token = writable('');
    
      let username = '';
      let password = '';
      let error = '';
    
      async function login() {
        try {
          const response = await axios.post('http://localhost:4000/login', { username, password });
          token.set(response.data.token);
          error = '';
        } catch (err) {
          error = 'Invalid credentials';
        }
      }
    </script>
    
    <input type="text" bind:value={username} placeholder="Username" />
    <input type="password" bind:value={password} placeholder="Password" />
    <button on:click={login}>Login</button>
    {#if error}
      <p>{error}</p>
    {/if}
    
  3. Create a protected component:

    <!-- src/Protected.svelte -->
    <script>
      import { token } from './Login.svelte';
      import { onMount } from 'svelte';
      import axios from 'axios';
    
      let protectedData = '';
      let error = '';
    
      onMount(async () => {
        try {
          const response = await axios.get('http://localhost:4000/protected', {
            headers: {
              'Authorization': $token
            }
          });
          protectedData = response.data.message;
          error = '';
        } catch (err) {
          error = 'Access denied';
        }
      });
    </script>
    
    <div>
      {#if error}
        <p>{error}</p>
      {:else}
        <p>{protectedData}</p>
      {/if}
    </div>
    
  4. Update the main component to include login and protected routes:

    <!-- src/App.svelte -->
    <script>
      import Login from './Login.svelte';
      import Protected from './Protected.svelte';
    </script>
    
    <main>
      <h1>Svelte JWT Authentication</h1>
      <Login />
      <Protected />
    </main>
    

OAuth Authentication

OAuth is another popular authentication method, often used for allowing users to log in using third-party services like Google, Facebook, or GitHub. Here’s how you can implement OAuth in a Svelte application using Auth0 as an example.

Setting Up Auth0

  1. Sign up for an Auth0 account and create a new application.
  2. Configure the application settings to include the allowed callback URL (e.g., http://localhost:5000/callback).

Frontend Setup

  1. Install the Auth0 SDK:

    npm install @auth0/auth0-spa-js
    
  2. Create an Auth service:

    // src/auth.js
    import createAuth0Client from '@auth0/auth0-spa-js';
    import { writable } from 'svelte/store';
    
    export const isAuthenticated = writable(false);
    export const user = writable({});
    export const popupOpen = writable(false);
    export const error = writable();
    
    let auth0Client;
    
    async function createClient() {
      auth0Client = await createAuth0Client({
        domain: 'YOUR_AUTH0_DOMAIN',
        client_id: 'YOUR_AUTH0_CLIENT_ID'
      });
    }
    
    async function login() {
      await auth0Client.loginWithPopup();
      user.set(await auth0Client.getUser());
      isAuthenticated.set(true);
    }
    
    async function logout() {
      auth0Client.logout({
        returnTo: window.location.origin
      });
      user.set({});
      isAuthenticated.set(false);
    }
    
    async function handleRedirectCallback() {
      await auth0Client.handleRedirectCallback();
      user.set(await auth0Client.getUser());
      isAuthenticated.set(true);
    }
    
    createClient();
    
    export { login, logout, handleRedirectCallback };
    
  3. Create login and logout buttons:

    <!-- src/LoginButton.svelte -->
    <script>
      import { login } from './auth';
    
      export let label = 'Login';
    
      function handleClick() {
        login();
      }
    </script>
    
    <button on:click={handleClick}>{label}</button>
    
    <!-- src/LogoutButton.svelte -->
    <script>
      import { logout } from './auth';
    
      export let label = 'Logout';
    
      function handleClick() {
        logout();
      }
    </script>
    
    <button on:click={handleClick}>{label}</button>
    
  4. Display user information:

    <!-- src/UserProfile.svelte -->
    <script>
      import { user, isAuthenticated } from './auth';
      import { $user, $isAuthenticated } from 'svelte/store';
    
      let profile;
      let loggedIn;
    
      $: profile = $user;
      $: loggedIn = $isAuthenticated;
    </script>
    
    {#if loggedIn}
      <div>
        <p>Welcome, {profile.name}!</p>
        <img src={profile.picture} alt={profile.name} />
      </div>
    {:else}
      <p>Please log in.</p>
    {/if}
    
  5. Handle Auth0 redirects:

    <!-- src/App.svelte -->
    <script>
      import { onMount } from 'svelte';
      import { handleRedirectCallback } from './auth';
      import LoginButton from './LoginButton.svelte';
      import LogoutButton from './LogoutButton.svelte';
      import UserProfile from './UserProfile.svelte';
    
      onMount(async () => {
        if (window.location.search.includes('code=') && window.location.search.includes('state=')) {
          await handleRedirectCallback();
          window.history.replaceState({}, document.title, window.location.pathname);
        }
      });
    </script>
    
    <main>
      <h1>Svelte OAuth Authentication</h1>
      <LoginButton />
      <LogoutButton />
      <UserProfile />
    </main>
    

Session-Based Authentication

For traditional session-based authentication, you can use cookies to manage sessions. Here’s an example using Express sessions on the backend.

Backend Setup

  1. Install necessary dependencies:

    npm install express-session connect-sqlite3
    
  2. Create an Express server with session handling:

    // backend/server.js
    const express = require('express');
    const session = require('express-session');
    const SQLiteStore = require('connect-sqlite3')(session);
    const bodyParser = require('body-parser');
    
    const app = express();
    const PORT = 4000;
    
    app.use(bodyParser.json());
    app.use(session({
      store: new SQLiteStore,
      secret: 'your_secret_key',
      resave: false,
      saveUninitialized: false,
      cookie: { secure: false } // Set to true if using HTTPS
    }));
    
    app.post('/login', (req, res) => {
      const { username, password } = req.body;
      // Replace with real user validation
      if (username === 'user' && password === 'pass') {
        req.session.user = { username };
        res.json({ message: 'Logged in' });
      } else {
        res.status(401).json({ error: 'Invalid credentials' });
      }
    });
    
    app.get('/protected', (req, res) => {
      if (req.session.user) {
        res.json({ message: 'Protected data', user: req.session.user });
      } else {
        res.status(401).json({ error: 'Unauthorized' });
      }
    });
    
    app.listen(PORT, () => {
      console.log(`Server running on http://localhost:${PORT}`);
    });
    

Frontend Setup

  1. Install Axios:

    npm install axios
    
  2. Create a login component:

    <!-- src/Login.svelte -->
    <script>
      import { writable } from 'svelte/store';
      import axios from 'axios';
    
      let username = '';
      let password = '';
      let error = '';
    
      async function login() {
        try {
          const response = await axios.post('http://localhost:4000/login', { username, password }, { withCredentials: true });
          error = response.data.message;
        } catch (err) {
          error = 'Invalid credentials';
        }
      }
    </script>
    
    <input type="text" bind:value={username} placeholder="Username" />
    <input type="password" bind:value={password} placeholder="Password" />
    <button on:click={login}>Login</button>
    {#if error}
      <p>{error}</p>
    {/if}
    
  3. Create a protected component:

    <!-- src/Protected.svelte -->
    <script>
      import { onMount } from 'svelte';
      import axios from 'axios';
    
      let protectedData = '';
      let error = '';
    
      onMount(async () => {
        try {
          const response = await axios.get('http://localhost:4000/protected', { withCredentials: true });
          protectedData = response.data.message;
          error = '';
        } catch (err) {
          error = 'Access denied';
        }
      });
    </script>
    
    <div>
      {#if error}
        <p>{error}</p>
      {:else}
        <p>{protectedData}</p>
      {/if}
    </div>
    
  4. Update the main component to include login and protected routes:

    <!-- src/App.svelte -->
    <script>
      import Login from './Login.svelte';
      import Protected from './Protected.svelte';
    </script>
    
    <main>
      <h1>Svelte Session-Based Authentication</h1>
      <Login />
      <Protected />
    </main>
    

Conclusion

Handling authentication in Svelte can be approached in various ways, including JWT, OAuth, and traditional session-based methods. Each method has its own benefits and use cases:

  • JWT: Suitable for stateless authentication, often used in SPAs and mobile applications.
  • OAuth: Ideal for integrating third-party authentication providers like Google or GitHub.
  • Session-Based: Traditional method using server-side sessions and cookies, suitable for applications requiring server-side state management.

By following the examples and best practices outlined in this article, you can implement robust and secure authentication mechanisms in your Svelte applications, enhancing both security and user experience.

How do you handle authentication in a React-Redux application

How does React handle dynamic imports

How do you handle code splitting with React Router

Explain the concept of lazy loading in React

What is the significance of the forwardRef function in React

What is the significance of the react-router-dom library

How do you implement server-side rendering with React and Node.js

How do you implement server-side rendering with React and Express