Home > Web Front-end > JS Tutorial > body text

Setting up Supabase Auth with Nuxt v3

Barbara Streisand
Release: 2024-10-17 08:24:03
Original
596 people have browsed it

Implementing authentication is something that you do on most projects, but still something that you may not remember how to do by memory because of how often you actually do it.

Here is a quick how-to about implementing Supabase Auth with Nuxt v3. In this example, we will be using OTP, but it applies to every case.

You will first want to start your project by going to Supabase's website.

After creating a project in Supabase and starting your project on Nuxt, we want to then install the Supabase Nuxt package by doing:

npx nuxi@latest module add supabase

We will then create our .env file and add the following environment variables:

SUPABASE_URL=<your_supabase_url>
SUPABASE_KEY=<your_supabase_key>
Copy after login

You can find these on the Supabase dashboard for your project, under Settings -> API

Setting up Supabase Auth with Nuxt v3

Afterwards, we can being setting up our project. I have made 2 very basic files so far:

  1. auth.ts (I used a Pinia store, but feel free to use just a regular file)
import { defineStore } from "pinia";

export const useAuthStore = defineStore("auth", () => {
  const supabase = useSupabaseClient();

  const sendOtp = async (email: string) => {
    const { error } = await supabase.auth.signInWithOtp({
      email,
    });

    if (error) {
      throw error;
    }

    return true;
  };

  const verifyOtp = async (email: string, otp: string) => {
    const { error } = await supabase.auth.verifyOtp({
      type: "email",
      token: otp,
      email,
    });

    if (error) {
      throw error;
    }

    return true;
  };

  return {
    sendOtp,
    verifyOtp,
  };
});
Copy after login
  1. LoginForm.vue
<template>
  <div class="max-w-md mx-auto bg-white p-8 rounded-lg shadow-md">
    <h2 class="text-3xl font-bold mb-6 text-center text-gray-800">Welcome</h2>
    <form @submit.prevent="handleSubmit" class="space-y-6">
      <div v-if="mode === 'email'">
        <label for="email" class="block mb-2 font-medium text-gray-700"
          >Email</label
        >
        <input
          type="email"
          id="email"
          v-model="email"
          required
          placeholder="Enter your email"
          class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-200"
        />
      </div>

      <div v-else-if="mode === 'code'">
        <p class="mb-2 font-medium text-gray-700">
          Enter the 6-digit code sent to {{ email }}
        </p>
        <input
          type="text"
          v-model="otpCode"
          required
          placeholder="Enter 6-digit code"
          maxlength="6"
          class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-200"
        />
      </div>

      <UButton
        icon="i-heroicons-paper-airplane"
        size="lg"
        color="primary"
        variant="solid"
        :label="buttonLabel"
        :trailing="true"
        block
      />
    </form>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from "vue";
import { useAuthStore } from "~/stores/auth";

const authStore = useAuthStore();

const email = ref("");
const otpCode = ref("");
const mode = ref("email");

const buttonLabel = computed(() => {
  return mode.value === "email" ? "Send One-Time Password" : "Verify Code";
});

const handleSubmit = async () => {
  if (mode.value === "email") {
    try {
      await authStore.sendOtp(email.value);
      mode.value = "code";
    } catch (error) {
      console.log("Error sending OTP: ", error);
    }
  } else {
    try {
      await authStore.verifyOtp(email.value, otpCode.value);
    } catch (error) {
      console.log("Error verifying OTP: ", error);
    }
  }
};
</script>

<style scoped></style>
Copy after login

Note that I am also using NuxtUI, in case you get any errors.

Because by default, the signInWithOtp function sends a magic link, you will have to change the email template on Supabase's dashboard to send a token:

Setting up Supabase Auth with Nuxt v3
This is found under Authentication -> Email Templates -> Change Confirm Signup and Magic Link templates to use {{ .Token }}

And that is pretty much it, you have a working auth!
If you want to add signout, you can also add a method to your previous file like such:

const signOut = async () => {
  const { error } = await supabase.auth.signOut();

  if (error) {
    throw error;
  }

  return true;
};
Copy after login

However, if you want to protect certain routes, we can also do that adding middleware.

Create a folder on the root called middleware (name is key) and a file called auth.ts.

You can then add something like this:

export default defineNuxtRouteMiddleware((to) => {
  const user = useSupabaseUser();

  const protectedRoutes = ["/app"];

  if (!user.value && protectedRoutes.includes(to.path)) {
    return navigateTo("/auth");
  }

  if (user.value && to.path === "/auth") {
    return navigateTo("/");
  }
});
Copy after login

This will basically protect from the server your /app route, so if you attempt to go to /app without being signed in, you will be redirected to /auth.

Likewise, if you try to visit /auth while already being signed in, you will be redirected to the home page /.

Now, to use this, you can place it inside the

Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!