Set up a Svelte todo list on self-hosted Supabase + Email sign up + Google, Facebook Auth + host on GitHub pages

chits_programming_blog

Chit

Posted on January 6, 2023

Set up a Svelte todo list on self-hosted Supabase + Email sign up + Google, Facebook Auth + host on GitHub pages

In this tutorial. I will guide you through creating a to-do list web app using Svelte as the front end hosted on GitHub pages, and Supabase as the back end. I will also discuss how to set up an email authentication, as well as google and Facebook third-party OAuth. The outcome would be like this from this Github repo.

Important information

This is my second time making a tutorial, if there is anything unclear, feel free to ask in the comments and I'll try to reply to them.

This tutorial assumes you are using a self-hosted Supabase. If you are using a managed Supabase you should follow the instructions on the GitHub page instead.

If you don't already have a self-hosted Supabase, check out my other tutorial How to Self-host Supabase and come back to this tutorial afterwards.

Create a GitHub repository for the Svelte App

We will host our svelte app on GitHub pages. It is a static site hosting service that host files straight out of a repository on GitHub. It has the benefit of being free and has pretty good bandwidth since it is hosted by a big company.

We first need to create a GitHub repository. if you don't have GitHub Pro, you must create a public repository in order to share your site with GitHub pages, but with GitHub Pro, both private and public repositories support GitHub pages.

For the repository name, you can choose any name you want unless you want to page to be on your main GitHub page (Main GitHub page means the website on your {github_username}.github.io). If so, you need to name your repository as {github_username}.github.io.

If you name your repository other things, your website would have a link of {github_username}.github.io/{project_name} . In my case, my website would be on https://chit-uob.github.io/svelte_supabase_todo_example.

You can then click Create Repository.

Clone To-do list example

Then we clone the Svelte to-do list example from the Supabase GitHub. We choose a folder to put the project, and then we clone it with the sparse setting, this clones the repository without downloading every single file. Then we can go inside the repository and spare-checkout the to-do list example.

  • Make sure you have Git installed, install from here if you don't already

  • To open the command prompt on windows, you can right-click an empty space on the folder, and choose Open in Windows Terminal

git clone --depth 1 --filter=blob:none --sparse https://github.com/supabase/supabase
cd supabase
git sparse-checkout set examples/todo-list/sveltejs-todo-list

Enter fullscreen mode Exit fullscreen mode

Now we can go in supabase -> examples -> todo-list , and copy the sveltejs-todo-list folder to another folder you use for the project. I am going to use the same example folder. Then we open the terminal inside the sveltejs-todo-list folder, and run the following commands.

git init
git add .
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/{github_username}/{repo_name}.git
git push -u origin main

Enter fullscreen mode Exit fullscreen mode
  • If you haven't already logged in to GitHub, it may prompt you to log in with your credentials

Configure front end

Then we install the GitHub pages npm package

  • You need Node.js installed for this, install it from here if not already
npm install gh-pages --save-dev

Enter fullscreen mode Exit fullscreen mode

Set up package.json

Inside the file package.json, we add a "homepage" property and set it as https://{github_username}.github.io/{project_name}, and a "deploy" inside the "script" property and set it as gh-pages -d dist, so lines 4-10 should look something like this:

  "version": "2.0.0",
  "type": "module",
  "homepage": "https://chit-uob.github.io/svelte_supabase_todo_example",
  "scripts": {
    "deploy": "gh-pages -d dist",
    "dev": "concurrently \"npm run dev:css\" \"vite\"",
    "dev:css": "tailwindcss -w -i ./src/tailwind.css -o src/assets/app.css",

Enter fullscreen mode Exit fullscreen mode

Then we copy the .env.example file, and rename it to .env . Inside there we fill in the backend URL and anon key. If you followed my last tutorial, VITE_SUPABASE_URL would be your backend domain name. Otherwise, it would be whatever you set your API_EXTERNAL_URL inside the .env file inside the Supabase docker folder. As for VITE_SUPABASE_ANON_KEY , it is the value of ANON_KEY in the Supabase docker folder .env file.

...
JWT_SECRET=...
ANON_KEY={THIS IS THE ANON KEY}
SERVICE_ROLE_KEY=...
...
## General
...
DISABLE_SIGNUP=...
API_EXTERNAL_URL={THIS IS THE SUPABASE URL}
...

Enter fullscreen mode Exit fullscreen mode
  • You should then add .env to the .gitignore file, in order to not commit your secret keys.

If not a user site nor custom domain: set up vite.config.ts

If you are not using the user site (username.github.io), or you are not using a custom domain, then you would need to configure the vite.config.ts , and set base to your repository name, so lines 5-8 look something like this:

// https://vitejs.dev/config/
export default defineConfig({
  base: '/svelte_supabase_todo_example/',
  plugins: [svelte()],
...

Enter fullscreen mode Exit fullscreen mode

This is because normally Vite looks for files in the main URL, which would be username.github.io/{whatever_file} , but since we want it to look for files inside username.github.io/{project_name}/{whatever_file} , we need to set the base to the project name.

Change front-end authentication

The original code uses GitHub and Google auth, but we want to use Facebook and Google auth instead, so inside the src/lib/Auth.svelte file, in line 114, we change it into on:click={() => handleOAuthLogin("github")} . In line 118, we change it into Facebook .

Optional: Mapping a custom domain to the GitHub page

if you have a custom domain, you have to create a file called CNAME inside the public folder, with the content being the custom domain. And change the homepage inside the package.json to be the custom domain.

Navigate to your DNS provider and create a CNAME record that points your subdomain to the default domain for your site. For example, if you want to use the subdomain subdomain.example.com for your user site, create a CNAME record that points subdomain.example.com to <user>.github.io. Also, add A Record with host @ and value 185.199.108.153, 185.199.109.153, 185.199.110.153, 185.199.111.153. So your record looks like this:

  • Side note: when I was testing this, GitHub seems to dislike having dashes - or underscore _ inside the subdomain

  • If you used a user site <user>.github.io , every other project site you use afterwards, will start with your custom domain, instead of <user>.github.io .

Deploy with GitHub pages

We can install the necessary packages, build the project, and then deploy it.

npm install
npm run build
npm run deploy

Enter fullscreen mode Exit fullscreen mode

We then visit the repository on GitHub and go to Settings -> Pages, select Deploy from a branch, and select gh-pages as the branch. Then we can optionally enable HTTPS too.

If you used a custom domain, the page would like something like this:

Congratulations! When you go to the URL stated above, you will be able to visit the website.

However, only the front end is working for now, in order to have a full-fletch web application, we need the backend to work as well.

Make the database table

The initial Supabase database given to us only contains the auth tables, we need to create the profiles table and todo table on our own. In the hosted version, the snippets are provided, but since we are self-hosting, we will have to copy them from there.

I created a Supabase account, created a project, and then copied the snippet. For you, you can just copy the following code to the run panel and run it.

Go to the Supabase dashboard, inside the default project -> SQL editor, we can paste the following code there, and click run to run them.

-- Create a table for public profiles
create table profiles (
  id uuid references auth.users not null primary key,
  updated_at timestamp with time zone,
  username text unique,
  full_name text,
  avatar_url text,
  website text,

  constraint username_length check (char_length(username) >= 3)
);
-- Set up Row Level Security (RLS)
-- See https://supabase.com/docs/guides/auth/row-level-security for more details.
alter table profiles
  enable row level security;

create policy "Public profiles are viewable by everyone." on profiles
  for select using (true);

create policy "Users can insert 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);

-- This trigger automatically creates a profile entry when a new user signs up via Supabase Auth.
-- See https://supabase.com/docs/guides/auth/managing-user-data#using-triggers for more details.
create function public.handle_new_user()
returns trigger as $$
begin
  insert into public.profiles (id, full_name, avatar_url)
  values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
  return new;
end;
$$ language plpgsql security definer;
create trigger on_auth_user_created
  after insert on auth.users
  for each row execute procedure public.handle_new_user();

-- Set up Storage!
insert into storage.buckets (id, name)
  values ('avatars', 'avatars');

-- Set up access controls for storage.
-- See https://supabase.com/docs/guides/storage#policy-examples for more details.
create policy "Avatar images are publicly accessible." on storage.objects
  for select using (bucket_id = 'avatars');

create policy "Anyone can upload an avatar." on storage.objects
  for insert with check (bucket_id = 'avatars');
Enter fullscreen mode Exit fullscreen mode

Then for the todo list

--
-- For use with:
-- https://github.com/supabase/supabase/tree/master/examples/todo-list/nextjs-todo-list or
-- https://github.com/supabase/supabase/tree/master/examples/todo-list/react-todo-list or
-- https://github.com/supabase/supabase/tree/master/examples/todo-list/sveltejs-todo-list or
-- https://github.com/supabase/supabase/tree/master/examples/todo-list/vue3-ts-todo-list
--

create table todos (
  id bigint generated by default as identity primary key,
  user_id uuid references auth.users not null,
  task text check (char_length(task) > 3),
  is_complete boolean default false,
  inserted_at timestamp with time zone default timezone('utc'::text, now()) not null
);
alter table todos enable row level security;
create policy "Individuals can create todos." on todos for
    insert with check (auth.uid() = user_id);
create policy "Individuals can view their own todos. " on todos for
    select using (auth.uid() = user_id);
create policy "Individuals can update their own todos." on todos for
    update using (auth.uid() = user_id);
create policy "Individuals can delete their own todos." on todos for
    delete using (auth.uid() = user_id);
Enter fullscreen mode Exit fullscreen mode

Email sign up

To enable email sign-up, we need our backend to be able to send emails. Email servers are very difficult to host, so we will use an SMTP relay service, and have them send the emails for us. There are many choices, I chose to use Sendinblue because it has the biggest free tier email sending limit. It can send up to 300 emails per day, which means up to 9000 emails per month. You can use whatever service you want, you just need to get the required credentials.

Get the credentials from Sendinblue

Create an account in Sendinblue. In the dashboard, click on the Profile in the upper right corner -> SMTP and API.

Inside that page, we need the SMTP Server, Port, Login. We also need to generate an SMTP key, which would act as the password.

Fill in the credentials in the self-hosted Supabase

Going back to the Supabase backend, in the supabase/docker/ directory inside the .env file, we can paste the respective values inside the respective field.

## Email auth
ENABLE_EMAIL_SIGNUP=true
ENABLE_EMAIL_AUTOCONFIRM=false
SMTP_ADMIN_EMAIL={The email address you want the email to be from}
SMTP_HOST=smtp-relay.sendinblue.com
SMTP_PORT={The port given to you}
SMTP_USER={Your login}
SMTP_PASS={Your SMTP key}
SMTP_SENDER_NAME={The name of the sender of your choosing}

Enter fullscreen mode Exit fullscreen mode

Social OAuth

We also want to enable Open Authentication login, because it skips the step of creating an account for the user, so users will more likely be inclined to sign up to your site.

Google

Supabase already has a guide on this, however, that is for the managed version, for the self-hosted version, there is something we need to do differently.

First, go to https://cloud.google.com/, Sign in to google if not already, and then click console. It will prompt you to accept the terms of service.

Inside there, click on Select a Project at the top left and click new project. Fill in your app information then click Create, this will take you to the dashboard for the new project.

In the search bar at the top labelled Search products and resources type OAuth. Click on OAuth consent screen from the list of results. On the OAuth consent screen page select External. Click Create.

On the Edit app registration page fill out your app information. The Application home page is your Svelte website, and The Authorised domain is the domain of your website. Click Save and continue at the bottom.

Click Credentials at the left to go to the Credentials page on the Google Cloud Platform console. Click Create Credentials near the top then select OAuth client ID . On the Create OAuth client ID page, select your application type. If you're not sure, choose Web application. Fill in your app name. At the bottom, under Authorized redirect URIs click Add URI.

Your URI should be what you set as the API_EXTERNAL_URL inside the supabase docker .env file + /auth/v1/callback. For example, https://mybackend.com/auth/v1/callback. Enter your callback URI under Authorized redirect URIs at the bottom. Enter your callback URI in the Valid OAuth Redirect URIs box. Click Save Changes at the bottom right. Click Create. Then we need to copy and save the values under Your Client ID and Your Client Secret.

Then we can go back to the supabase docker .env file, and add the following code

## Google auth
ENABLE_GOOGLE_SIGNUP=true
GOOGLE_CLIENT_ID={the_client_id_given_to_you}
GOOGLE_CLIENT_SECRET={the_client_secret_given_to_you}

Enter fullscreen mode Exit fullscreen mode

And in the supabase docker docker-compose.yml file, under the auth environment section, (around line 87), we fill in the following:

GOTRUE_EXTERNAL_GOOGLE_ENABLED: ${ENABLE_GOOGLE_SIGNUP}
GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
GOTRUE_EXTERNAL_GOOGLE_SECRET: ${GOOGLE_CLIENT_SECRET}
GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI: {the_callback_uri}

Enter fullscreen mode Exit fullscreen mode

Around this part is a lot of GOTRUE_..., so it should be pretty easy to find. Keep in mind that the ${} things should be taken literally, you shouldn't replace the string inside ${}, but do replace {the callback uri} with the actual callback uri.

Facebook

The Facebook guide can also be found on the Supabase guide, I am going to briefly go through what you need to do, and the self-hosted instructions not included in their guide.

We first create and configure a Facebook Application on the Facebook Developers Site. We first login. Click on My Apps at the top right. Click Create App near the top right. Select your app type and click Continue (Do NOT choose "business", it complicates things). Fill in your app information, then click Create App. This should bring you to the screen: Add Products to Your App. (Alternatively you can click on Add Product in the left sidebar to get to this screen.)

From the Add Products to your App screen, we can click Setup under Facebook Login . Skip the Quickstart screen, instead, in the left sidebar, click Settings under Facebook Login . Enter your callback URI under Valid OAuth Redirect URIs on the Facebook Login Settings page. Enter this in the Valid OAuth Redirect URIs box. Click Save Changes at the bottom right.

Be aware that you have to set the right access levels on your Facebook App to enable 3rd party applications to read the email address. From the App Review -> Permissions and Features screen: Click the button Request Advanced Access on the right side of public_profile and email .

Click Settings / Basic in the left sidebar. Copy your App ID from the top of the Basic Settings page. Under App Secret click Show then copy your secret. Make sure all required fields are completed on this screen.

Then similarly, we go to the supabase docker .env file, and add the following code:

## Facebook auth
ENABLE_FACEBOOK_SIGNUP=true
FACEBOOK_CLIENT_ID={the_id}
FACEBOOK_CLIENT_SECRET={the_secret}

Enter fullscreen mode Exit fullscreen mode

And in the supabase docker docker-compose.yml file, under the google stuff we just added, we add:

GOTRUE_EXTERNAL_FACEBOOK_ENABLED: ${ENABLE_FACEBOOK_SIGNUP}
GOTRUE_EXTERNAL_FACEBOOK_CLIENT_ID: ${FACEBOOK_CLIENT_ID}
GOTRUE_EXTERNAL_FACEBOOK_SECRET: ${FACEBOOK_CLIENT_SECRET}
GOTRUE_EXTERNAL_FACEBOOK_REDIRECT_URI: {the_callback_uri}

Enter fullscreen mode Exit fullscreen mode
  • Note that both Google and Facebook Auth are in testing mode, to use them in production, you need to change them to production mode.

Replace site URL

also inside the supabase docker .env file, you can change the SITE_URL=http://localhost:3000 , and set the URL to the URL of your front-end website.

Restart Supabase

Now that everything is set, you can restart Supabase. If you followed my last tutorial, Supabase would be running inside a screen, do screen -r supabase , then ctrl + c to stop the already running docker, then docker compose up to start the docker again. If it is not already running, you can just do docker compose up inside the supabase docker directory to start Supabase.

Conclusion

Now you should get a fully functional to-do list web app, you can try the different logins, from email sign-up and sending an email to confirm your account, to one-click OAuth with Google and Facebook. After logging in, you can also add and remove to-do items, and they will stay there when you log in with different devices.

This is my second touch on making a tutorial, if there are any steps unclear, feel free to leave a comment and I'll try to answer them. hope this tutorial helps.

💖 💪 🙅 🚩
chits_programming_blog
Chit

Posted on January 6, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related