laravel 9 sanctum authentication with nuxt js example

In this section we will install & setup laravel 9 sanctum authentication with nuxt js. Nuxt JS provides automatic performance optimization, routing, component imports, and options for server-side rendering (SSR) or static site generation (SSG). If you’ve ever used Gatsby for React, modules are similar to plugins.


Setup Laravel 9 Sanctum Authentication

Create laravel project

composer create-project Laravel/laravel laravel-backend  

Setup your .env file

.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=database_name
DB_USERNAME=database_user_name
DB_PASSWORD=database_password


Install Laravel Breeze

composer require laravel/breeze --dev

Install laravel breeze api command to create Sanctum auth.

php artisan breeze:install api

After install breeze api, you can see .env file two url for backend and frontend. You can change url in production, for local leave it.

.env

APP_URL=http://localhost:8000
FRONTEND_URL=http://localhost:3000

run project and leave it.

php artisan serve  

Note: Open two terminal one for run laravel application & second to create nuxtjs project and run.


Setup Nuxt js Sanctum Authentication

Create nuxt js app

Using NPM:

npm init nuxt-app frontend


Using Yarn:

yarn create nuxt-app frontend

Then choose your project requirements.


Install Nuxtjs Auth

using yarn:

yarn add --exact @nuxtjs/auth-next
yarn add @nuxtjs/axios

using npm:

npm install --save-exact @nuxtjs/auth-next
npm install @nuxtjs/axios


Import Nuxt JS laravel Sanctum in nuxt.config.js

nuxt.config.js

export default {
  // Global page headers: https://go.nuxtjs.dev/config-head
  head: {
    title: 'frontend',
    htmlAttrs: {
      lang: 'en'
    },
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: '' },
      { name: 'format-detection', content: 'telephone=no' }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
    ]
  },

  // Global CSS: https://go.nuxtjs.dev/config-css
  css: [
  ],

  // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
  plugins: [
  ],

  // Auto import components: https://go.nuxtjs.dev/config-components
  components: true,

  // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
  buildModules: [
    // https://go.nuxtjs.dev/tailwindcss
    '@nuxtjs/tailwindcss',
  ],

  // Modules: https://go.nuxtjs.dev/config-modules
  modules: [
    '@nuxtjs/axios',
    '@nuxtjs/auth-next'
  ],

  auth: {
    strategies: {
      laravelSanctum: {
        provider: 'laravel/sanctum',
        url: 'http://localhost:8000',
        endpoints: {
          login: {
            url: '/login'
          }
        }
      },
    }
  },

  // Axios module configuration: https://go.nuxtjs.dev/config-axios
  axios: {
    // Workaround to avoid enforcing hard-coded localhost:3000: https://github.com/nuxt-community/axios-module/issues/308
    baseURL: 'http://localhost:8000',
    credentials: true
  },

  router: {
    middleware: ['auth']
  },

  // Build Configuration: https://go.nuxtjs.dev/config-build
  build: {
  }
}


Next, you need to create login.vue , register.vue and layouts folder add default.vue file.

laravel 9 sanctum nuxt js auth folder

laravel 9 sanctum nuxt js auth folder

Create default.vue and navbar with nuxt js link like login, register and logout.

default.vue

<template>
  <div>
    <nav class="container flex justify-around py-8 mx-auto bg-white">
      <div>
        <h3 class="text-2xl font-medium text-blue-500">LOGO</h3>
      </div>
      <div class="flex space-x-8">
        <NuxtLink to="/">Home</NuxtLink>
        <NuxtLink to="/login" v-if="!$auth.loggedIn">Login</NuxtLink>
        <NuxtLink to="/register" v-if="!$auth.loggedIn">Register</NuxtLink>
        <div v-if="$auth.loggedIn">
          <button
            type="button"
            @click="logout"
          >
            Logout
          </button>
        </div>
      </div>
    </nav>
    <Nuxt />
  </div>
</template>
<script>
export default {
  middleware: "auth",
  methods: {
    async logout() {
      this.$nuxt.$loading.start();
      this.$auth.logout();
      this.$nuxt.$loading.finish();
      this.$router.push("/login");
    },
  },
};
</script>


pages/register.vue

<template>
  <div
    class="relative flex flex-col justify-center min-h-screen overflow-hidden"
  >
    <div class="w-full p-6 m-auto bg-white rounded shadow-lg lg:max-w-md">
      <h1 class="text-3xl font-semibold text-center text-purple-700">
        Sign Up
      </h1>

      <form class="mt-6" ref="registerform" @submit.prevent="register">
        <div>
          <label for="name" class="block text-sm text-gray-800">name</label>
          <input
            v-model="form.name"
            name="name"
            type="text"
            class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
          />
        </div>
        <div>
          <label for="email" class="block text-sm text-gray-800">Email</label>
          <input
            v-model="form.email"
            name="email"
            type="email"
            class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
          />
        </div>
        <div class="mt-4">
          <div>
            <label for="password" class="block text-sm text-gray-800"
              >Password</label
            >
            <input
              v-model="form.password"
              name="password"
              type="password"
              class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
            />
          </div>
          <div>
            <label for="password" class="block text-sm text-gray-800"
              >Password Confirmation</label
            >
            <input
              v-model="form.password_confirmation"
              name="password_confirmation"
              type="password"
              class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
            />
          </div>
          <div class="mt-6">
            <button
              type="submit"
              class="w-full px-4 py-2 tracking-wide text-white transition-colors duration-200 transform bg-purple-700 rounded-md hover:bg-purple-600 focus:outline-none focus:bg-purple-600"
            >
              Submit
            </button>
          </div>
        </div>
      </form>
    </div>
  </div>
</template>
<script>
export default {
  auth: "guest",
    data() {
    return {
      form: {
        name: null,
        email: null,
        password: null,
        password_confirmation: null
      },
      errors: []
    }
  },
  mounted() {
    this.$axios.$get("/sanctum/csrf-cookie");
  },
  methods: {
    register() {
      try {
        this.$axios.post("/register", this.form).then((res) => {
          this.$auth.loginWith("laravelSanctum", { data: this.form });
          this.$router.push({
            path: "/",
          });
        });
      } catch (err) {
        console.log(err);
      }
    },
  },
};
</script>


pages/login.vue

<template>
  <div
    class="relative flex flex-col justify-center min-h-screen overflow-hidden"
  >
    <div class="w-full p-6 m-auto bg-white rounded shadow-lg lg:max-w-md">
      <h1 class="text-3xl font-semibold text-center text-purple-700">
        Sign In
      </h1>
      <form class="mt-6" @submit.prevent="login">
        <div>
          <label for="email" class="block text-sm text-gray-800">Email</label>
          <input
            v-model="form.email"
            name="email"
            type="email"
            class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
          />
        </div>
        <div class="mt-4">
          <div>
            <label for="password" class="block text-sm text-gray-800"
              >Password</label
            >
            <input
              v-model="form.password"
              name="password"
              type="password"
              class="block w-full px-4 py-2 mt-2 text-purple-700 bg-white border rounded-md focus:border-purple-400 focus:ring-purple-300 focus:outline-none focus:ring focus:ring-opacity-40"
            />
          </div>
          <div class="mt-6">
            <button
              type="submit"
              class="w-full px-4 py-2 tracking-wide text-white transition-colors duration-200 transform bg-purple-700 rounded-md hover:bg-purple-600 focus:outline-none focus:bg-purple-600"
            >
              Login
            </button>
          </div>
        </div>
      </form>
    </div>
  </div>
</template>

<script>
export default {
  auth: "guest",
  data() {
    return {
      form: {
        email: null,
        password: null,
      },
    };
  },
  mounted() {
    this.$axios.$get("/sanctum/csrf-cookie");
  },
  methods: {
    async login() {
      this.$nuxt.$loading.start();
      try {
        await this.$auth.loginWith("laravelSanctum", { data: this.form });
        this.$router.push({
          path: "/",
        });
      } catch (err) {
        console.log(err);
      }
      this.$nuxt.$loading.finish();
    },
  },
};
</script>
laravel 9 sanctum nuxt js login

laravel 9 sanctum nuxt js login


pages/index.vue

<template>
  <div>
    <div class="flex items-center justify-center h-screen">
      <div class="max-w-xl p-5 shadow">
        <div v-if="!$auth.loggedIn">
          <h3>Home</h3>
        </div>
        <div v-if="$auth.loggedIn">
          <div>Name:{{ $auth.user.name }}</div>
          <div>Name:{{ $auth.user.email }}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "IndexPage",
};
</script>
laravel 9 sanctum nuxt js auth

laravel 9 sanctum nuxt js auth


Run the server

npm run dev


Read Also

Laravel 9 Add Simple Sidebar with Tailwind CSS Example

How to Use Carousel Slider in Laravel 9 Example

Laravel 9 Posts with Tags Many to Many Relationships Example

Laravel 9 Insert Category in Posts CRUD Example

How to Use Ckeditor 5 in Laravel 9 Vite with Tailwind CSS

Laravel 9 Simple Image Upload in Ckeditor 5 Example

Laravel 9 Flash Message Timeout and Hide Message Example

Install & Setup Markdown Editor in Laravel 9

Nuxt 3 Data Fetching Using Laravel 9 Api Example

Laravel 9 Image Upload with Preview using Tailwind CSS & Alpine JS

Laravel 9 with Tailwind CSS Form Validation Example

Laravel 9 Backend Api Connect with Vue 3 Using Axios Example

Laravel 9 Authentication with Next js Example

Laravel 9 Simple Search with Pagination Example

Laravel 9 Install Setup TALL(Tailwind, Alpinejs, Livewire) Admin Panel

How to Fix and Clean Code Style in laravel 9

Laravel 9 Image File Upload Example

3 Way to Create Slug in Laravel 9 without Package

How to Add Dark Mode in Laravel 9 with Tailwind CSS