Logo

dev-resources.site

for different kinds of informations.

Simplifying Client-Side Authentication with Firebase and SvelteKit

Published at
11/12/2023
Categories
programming
firebase
auth
Author
erayg
Categories
3 categories in total
programming
open
firebase
open
auth
open
Author
5 person written this
erayg
open
Simplifying Client-Side Authentication with Firebase and SvelteKit

banner

Authentication tasks can often be a complex and challenging aspect of web development. If you've never worked with Firebase before, you're in luck. In this article, I've created a sample repository that's not just for learning purposes but can also be used in a production environment. We'll explore how to use Firebase Authentication seamlessly with SvelteKit and TypeScript, making the authentication process smoother and more efficient.

Firebase Authentication provides backend services, easy-to-use SDKs, and ready-made UI libraries to authenticate users to your app. It supports authentication using passwords, phone numbers, popular federated identity providers like Google, Facebook and Twitter, and more.

Understanding Firebase Authentication

Before diving into the implementation details, let's briefly discuss what Firebase Authentication offers. Firebase Authentication is a robust backend service that provides developers with user authentication capabilities. It offers an easy-to-use SDK and pre-built UI libraries that allow you to authenticate users to your web application effortlessly. Firebase supports a wide range of authentication methods, including email/password, phone numbers, and federated identity providers like Google, Facebook, and Twitter.

Creating a SvelteKit project

To begin, we'll set up a new SvelteKit project. If you're new to SvelteKit, you can quickly create a project using the following commands:

npm create svelte@latest my-app
cd myapp
Enter fullscreen mode Exit fullscreen mode

Install FirebaseĀ Emulator

Next, we'll integrate Firebase into our SvelteKit project. Firebase provides a suite of services, and for this article, we're focusing on Firebase Authentication. But before we proceed, we'll set up Firebase Emulators for local development. Firebase Emulators allow us to test authentication locally, ensuring smooth development.
To set up Firebase Emulators, you need to install the Firebase CLI and initialize your Firebase project:Local development with Local Emulator Suite can be a good fit for your evaluation, prototyping, development and continuous integration workflows.

Installing FirebaseĀ CLI

npm install -g firebase-tools
Enter fullscreen mode Exit fullscreen mode

Or you can download CLI manually.

After installing Firebase CLI, you need to login to your Google account.

firebase login

Enter fullscreen mode Exit fullscreen mode

Then, you need to initialize Firebase project in your project directory.

firebase init

Enter fullscreen mode Exit fullscreen mode

During the initialization process, choose Firebase Emulators, and select the Firebase project you want to use. Also, make sure to select the Authentication emulator.
After installation we will be ready to use Firebase Auth Emulator.

Install Firebase

In your project folder run the following command.

npm install firebase

Enter fullscreen mode Exit fullscreen mode

After the installation, create a firebase.client.ts file in src/lib folder.

import { initializeApp } from 'firebase/app';
import { connectAuthEmulator, getAuth } from 'firebase/auth';
import type { FirebaseApp } from 'firebase/app';
import type { Firestore } from 'firebase/firestore';
import type { Auth } from 'firebase/auth';
import { browser } from '$app/environment';

export let db: Firestore;
export let app: FirebaseApp;
export let auth: Auth;

const firebaseConfig = {
 apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
 appId: import.meta.env.VITE_FIREBASE_APP_ID,
 useEmulator: import.meta.env.VITE_FIREBASE_USE_EMULATOR === 'true',
 authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN
};

export const initializeFirebase = () => {
 if (!browser) {
  throw new Error("Can't use the Firebase client on the server.");
 }
 if (!app) {
  app = initializeApp(firebaseConfig);
  auth = getAuth(app);

  if (firebaseConfig.useEmulator) {
   connectAuthEmulator(auth, 'http://127.0.0.1:9099');
  }
 }
};

Enter fullscreen mode Exit fullscreen mode

This is our base code to initialize Firebase for our project. All the config variables we are going to need will be inĀ .env file.

VITE_FIREBASE_API_KEY=API_KEY_HERE
VITE_FIREBASE_APP_ID=APP_ID_HERE
VITE_FIREBASE_USE_EMULATOR=true # true in development, false in production
VITE_FIREBASE_AUTH_DOMAIN=AUTH_DOMAIN_HERE
Enter fullscreen mode Exit fullscreen mode

Now to invoke this initializeFirebase function in our project, let's create a +layout.ts file in src/routes and add our load function that we are going to use on +layout.svelte page.

/** @type {import('./$types').LayoutLoad} */

import { initializeFirebase, auth } from '$lib/firebase.client';
import { browser } from '$app/environment';
import { onAuthStateChanged } from 'firebase/auth';

export async function load({ url }) {
 if (browser) {
  try {
   initializeFirebase();
  } catch (ex) {
   console.error(ex);
  }
 }

 function getAuthUser() {
  return new Promise((resolve) => {
   onAuthStateChanged(auth, (user) => resolve(user ? user : false));
  });
 }

 return {
  getAuthUser: getAuthUser,
  url: url.pathname
 };
}
Enter fullscreen mode Exit fullscreen mode

Now our load function will get auth user on auth state changed. If user is not logged in, it will return false on mount.

Creating theĀ State

To manage the authentication state in your SvelteKit app, we'll create a session.ts file in the src/lib folder. This file will define the session state and export a session store.

import { writable, type Writable } from 'svelte/store';

type User = {
 email?: string | null;
 displayName?: string | null;
 photoURL?: string | null;
 uid?: string | null;
};

export type SessionState = {
 user: User | null;
 loading?: boolean;
 loggedIn?: boolean;
};

export const session = <Writable<SessionState>>writable();
Enter fullscreen mode Exit fullscreen mode

Using LayoutĀ page

Now to use our load function, let's create +layout.svelte page

<script lang="ts">
 import { onMount } from 'svelte';
 import { session } from '$lib/session';
 import { goto } from '$app/navigation';
 import { signOut } from 'firebase/auth';
 import { auth } from '$lib/firebase.client';

 import type { LayoutData } from './$types';
 export let data: LayoutData;

 let loading: boolean = true;
 let loggedIn: boolean = false;

 session.subscribe((cur: any) => {
  loading = cur?.loading;
  loggedIn = cur?.loggedIn;
 });

 onMount(async () => {
  const user: any = await data.getAuthUser();

  const loggedIn = !!user && user?.emailVerified;
  session.update((cur: any) => {
   loading = false;
   return {
    ...cur,
    user,
    loggedIn,
    loading: false
   };
  });

  if (loggedIn) {
   goto('/');
  }
 });

</script>
<!-- +layout.svelte -->

{#if loading}
 <div>Loading...</div>
{:else}
  <div>
   Logged in: {loggedIn}
   <slot />
  </div>
{/if}
Enter fullscreen mode Exit fullscreen mode

Building a LoginĀ Page

We'll start by creating a basic login form. In your Svelte page, you can create the login form and handle authentication actions.

<!-- login/+page.svelte -->

<div class="login-form">
 <h1>Login</h1>
 <form on:submit={loginWithMail}>
  <input bind:value={email} type="text" placeholder="Email" />
  <input bind:value={password} type="password" placeholder="Password" />
  <button type="submit">Login</button>
 </form>

 <div>or</div>

 <button on:click={loginWithGoogle}>Login with Google</button>
 <div>Don't you have an account? <a href="/register"> Register</a></div>
</div>
Enter fullscreen mode Exit fullscreen mode

In the script part of our Svelte page, we are going to add our functionality.

<script lang="ts">
// login/+page.svelte
 import { session } from '$lib/session';
 import { auth } from '$lib/firebase.client';
 import {
  GoogleAuthProvider,
  signInWithPopup,
  signInWithEmailAndPassword,
  type UserCredential
 } from 'firebase/auth';
 import { goto } from '$app/navigation';

 let email: string = '';
 let password: string = '';

 async function loginWithMail() {
  await signInWithEmailAndPassword(auth, email, password)
   .then((result) => {
    const { user }: UserCredential = result;
    session.set({
     loggedIn: true,
     user: {
      displayName: user?.displayName,
      email: user?.email,
      photoURL: user?.photoURL,
      uid: user?.uid
     }
    });
    goto('/');
   })
   .catch((error) => {
    return error;
   });
 }

 async function loginWithGoogle() {
  const provider = new GoogleAuthProvider();
  await signInWithPopup(auth, provider)
   .then((result) => {
    const { displayName, email, photoURL, uid } = result?.user;
    session.set({
     loggedIn: true,
     user: {
      displayName,
      email,
      photoURL,
      uid
     }
    });

    goto('/');
   })
   .catch((error) => {
    return error;
   });
 }
</script>
Enter fullscreen mode Exit fullscreen mode

Building a RegisterĀ Page

<script lang="ts">
 // register/+page.svelte
 import { auth } from '$lib/firebase.client';
 import { createUserWithEmailAndPassword } from 'firebase/auth';
 import { goto } from '$app/navigation';
 import { session } from '$lib/session';

 let email: string = '';
 let password: string = '';

 async function handleRegister() {
  await createUserWithEmailAndPassword(auth, email, password)
   .then((result) => {
    const { user } = result;
    session.update((cur: any) => {
     return {
      ...cur,
      user,
      loggedIn: true,
      loading: false
     };
    });
    goto('/');
   })
   .catch((error) => {
    throw new Error(error);
   });
 }
</script>
Enter fullscreen mode Exit fullscreen mode
<!-- register/+page.svelte -->
<div class="register-form">
 <form on:submit={handleRegister}>
  <h2>Register</h2>
  <input bind:value={email} type="text" placeholder="Email" />
  <input bind:value={password} type="password" placeholder="Password" />
  <button type="submit">Register</button>
 </form>
</div>
Enter fullscreen mode Exit fullscreen mode

In this article, we've walked through the process of integrating Firebase Authentication with a SvelteKit application. We've covered setting up Firebase Emulators for local development, initializing Firebase in your project, managing authentication state, and implementing login and registration features. This combination of Firebase and SvelteKit offers a powerful and streamlined solution for client-side authentication.

As you continue to work on your project, you can build upon these foundations and explore additional Firebase features to enhance the user experience and security of your web application.

By following these steps, you can simplify client-side authentication and create a secure and user-friendly web application using Firebase and SvelteKit.

GitHub Repository: SvelteKit Firebase Authentication Example

In this example project, you'll see how all the pieces come together. You can examine the project structure, review the implementation of authentication features, and use it as a reference for your own projects.
Here are some key points about the example project:
It showcases the integration of Firebase Authentication with SvelteKit, just as we discussed in this article.
You can explore how Firebase Emulators are set up for local development.
The project includes login and registration pages with email/password and Google authentication methods.
The management of authentication state using Svelte's stores is also demonstrated.
Feel free to clone, fork, or download the project for your own use. It's a practical resource to accelerate your development when working on projects that require user authentication.

By examining the example project alongside this article, you'll gain a more comprehensive understanding of how to implement Firebase Authentication with SvelteKit effectively.

Happy coding!

About me
As a frontend engineer with a passion for open-source work, I take pride in my ability to deliver high-quality results to clients. My experience and expertise have equipped me with the skills needed to develop innovative solutions that exceed expectations. As an active member of the tech community, I value the importance of open communication, continuous learning, and collaboration. If you're interested in learning more about my work or how I can contribute to your project, feel free to connect with me.

auth Article's
30 articles in total
Favicon
Wait, are we just handing over system access to the AI agents?
Favicon
Implementing Auth in .NET WebApi & SPAs: Why is it still so painful?
Favicon
Secure Your Nuxt 3 App
Favicon
Managing Auth State in react using useContext API
Favicon
How to Authenticate Users Codeigniter Shield
Favicon
How to decode a JWT
Favicon
Laravel 11 API Rest Auth with jwt-auth
Favicon
Announcement - Keycloak.AuthServices v2.0.0 is out šŸŽ‰!
Favicon
Generate magic tokens in Rails with generates_token_for
Favicon
Your organization has enabled or enforced SAML SSO ... you must re-authorize the OAuth Application `GitHub for VS Code`
Favicon
JWT Revokation
Favicon
Recent Security Vulnerability Detected in Clerk - Should You Roll Your Own Auth?
Favicon
User Management Unveiled: An Architectural Overview
Favicon
Compressing and Decompressing User Permissions with JavaScript
Favicon
Clerk Webhooks: Data Sync with Convex
Favicon
Simplifying Client-Side Authentication with Firebase and SvelteKit
Favicon
I Just Want Authentication To Work
Favicon
Setup User Auth for your Reflex app using local_auth
Favicon
How to Implement Passkey Authentication and Fine-Grained Authorization in JavaScript
Favicon
Authentication Workflows Overview
Favicon
Securing MQTT: A Guide to Basic Authentication
Favicon
Shopify Passkey Implementation Analyzed
Favicon
Apa itu Autentikasi: Definisi dan Jenis-jenis Autentikasi
Favicon
Best Practices for Authorization in Microservices
Favicon
Granular Permission Management with CASL Library
Favicon
Multi Auth System in Laravel Breeze #1
Favicon
Simplifying Authentication Integration For Developers With Authgear SDKs
Favicon
API Authentication Methods - Pros and Cons
Favicon
Authentication vs. Authorization
Favicon
Twitter API suspended? Here's how to fix it

Featured ones: