Svelte – Login and Authentication with Supabase

Posted on



Svelte Authentication

Modern frontend application needs some way to verify the user. Creating an account for users in our application will let us engage with the users and provide some personalized experience for the users. There are multiple ways to achieve this and for today we will look at how to get this working with Svelte and Supabase



What are we building?

AuthComponent.PNG



Supabase Introduction

Supabase is an open-source project which claims to be a Firebase alternative. It provides most of the backend services you would need to build an application. It provides a Postgress database, Authentication, Storage options, and more.

Getting started with Supabase seems to be very easy as you can log in with your Github account and create a project in a few minutes



Creating Svelte Project

Starting off, let’s create the svelte project using the command from the official svelte site

https://svelte.dev/

npx degit sveltejs/template svelte-login-supabase
cd svelte-login-supabase
Enter fullscreen mode

Exit fullscreen mode

Supabase provides a javascript client package to help with the connection to the Supabase project. We can install it using the npm install command

npm install @supabase/supabase-js
Enter fullscreen mode

Exit fullscreen mode

More info about the package can be found in this link – https://github.com/supabase/supabase-js



Setting up Supabase

Create a new project or open an existing project. Supabase will configure a Postgress database for us and we can start writing SQL statements in the database to create the tables.

We will need a profile table for the user’s profile

create table profiles (
  id uuid references auth.users not null,
  updated_at timestamp with time zone,
  username text unique,
  display_name text,
  bio text,
  twitter_link text,

  primary key (id),
  unique(username),
  constraint username_length check (char_length(username) >= 3)
);

alter table profiles enable row level security;

create policy "User profile can be read by everyone."
  on profiles for select
  using ( true );

create policy "Users can create their own profile."
  on profiles for insert
  with check ( auth.uid() = id );

create policy "Users can update own profile."
  on profiles for update
  using ( auth.uid() = id );
Enter fullscreen mode

Exit fullscreen mode

We can write the SQL query to create table profiles using the above statements

Create table profiles

  • id – Used to store the unique user id. This is linked with the authentication id of the user
  • updated_at – Timestamp of the time when the profile is updated
  • username – Unique username for the user
  • display_name – Display name for the user in the application
  • bio – Description for the user
  • twitter_link – Link to add for the user’s twitter profile

We can add more constraints for the columns when creating the table.

  1. Username should be unique – unique(username)
  2. Username length constraint greater than 3 – constraint username_length check (char_length(username) >= 3)



Row Level Security

Postgres offers Row Level Security which will help in making sure that users with proper authorization will make changes to the database. This offers one more level of security on top of the authenticated user.

In our scenario, we are having this table to update our user’s details. It should be visible to all the users. So read permission should be given for all

alter table profiles enable row level security;

create policy "User profile can be read by everyone."
  on profiles for select
  using ( true );
Enter fullscreen mode

Exit fullscreen mode

Authenticated users can only create/update their profiles. So we can have a policy checking if the updating user is same as the authenticated user

create policy "Users can create their own profile."
  on profiles for insert
  with check ( auth.uid() = id );

create policy "Users can update own profile."
  on profiles for update
  using ( auth.uid() = id );
Enter fullscreen mode

Exit fullscreen mode

https://www.postgresql.org/docs/current/ddl-rowsecurity.html



Setting up the environment in Svelte

Create a .env file in your root directory and we can add the Supabase environment variable there.

  1. URL of the Supabase Application
  2. Anonymous key for the application

Variables can be found when you navigate to Setting → API

SVELTE_APP_SUPABASE_URL – URL of the Supabase app found under Config

SVELTE_APP_SUPABASE_ANON_KEY – Public Anonymous key for the project

SVELTE_APP_SUPABASE_ANON_KEY – This key will be exposed in your application. This key is safe to use as long as you have proper Row Level Security turned on in your tables.

.env

SVELTE_APP_SUPABASE_URL=YOUR_URL
SVELTE_APP_SUPABASE_ANON_KEY=YOUR_KEY
Enter fullscreen mode

Exit fullscreen mode



Update config to reflect the environment variables

Supabase package which we installed earlier using .json file and so we need to update the rollup config to convert the .json file to ES6 format. We can use a plugin to do this work for us.

npm install --save-dev @rollup/plugin-json
Enter fullscreen mode

Exit fullscreen mode

We also need more plugins to take the variable from the .env file and use them in the rollup config file.

npm install --save-dev dotenv @rollup/plugin-replace
Enter fullscreen mode

Exit fullscreen mode

All of these dependencies are dev dependencies and so they won’t increase the size of your final build.

Let’s update the rollup.config file to below so as to use both the plugins which we have installed

import svelte from 'rollup-plugin-svelte';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import css from 'rollup-plugin-css-only';

import { config } from 'dotenv';
import replace from '@rollup/plugin-replace';
import json from '@rollup/plugin-json'
const production = !process.env.ROLLUP_WATCH;

function serve() {
    let server;

    function toExit() {
        if (server) server.kill(0);
    }

    return {
        writeBundle() {
            if (server) return;
            server = require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
                stdio: ['ignore', 'inherit', 'inherit'],
                shell: true
            });

            process.on('SIGTERM', toExit);
            process.on('exit', toExit);
        }
    };
}

export default {
    input: 'src/main.js',
    output: {
        sourcemap: true,
        format: 'iife',
        name: 'app',
        file: 'public/build/bundle.js'
    },
    plugins: [
        svelte({
            compilerOptions: {
                // enable run-time checks when not in production
                dev: !production
            }
        }),
        replace({
            __api: JSON.stringify({
                env: {
                    isProd: production,
                    ...config().parsed // attached the .env config
                }
            }),
            delimiters: ['', '']
        }),
        json(),
        // we'll extract any component CSS out into
        // a separate file - better for performance
        css({ output: 'bundle.css' }),

        // If you have external dependencies installed from
        // npm, you'll most likely need these plugins. In
        // some cases you'll need additional configuration -
        // consult the documentation for details:
        // https://github.com/rollup/plugins/tree/master/packages/commonjs
        resolve({
            browser: true,
            dedupe: ['svelte']
        }),
        commonjs(),

        // In dev mode, call `npm run start` once
        // the bundle has been generated
        !production && serve(),

        // Watch the `public` directory and refresh the
        // browser on changes when not in production
        !production && livereload('public'),

        // If we're building for production (npm run build
        // instead of npm run dev), minify
        production && terser()
    ],
    watch: {
        clearScreen: false
    }
};
Enter fullscreen mode

Exit fullscreen mode



Connecting to Supabase

Most of our configuration is complete and we can dive into connecting with the Supabase application in Svelte.

Create a new file supabaseClient.js

import { createClient } from '@supabase/supabase-js'

const supabaseUrl = __api.env.SVELTE_APP_SUPABASE_URL
const supabaseAnonKey = __api.env.SVELTE_APP_SUPABASE_ANON_KEY

export const supabase = createClient(supabaseUrl, supabaseAnonKey)
Enter fullscreen mode

Exit fullscreen mode

Note: These variables will be exposed in our browser. Please be careful to not add more sensitive data. Our application is protected with Row Level Security and so you can use the Anonymous key even though it is exposed in the browser



Sign up Component

We can start by building a Sign up component which will get simple email and password from the user and then create an account in Supabase

Create a new component named Signup.svelte and add the following code



Method to create new user

<script>
import { supabase } from "./supabaseClient";

let loading = false;
let email, password, confirmpassword;
let message = { success: null, display: "" };

const handleSignup = async () =&

Incoming search terms:

  • svelte login

Leave a Reply

Your email address will not be published.