manish thakur
manish thakur

Reputation: 820

How to set authorization header and protect routes in Vuejs and Node

I am using passport-jwt strategy to protect auth users in my app, once I login I am generating a jwt-token now I want to protect my welcome page rout so that user cannot open it without login

So when I login I am creating jwt-token with payload like this

my user.js file

const payload = { email: rows[0].email } // jwy payload
            console.log('PAYLOAD')
            console.log(payload)
            jwt.sign(
                payload,
                key.secretOrKey, { expiresIn: 3600 },
                (err, token) => {
                    res.json({
                        success: true,
                        token: 'Bearer ' + token,
                        email
                    })

                })

Now in my passport.js I am doing like this

   const opts = {};

opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;

passport.use(new JwtStrategy(opts, (jwt_payload, done) => {

    let payLoadEmail = jwt_payload.email //payload data what I have passed in creating jwt 
    console.log("payload email :" + payLoadEmail)
    User.fetchLogedInUser(payLoadEmail)
        .then(([rows]) => {
            if (rows.length > 0) {
                return done(null, rows[0].email) // returning data what I need
            }
            return done(null, false)
        })
        .catch(err => console.log(err))

}));

Both are working fine.

Now I want to protect my welcome rout so in my router.js file

    const express = require('express');
const router = express.Router();
const passport = require('passport')


const UsersCtrl = require('../controllers/users');

router.use('/login', UsersCtrl.login)
router.use('/welcome',passport.authenticate('jwt',{session:false}))
router.use('/logout', UsersCtrl.logout)


module.exports = router;

suppose user types localhost:8080/welcome without login then I want to protect it

So in my store.js file when user logs in I am doing this on login click and I have made a method getAuthUser. I don't know how to I pass this config to protect my welcome file

Here is my full store.js code

    import axios from 'axios'
import jwt from 'jsonwebtoken'

function checkTokenValidity(token) {  // token validity
    if (token) {
        const decodedToken = jwt.decode(token)
        return decodedToken && (decodedToken.exp * 1000) > new Date().getTime()

    }
    return false
}
export default {
    namespaced: true,
    state: {
        user: null,
        isAuthResolved: false   // this I am calling on my login page i am confused where should I call this or not to call this
    },
    getters: {
        authUser(state) {
            return state.user
        },
        isAuthenticated(state) {
            return !!state.user
        }
    },
    actions: {
        loginWithCredentials({ commit }, userDate) {
            return axios.post('/api/v1/users/login', userDate)
                .then(res => {
                    const user = res.data
                    console.log(user.email)
                    localStorage.setItem('jwt-token', user.token)
                    commit('setAuthUser', user)
                })
        },

        logout({ commit }) {
            return new Promise((resolve, reject) => {
                localStorage.removeItem('jwt-token')
                commit('setAuthUser', null)
                resolve(true)
            })

        },

        getAuthUser({ commit, getters }) {
            const authUser = getters['authUser']
            const token = localStorage.getItem('jwt-token')
            const isTokenValid = checkTokenValidity(token)
            if (authUser && isTokenValid) {
                return Promise.resolve(authUser)
            }

            const config = {  // here what to do with this how can I pass this to protect my route
                headers: {
                    'cache-control': 'no-cache',
                    'Authorization': token
                }
            }

        }

    },
    mutations: {
        setAuthUser(state, user) {
            return state.user = user
        },
        setAuthState(state, authState) {
            return state.isAuthResolved = authState
        }
    }

In my route.js vue file

    import Vue from 'vue'
import Router from 'vue-router'
import store from './store'

Vue.use(Router)

const router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [{
        path: '/welcome',
        name: 'welcome',
        meta: { onlyAuthUser: true },
        component: () =>
            import ('./views/Welcome.vue'),


    }, ]
})
router.beforeEach((to, from, next) => {
    store.dispatch('auth/getAuthUser')
        .then((authUser) => {
            const isAuthenticated = store.getters['auth/isAuthenticated']

            if (to.meta.onlyAuthUser) {
                if (isAuthenticated) {
                    next()
                } else {
                    next({ name: 'PageNotAuthenticated' })
                }
            } else if (to.meta.onlyGuestUser) {
                if (isAuthenticated) {
                    next({ name: 'welcome' })
                } else {
                    next()
                }
            } else {
                next()
            }
        })
})

export default router

My main problem is I want to protect routes and make the user authenticated using jwt and passport I am getting jwt once I login and want to check once my protected rout is access with out login for backend.

In front end (vue.js) I my store file in action> getAuthUsers I don't know how to pass config to other routes like my welcome.

Upvotes: 2

Views: 3107

Answers (1)

Varun Agarwal
Varun Agarwal

Reputation: 1587

Not sure if I understood your question entirely because you seem to be implementing route access correctly. You simply need to add routes as an array while the rest of your code remains the same.

const router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [{
        path: '/welcome',
        name: 'welcome',
        meta: { onlyAuthUser: true },
        component: () =>
            import ('./views/Welcome.vue'),


    },
    {
        path: '/login',
        name: 'Login',
        meta: { onlyGuesUser: true },
        component: () =>
            import ('./views/Login.vue'),


    }]
})

For using Authentication: Bearer xxxxxxxx you can modify your axios code to directly use required headers instead of passing it through routes every time. Make a new folder called services and a file called base-api. You can obviously name it however you like, but this is my setup.

import axios from 'axios';

export default () => {
  let headers = {
    'cache-control': 'no-cache'
  };
  let accessToken = localStorage.getItem('jwt-token');
  if (accessToken && accessToken !== '') {
     headers.Authorization = accessToken;

  };
  return axios.create({
    baseURL: 'SECRET_URL_',
    headers: headers
  });
}

Import this file in your store.js. Replace import axios from 'axios' with import axios from '@src/services/base-api.js. As the file is returning an axios instance you need to access it as axios(). Which means you function would be

return axios().post('/api/v1/users/login', userDate)
                .then(res => {
                    // do whatever
                })

Upvotes: 2

Related Questions