Authentication in Nuxt by Pinia

kietHTkietHT
3 min read

To implement this authentication system in your Nuxt.js application:

  1. First, install the required dependencies if you haven't already:
    npm install @pinia/nuxt

  2. Add Pinia to your Nuxt configuration (nuxt.config.js):
    export default defineNuxtConfig({ modules: ['@pinia/nuxt'], })

  3. Create a middleware to protect routes:
    // middleware/auth.js
    export default defineNuxtRouteMiddleware((to, from) => { const auth = useAuthStore()

    if (!auth.isAuthenticated && to.path !== '/login') { return navigateTo('/login') } })

  4. Create stores/auth.js

     // stores/auth.js
     import { defineStore } from 'pinia'
    
     export const useAuthStore = defineStore('auth', {
       state: () => ({
         user: null,
         token: null,
         isAuthenticated: false,
         loading: false,
         error: null,
       }),
    
       getters: {
         getUser: state => state.user,
         getToken: state => state.token,
         isUserAuthenticated: state => state.isAuthenticated,
         getError: state => state.error,
       },
    
       actions: {
         async login(credentials) {
           try {
             this.loading = true
             this.error = null
    
             // Make API call to your authentication endpoint
             const response = await $fetch('/api/auth/login', {
               method: 'POST',
               body: credentials,
             })
    
             // Store the token in localStorage
             localStorage.setItem('token', response.token)
    
             // Update state
             this.token = response.token
             this.user = response.user
             this.isAuthenticated = true
    
             // Navigate to dashboard or home page
             navigateTo('/dashboard')
           }
           catch (error) {
             this.error = error.message || 'Login failed'
             throw error
           }
           finally {
             this.loading = false
           }
         },
    
         async logout() {
           try {
             // Make API call to logout endpoint if needed
             await $fetch('/api/auth/logout', {
               method: 'POST',
             })
           }
           catch (error) {
             console.error('Logout error:', error)
           }
           finally {
             // Clear state and localStorage
             this.token = null
             this.user = null
             this.isAuthenticated = false
             localStorage.removeItem('token')
    
             // Navigate to login page
             navigateTo('/login')
           }
         },
    
         async checkAuth() {
           const token = localStorage.getItem('token')
           if (!token) {
             this.logout()
             return
           }
    
           try {
             // Verify token with backend
             const response = await $fetch('/api/auth/verify', {
               headers: {
                 Authorization: `Bearer ${token}`,
               },
             })
    
             this.token = token
             this.user = response.user
             this.isAuthenticated = true
           }
           catch (error) {
             this.logout()
           }
         },
    
         async register(userData) {
           try {
             this.loading = true
             this.error = null
    
             const response = await $fetch('/api/auth/register', {
               method: 'POST',
               body: userData,
             })
    
             // Automatically log in after successful registration
             await this.login({
               email: userData.email,
               password: userData.password,
             })
           }
           catch (error) {
             this.error = error.message || 'Registration failed'
             throw error
           }
           finally {
             this.loading = false
           }
         },
       },
     })
    
  5. Use the auth store in your components:

     <template>
       <div>
         <form @submit.prevent="handleLogin">
           <input v-model="email" type="email" />
           <input v-model="password" type="password" />
           <button type="submit" :disabled="auth.loading">
             {{ auth.loading ? 'Loading...' : 'Login' }}
           </button>
           <p v-if="auth.error" class="error">{{ auth.error }}</p>
         </form>
       </div>
     </template>
    
     <script setup>
     const auth = useAuthStore()
     const email = ref('')
     const password = ref('')
    
     const handleLogin = async () => {
       try {
         await auth.login({
           email: email.value,
           password: password.value
         })
       } catch (error) {
         console.error('Login error:', error)
       }
     }
     </script>
    
  6. Initialize auth check in your app.vue:

     <script setup>
     const auth = useAuthStore()
    
     // Check authentication status when app loads
     onMounted(() => {
       auth.checkAuth()
     })
     </script>
    

    Key features of this authentication system:

    • Complete state management for authentication

    • Token-based authentication with localStorage

    • Login, logout, and registration functionality

    • Protected routes with middleware

    • Error handling and loading states

    • Automatic token verification

0
Subscribe to my newsletter

Read articles from kietHT directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

kietHT
kietHT

I am a developer who is highly interested in TypeScript. My tech stack has been full-stack TS such as Angular, React with TypeScript and NodeJS.