Authentication in Nuxt app Part 3

Auth module and Express.js implementation

To follow this post you should first read Authentication in Nuxt part one.

 

What access scope can do in nuxt.js

 

In many apps, AWS, Google Cloud you have ACL (Access Control List) that basically enables giving users granular access to some of their resources. One can say that scopes are a simplified version of ACL, they also give specific users access to resources but rather in a more general way. So if you have some parts of your app that should be restricted only to specific groups of users, scopes are the solution that will work out.

This article is focused on basics related to integrating scopes in authentication mechanisms based on the official auth Nuxt module, Express.js, passport.js and MongoDB. This is the continuity of a bigger service so if you just landed here, haven't followed it from the beginning and got lost somewhere during reading just check previous parts of the series. Good luck!

 

Implement scope access in nuxt app

 

To make things super easy I only cover scope for admin users that can access the admin panel. If you need more scopes just use the same logic presented here. Start with creating a new file named i.e. authenticator.js in your middleware folder. In the file check if a user has specific scope to get through. In this example I use ‘admin name' but truly you can go with any name as long as you keep it the same way in the 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 auth section as middleware option in your nuxt.config.js file. 

// nuxt.config.js

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

 

Then add this middleware to your desired pages. I suggest having a separate layout for all admin pages where you can block access to all such pages at once.

// layouts/admin.vue

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

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

 

Check if a logged user without admin scope can access admin pages. It shouldn't be possible.

 

Implement scope access in the backend

 

Change the JWT local strategy by adding user scope to the response as shown below. Thanks to this your nuxt app will be able to get the information about a user scope and response 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 in 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)

 

In this article I don't cover CRUD operations for user scopes so remember to add admin scope to the user you want to grant admin access before going further. The simplest solution will be updating your database manually.

After making sure that the user has admin scope check whether he can access the admin pages. If everythings works it's time to restrict access to your endpoints which don't use scope functionality yet.

In the authentication controller create a new function responsible for admin scope checking. If the local JWT strategy won't pass admin scope 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();
}

 

Then implement adminScope as a middleware in your admin routes to restrict access to them for admins only.

 

// 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 whether nuxt and backend routes are blocked correctly for users without admin scopes.

If all works I can only congratulate you on implementing scopes in your nuxt application!

Notice that I use simple string for scope field but you can of course implement array and attach multiple different scopes for any user as the auth nuxt module is fully capable of handling such implementation.

BlowStack 2023