mastering supabase auth in nuxt.js: a practical guide and industry insights

introduction

welcome! in this practical guide we’ll walk you through mastering supabase auth in nuxt.js. whether you’re a beginner, a student, or a full‑stack engineer, you’ll learn how to integrate secure authentication, manage sessions, and keep your app seo‑friendly—all while keeping your coding workflow smooth and devops ready.

prerequisites

  • node.js ≥ 18 and npm or yarn
  • basic knowledge of nuxt 3 and vue 3
  • a supabase account (free tier works fine)
  • understanding of full‑stack concepts and seo basics

step‑by‑step implementation

1. create a supabase project

log in to supabase, start a new project, and copy the supabase_url and supabase_anon_key. these keys will be used in your nuxt app.

2. install the supabase nuxt module

# using npm
npm i @supabase/supabase-js @nuxtjs/supabase

# or with yarn
yarn add @supabase/supabase-js @nuxtjs/supabase

3. configure nuxt to load environment variables

# .env (place at the project root)
nuxt_public_supabase_url=https://your-project.supabase.co
nuxt_public_supabase_anon_key=your-anon-key

4. initialize supabase in nuxt.config.ts

import { definenuxtconfig } from 'nuxt'

export default definenuxtconfig({
  modules: ['@nuxtjs/supabase'],
  runtimeconfig: {
    public: {
      supabaseurl: process.env.nuxt_public_supabase_url,
      supabaseanonkey: process.env.nuxt_public_supabase_anon_key,
    },
  },
})

5. build a simple sign‑up form

<template>
  <form @submit.prevent="signup">
    <input v-model="email" type="email" placeholder="email" required />
    <input v-model="password" type="password" placeholder="password" required />
    <button type="submit">sign up</button>
  </form>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { usesupabaseclient } from '#supabase'

const email = ref('')
const password = ref('')
const supabase = usesupabaseclient()

const signup = async () => {
  const { error } = await supabase.auth.signup({
    email: email.value,
    password: password.value,
  })
  if (error) {
    alert(`❌ ${error.message}`)
  } else {
    alert('✅ check your email for a confirmation link!')
  }
}
</script>

6. sign‑in form (similar to sign‑up)

<template>
  <form @submit.prevent="signin">
    <input v-model="email" type="email" placeholder="email" required />
    <input v-model="password" type="password" placeholder="password" required />
    <button type="submit">sign in</button>
  </form>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { usesupabaseclient } from '#supabase'

const email = ref('')
const password = ref('')
const supabase = usesupabaseclient()

const signin = async () => {
  const { error, data } = await supabase.auth.signinwithpassword({
    email: email.value,
    password: password.value,
  })
  if (error) {
    alert(`❌ ${error.message}`)
  } else {
    // store the session in a cookie for ssr (see next section)
    console.log('✅ logged in:', data.session)
  }
}
</script>

7. session handling and ssr support

nuxt 3 can run both on the client and the server. to keep the user logged in across page reloads, store the session in a httponly cookie.

// plugins/supabase.server.ts
import { definenuxtplugin } from '#app'
import { createclient } from '@supabase/supabase-js'

export default definenuxtplugin((nuxtapp) => {
  const config = useruntimeconfig()
  const supabase = createclient(
    config.public.supabaseurl,
    config.public.supabaseanonkey,
    {
      auth: {
        // persist the session in a cookie
        storage: {
          getitem: (key) => nuxtapp.ssrcontext?.event?.req?.cookies?.[key] ?? null,
          setitem: (key, value) => {
            // set cookie on the server response
            const event = nuxtapp.ssrcontext?.event
            if (event) {
              event.res.setheader('set-cookie', `${key}=${value}; httponly; path=/; samesite=lax`)
            }
          },
          removeitem: (key) => {
            const event = nuxtapp.ssrcontext?.event
            if (event) {
              event.res.setheader('set-cookie', `${key}=; max-age=0; path=/; httponly`)
            }
          },
        },
      },
    }
  )
  nuxtapp.provide('supabase', supabase)
})

8. protecting routes (middleware)

// middleware/auth.global.ts
export default definenuxtroutemiddleware((to, from) => {
  const supabase = usesupabaseclient()
  const user = supabase.auth.user()
  if (!user && to.path !== '/login') {
    return navigateto('/login')
  }
})

9. adding seo‑friendly meta tags

when you render pages on the server, search engines can index the content correctly. use nuxt’s usehead composable.

// pages/dashboard.vue
<script setup lang="ts">
import { usehead } from '#app'
import { usesupabaseclient } from '#supabase'

usehead({
  title: 'dashboard – my app',
  meta: [
    { name: 'description', content: 'secure dashboard for logged‑in users.' },
    { property: 'og:title', content: 'dashboard – my app' },
    { property: 'og:description', content: 'secure dashboard for logged‑in users.' },
  ],
})

const supabase = usesupabaseclient()
const user = supabase.auth.user()
</script>

10. devops tips for a production‑ready setup

  • environment separation: keep supabase_url and supabase_anon_key in separate .env files for dev, staging, and prod.
  • ci/cd pipelines: use github actions or gitlab ci to run npm run lint and npm run test before deploying.
  • monitoring: enable supabase logs and set up alerts for authentication failures.
  • performance: leverage nuxt’s static site generation (ssg) for public pages and keep auth‑protected pages server‑rendered.

putting it all together – a minimal project structure


my-nuxt-app/
├─ .env
├─ nuxt.config.ts
├─ plugins/
│   └─ supabase.server.ts
├─ middleware/
│   └─ auth.global.ts
├─ pages/
│   ├─ index.vue          ← public landing page (seo‑optimized)
│   ├─ login.vue          ← sign‑in / sign‑up forms
│   └─ dashboard.vue     ← protected, uses usehead for seo
└─ components/
    └─ authform.vue       ← reusable form component

conclusion

by following these steps you now have a full‑stack nuxt.js application with robust supabase auth, ready for devops pipelines and seo‑friendly rendering. keep experimenting, add social logins, and remember that clear, modular code is the key to scaling both your project and your knowledge.

Comments

Discussion

Share your thoughts and join the conversation

Loading comments...

Join the Discussion

Please log in to share your thoughts and engage with the community.