DEV Community

Cover image for Secure Your Nuxt 3 App
dev-davexoyinbo
dev-davexoyinbo

Posted on

Secure Your Nuxt 3 App

Nuxt auth logo
Authentication is a crucial aspect of any modern web application. Whether you’re building an e-commerce site, a social platform, or any service requiring user authentication, handling authentication securely and efficiently is key to ensuring a smooth user experience. In this post, we’ll explore how to easily integrate authentication into your Nuxt.js application using the @workmate/nuxt-auth package. We would discuss the local auth provider here, where you can connect to your backend directly. The package also has support for oAuth2 like github and google. To view that, check out the github repository
https://github.com/work-mate/nuxt-auth-module

What is @workmate/nuxt-auth?
@workmate/nuxt-auth is a package designed to make authentication in Nuxt.js apps seamless. This package provides a straightforward way to add authentication flows, such as login, registration, and user session management, to your Nuxt app.

Installing @workmate/nuxt-auth
The first step is to install the package. Open your terminal and navigate to the root of your Nuxt project. Then, run the following command to install the @workmate/nuxt-auth package:

npm install --save @workmate/nuxt-auth
Enter fullscreen mode Exit fullscreen mode

or if you are using yarn:

yarn add @workmate/nuxt-auth
Enter fullscreen mode Exit fullscreen mode

Setting Up the Package in Your Nuxt Project
Once the package is installed, you need to configure it in your Nuxt application. Open your nuxt.config.js file and add @workmate/nuxt-auth to the modules array:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    "@workmate/nuxt-auth"
  ],
  ...
}); 
Enter fullscreen mode Exit fullscreen mode

Set up your auth providers

// nuxt.config.ts
const BACKEND_URL = process.env.BACKEND_BASE_URL || "http://localhost:9000";

export default defineNuxtConfig({
  modules: [ "@workmate/nuxt-auth",],

  auth: {
    global: true,
    redirects: {
      redirectIfLoggedIn: "/dashboard",
      redirectIfNotLoggedIn: "/register", // default is /login
    },
    apiClient: {
      baseURL: BACKEND_URL,
    },
    //token: {
    // type: "Bearer",
    // maxAge: 1000 * 60 * 60 * 24 * 30,
    // cookiesNames: {
    //  accessToken: "auth:token",
    //  refreshToken: "auth:refreshToken",
    //  authProvider: "auth:provider",
    //  tokenType: "auth:tokenType",
    //}
  };
    providers: {
      local: {
        endpoints: {
          signIn: {
            path: `${BACKEND_URL}/api/auth/login`,
            method: "POST",
            tokenKey: "token",
            body: {
              principal: "email",
              password: "password",
            },
          },
          user: {
            path: `${BACKEND_URL}/api/auth/user`,
            userKey: "data",
          },
          signOut: {
            path: `${BACKEND_URL}/api/auth/user`,
            method: "POST",
          },
        },
      },
    },
  },
});
Enter fullscreen mode Exit fullscreen mode

Brief explanation of the config
Let's go through the above real quick, the global:true line ensures that the auth middleware is set on every page of your website. And since you won't be authenticated by default, you want to turn it off on the home route like so

// pages/index.vue
<template>
   <main>Landing page</main>
</template>

<script lang="ts" setup>
definePageMeta({
  auth: false,
});
<script>
Enter fullscreen mode Exit fullscreen mode

You can also set the auth to false on pages you want your users to access regardless of whether they are logged in or not like the help page or the about us page.

In the case where you don't want to use the global middleware, add the auth middleware to the pages you want to protect, eg the dashboard

// pages/dashboard.vue
<template>
   <main>Dashboard page</main>
</template>

<script lang="ts" setup>
definePageMeta({
  middleware: "auth",
});
<script>
Enter fullscreen mode Exit fullscreen mode

The signIn endpoint
In the above config, the application would make a post request to the endpoint ${BACKEND_URL}/api/auth/login with the body

{
    "email": "email@example.com",
    "password": "password"
}
Enter fullscreen mode Exit fullscreen mode

and would expect data with the format

{
    "token": "auth token",
}
Enter fullscreen mode Exit fullscreen mode

for nested data, use 'period' separated keys eg nested.token.data.

The same foes for the user endpoint and the sign out endpoint.

The api client
By default, nuxt would want you to send requests to your frontend domain, meanwhile you might want to send it to another (eg. the backend). This package automatically handles this and also adds the authorization headers to the api client so you don't have to manually do that.

To use the api client, add the apiClient's baseurl to the config as shown in the code above. Then instead of calling useFetch or $fetch in nuxt use

useAuthFetch(url, options)
const { $authFetch } = useNuxtApp();

$authFetch(url, options)
Enter fullscreen mode Exit fullscreen mode

And they have the exact same interface with the useFetch and $fetch apis.

Logging In

// pages/index.vue
<template>
   <form @submit.prevent="submit" class="login-form">
      <div class="form-group">
        <label for="email">Email</label>
        <input
          type="email"
          id="email"
          v-model="email"
          placeholder="Enter your email"
          required
        />
      </div>

      <div class="form-group">
        <label for="password">Password</label>
        <input
          type="password"
          id="password"
          v-model="password"
          placeholder="Enter your password"
          required
        />
      </div>

      <button type="submit">Login</button>
    </form>
</template>

<script lang="ts" setup>
definePageMeta({
  middleware: 'auth-guest',
});

const email = ref();
const password = ref();

const { login } = useAuth();

function submit() {
  login("local", {
    principal: email.value,
    password: password.value,
  }).catch(err => {
     //handle error
  })
}
<script>
Enter fullscreen mode Exit fullscreen mode

The auth guest middleware allows only unauthenticated users to visit a page, which is what we need in the case of the login.

Auth Data
In order to get the auth data, you can use the useAuth composable

const {
  loggedIn,
  user,
  token,
  refreshToken,
  login,
  logout,
  refreshUser,
  refreshTokens,
} = useAuth();

// or
const { $auth } = useNuxtApp();
const {
  loggedIn,
  user,
  token,
  refreshToken,
  login,
  logout,
  refreshUser,
  refreshTokens,
} = $auth;
Enter fullscreen mode Exit fullscreen mode

In order to logout, you can use the logout from the above code snippet

logout().then(() => {
  // show logout notification
});
Enter fullscreen mode Exit fullscreen mode

Top comments (0)