5 min.

Authentication in Nuxt app Part 3

Auth module and Express.js implementation

Explore how to integrate scopes into Nuxt.js for authorization, using Express.js, Passport.js, MongoDB, and the Nuxt auth module.

To follow this post, you should first read Authentication in Nuxt, Part One and Authentication in Nuxt, Part Two.

 

 

What Access Scopes Can Do in Nuxt.js

 

In many applications, such as AWS and Google Cloud, you have an Access Control List (ACL) that enables granular access to resources for users. Scopes can be considered a simplified version of ACLs, providing specific users access to resources in a more general manner. Therefore, if certain parts of your app need to be restricted to specific user groups, scopes offer a suitable solution.

 

This article focuses on the basics of integrating scopes into authentication mechanisms, leveraging the official Nuxt auth module, Express.js, Passport.js, and MongoDB. Actually, it's more related to authorization rather than authentication. This piece is part of a larger series, so if you've just arrived here without following from the beginning and find yourself lost, I recommend checking out the previous parts of the series.

 

 

Implementing Scope Access in a Nuxt App

 

To simplify, this guide will cover scope implementation for admin users accessing the admin panel. If you require additional scopes, you can apply the same logic outlined here. Begin by creating a new file named, for example, authenticator.js in your middleware folder. This file should check if a user has the specific scope required for access. In this instance, I use 'admin' as the scope name, but you can choose any name, provided it remains consistent across your backend.

 

 

// middleware/authenticator.js

export default function ({ $auth, redirect }) {
  const user = $auth.user
  if (user.user && user.user.scope === 'admin') {
  } else {
    redirect('/')
  }
}

 

 

Next, add this file path to the middleware option in the auth section of your nuxt.config.js file.

 

 

// nuxt.config.js

auth: {
  middleware: [
    { src: '~/middleware/authenticator.js' }
  ],
  ...

 

 

Then, apply this middleware to your desired pages. For admin pages, I suggest using a separate layout where you can block access to all such pages simultaneously.

 

 

// layouts/admin.vue

<template>
  <v-app>
   <div>
    <nuxt />
   </div>
  </v-app>
</template>

<script>
export default {
  middleware: ['auth', 'authenticator']
}
</script>

 

 

Verify that a logged-in user without the admin scope cannot access admin pages.

 

 

Implementing Scope Access in the Backend

 

Modify the JWT local strategy by including the user scope in the response. This allows your Nuxt app to recognize a user's scope and respond accordingly.

 

 

// api/controllers/authentication.controller.js

passport.use(new JwtStrategy({
  jwtFromRequest: tokenExtractor,
  secretOrKey: authUserSecret
},
function (jwtPayload, done) {
  return GetUser(jwtPayload.email)
    .then((user) => {
      if (user) {
        return done(null, {
          email: user.email,
          scope: user.scope
        })
      } else {
        return done(null, false, 'Failed')
      }
    })
    .catch((err) => {
      return done(err)
    })
}
))

 

 

Add the scope field to your user model.

 

 

// api/models/user.js

const mongoose = require('mongoose')
const Schema = mongoose.Schema

const UserSchema = new Schema({
 ...
  scope: { type: String, default: 'user' },
 ...
})

export default mongoose.model('User', UserSchema)

 

 

Before proceeding, ensure you assign the admin scope to the user intended for admin access, potentially by manually updating your database.

 

To restrict access to your endpoints that don't yet utilize scope functionality, create a new function in the authentication controller for checking the admin scope. If a request does not pass the admin scope check, this function will block specific backend routes.

 

 

// api/controllers/authentication.controller.js

const adminScope = (req, res, next) => {
  if (req.user.scope !== 'admin'){
    return res.status(403).send({
      status:'fail',
      message:'Invalid scope!'
    })
  }
  next();
}

 

 

Finally, implement adminScope as middleware in your admin routes to restrict access solely to admins.

 

 

// api/index.js

...
import AuthenticationController from '../api/controllers/authentication.controller'
const passport = require('passport')
const adminRoutes = require('./routes/admin')
...

app.use('/admin', [passport.authenticate('jwt', { session: false }), AuthenticationController.adminScope], [adminRoutes])

 

 

Double-check that both Nuxt and backend routes correctly block users without admin scopes.

 

If everything works as intended, congratulations on implementing scopes in your Nuxt application! Note that while this guide uses a simple string for the scope field, you can also implement an array to assign multiple different scopes to any user, as the Nuxt auth module fully supports such implementations.