I'm new to Vue so don't know how I achieve the following:
I want an Axios response so I can match the response token with a locally stored token because I found that if I modify the token value in local store, the user can still navigate from any secure route.
Is there any other method to secure this?
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)){
const authUser = localStorage.getItem('authUser')
console.log(authUser);
var session='here i want axios response value'
if (!authUser===session){
console.log('here log');
next({ path: '/', })
} else {
console.log('else redirect');
next()
}
} else {
console.log('bhar else redirect');
next()
}
});
Here is my login.vue success loginpost method:
loginPost(){
var _this = this
var vm = this.hasErrors
var _vm = this.errorMessage
var log = {
companyname: this.loginData.companyname,
username: this.loginData.both,
password: this.loginData.password,
}
this.$http.post('http://localhost:3000/api/users/login', log)
.then(function (response) {
if(response.status=== 200){
this.$store.commit('authUser', response.data.id)
localStorage.setItem('authUser', response.data.id)
_this.$router.push('/authuser');
}else{
console.log('unknow');
}
})
.catch(function (error) {
var errors = error.response;
if(errors.statusText === 'Unprocessable Entity'){
if(errors.data){
if(error.response.data.error.details.messages.username){
vm.both = true
_vm.both = error.response.data.error.details.messages.username[0]
}
}
}
});
Related
I am trying to catch an error whilst the user tries to access a page without an authentication token.
axios.js?v=012beb2f:840 POST http://localhost:3001/api/get-user 422 (Unprocessable Entity)
Uncaught (in promise) AxiosError {message: 'Request failed with status code 422', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
router.beforeEach((to, from, next) => {
const store = useUserStore()
if(to.meta.requiresAuth)
{
try
{
const response = axios.post('/api/get-user', {}, {
headers: {
Authorization: `Bearer ${store.user.token}`
}
})
.then(response => {
console.log(response)
next()
})
}
catch(error)
{
console.log(error)
next('/login')
}
}
else
{
next()
}
})
Thats the code that makes the request to the server. If the token is correct it works fine. However incorrect token throws the error mentioned above. I would like it to redirect to /login page if token is incorrect.
This is the code on server side.
router.post('/get-user', signupValidation, (req, res, next) => {
if(
!req.headers.authorization ||
!req.headers.authorization.startsWith('Bearer') ||
!req.headers.authorization.split(' ')[1]
){
return res.status(422).json({
message: "Please provide the token",
});
}
const theToken = req.headers.authorization.split(' ')[1];
const decoded = jwt.verify(theToken, 'the-super-strong-secrect');
db.query('SELECT * FROM users where id=?', decoded.id, function (error, results, fields) {
if (error) throw error;
return res.send({ error: false, data: results[0], message: 'Fetch Successfully.' });
});
});
Change the synchronous try/catch...
try
{
somePromise.then(...)
}
catch(error)
{
console.log(error)
next('/login')
}
...to instead use the catch() provided by the promise:
const headers = { Authorization: `Bearer ${store.user.token}` };
axios.post('/api/get-user', {}, { headers })
.then(response => {
console.log(response)
next()
})
.catch(error => {
console.log(error)
next('/login')
}}
Note, also, that the OP code incorrectly assigned the axios.post promise to an unused variable called "response".
Alternatively, use the synchronous try/catch style with async/await:
router.beforeEach(async (to, from, next) => {
const store = useUserStore()
if(to.meta.requiresAuth)
{
try
{
const headers = { Authorization: `Bearer ${store.user.token}` };
const response = await axios.post('/api/get-user', {}, { headers });
console.log(response);
next();
}
catch(error)
{
console.log(error)
next('/login')
}
}
else
{
next()
}
})
I want to authenticate using the Passport local strategy. To be safe, I store the session in MongoDB.I am authenticating with passportjs for the first time, so if you can help me I would be very grateful.
I'm having a hard time because Factory Pattern is used in the backend I'm working on. First, the user signs up, then after the login process, the session belonging to the user is created in MongoDB. At the same time, a cookie is set on the client-side. There is no problem so far. However, when I send a request to the protected route that I created for the authenticated user, it gives an error before reaching the route. I can't find where the error is coming from.
ExpressFactory is like that
import express from "express";
import { AppContextType } from "../src/types/configTypes";
const passport = require("passport");
const session = require("express-session");
const mongoDbSession = require("connect-mongodb-session")(session);
export default async (appContext: AppContextType) => {
const app = express();
const { config } = appContext;
app.use(express.json());
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
res.header(
"Access-Control-Allow-Headers",
"Content-Type, Authorization, Content-Length, X-Requested-With"
);
res.setHeader("Access-Control-Allow-Credentials", "true");
if ("OPTIONS" === req.method) {
res.sendStatus(200);
} else {
next();
}
});
const store = new mongoDbSession({
uri: config.db,
collection: "sessions",
});
app.use(
session({
secret: "very secret this is",
resave: false,
saveUninitialized: false,
store: store,
})
);
// Passport initialize
app.use(passport.initialize());
app.use(passport.session());
app.use(
"/message",
require("../src/controllers/messageController")(appContext)
);
app.use("/user", require("../src/controllers/userController")(appContext));
//response handler, if no middleware handles
app.use((req, res) => {
res.status(404).send(Object.assign(res as any, { success: false }));
});
return new Promise((resolve) => {
const httpServer = app.listen(5000, () => {
console.log("Connected Server Port : 5000");
resolve(httpServer);
});
});
};
Then I created passportAuthFactory to create the passportjs strategy and passed the appContext inside it to connect to the database collection.Like this :
import expressFactory from "../config/expressFactory";
import configFactory from "../config/configFactory";
const clientListenerFactory = require("../config/clientListenerFactory");
const passportAuthFactory = require("../config/passportAuthFactory");
import {
EnvironmentType,
ConfigType,
AppContextType,
} from "./types/configTypes";
const config = configFactory(process.env.NODE_ENV as EnvironmentType);
import appContextFactory from "../config/appContextFactory";
const appContextPromise = appContextFactory(config as ConfigType);
module.exports = appContextPromise.then(async (appContext: AppContextType) => {
const httpServer = await expressFactory(appContext);
await clientListenerFactory(httpServer, appContext);
passportAuthFactory(appContext);
});
My PassportJs File looks like this
const bcrypt = require("bcrypt");
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
import { AppContextType } from "../src/types/configTypes";
module.exports = (appContext: AppContextType) => {
const { userService } = appContext;
passport.use(
new LocalStrategy(
{ usernameField: "email" },
(email: any, password: any, done: any) => {
userService
.getUser(email)
.then((user: any) => {
if (!user) {
return done(null, false, { message: "User not found" });
}
bcrypt.compare(
password,
user.password,
(err: any, isMatch: any) => {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: "Wrong password" });
}
}
);
})
.catch((err: any) => {
return done(null, false, { message: err });
});
}
)
);
passport.serializeUser((user: any, done: any) => {
done(null, user._id);
});
passport.deserializeUser(function (id: any, done: any) {
userService
.getUserById(id)
.then((user) => {
done(user);
console.log("Deserialize");
console.log(user);
})
.catch((err) => {
done(err);
});
});
};
Controller File as
const authMiddleware = require("../middlewares/authMiddleware");
const passport = require("passport");
require("../../config/passportAuthFactory");
module.exports = (appContext: AppContextType) => {
const { userService } = appContext;
const router = express.Router();
router.get(
"/login",
passport.authenticate("local"),
function (req: Request, res: Response) {
try {
res.status(200).send(
Object.assign(
{
isAuthenticated: req.isAuthenticated(),
user: req.user,
},
{ success: true }
)
);
} catch (err) {
res.status(400).send(Object.assign(err as any, { success: false }));
}
}
There is no problem in the first signup and the first login, but then when I test the protected delete route with the person who has the authentication, I get the error.The error I got on the second request is as follows:
500 Internal Server Error
and also this is shown on the vscode terminal console
[object Object]
What could be causing this error I would be grateful if you could help me I'm about to go crazy I've been trying to figure this out for 3 days
I'm having this odd error and I'm not knowing what to do to make it work. The thing is, I need to export some functions and express router. The thing is, if I try to set
module.exports = {router, function1, function2}
it gaves me that error
(TypeError: app.use() requires a middleware function).
If I try to set my functions with exports.function1 = async function function1 (req,res) {blablabla} they get exported but I still get the same error... I need to use the functions in this way
router.get('/api/auth0/users', async (req, res,next) => {
function1(res, next)
})
and I'm lacking ideas... and have no clue of why the multiple module.exports it's not working since I've used it a lot (seems like the problem is with the router.... (NOTE: I've just used an example code since mine is a 140 lines src)
(NOTE2: function1 and function2 are async since they make queries to MongoDB)
UPDATE: (Adding the import codes)
I import it in my main .js file like this
const {router} = require('./auth/auth0')
then tell app to use it like this
app.use(router);
app is defined using this lines
const express = require("express");
const app = express();
changing the export/import name to another like authRouter or something makes no difference.
Heres the complete code:
const router = require('express').Router()
const express = require('express')
const passport = require('passport');
const session = require('express-session')
const {generateJwt} = require("../helpers/generateJwt");
const usuarios = require('../models/usuarios')
let OpenIDConnectStrategy = require('passport-openidconnect');
passport.serializeUser(function (user, cb) {
cb(null, user);
});
passport.deserializeUser(function (obj, cb) {
cb(null, obj);
});
passport.use(new OpenIDConnectStrategy({
issuer: 'https://' + process.env.AUTH0_DOMAIN + '/',
authorizationURL: 'https://' + process.env.AUTH0_DOMAIN + '/authorize',
tokenURL: 'https://' + process.env.AUTH0_DOMAIN + '/oauth/token',
userInfoURL: 'https://' + process.env.AUTH0_DOMAIN + '/userinfo',
clientID: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
callbackURL: '/login/callback',
scope: [ 'profile', 'email' ]
},
function verify(issuer, profile, cb) {
if(profile){
userEmail = profile.emails[0].value
userProfile = profile
whoIs = profile.id
}
return cb(null,profile)
}
));
router.use(express.json())
router.use(session({ secret: 'keyboard cat~troubles', secured:true, key: 'sid', saveUninitialized: true, resave: false}));
router.use(passport.initialize())
router.use(passport.session())
var userProfile = ""
let userEmail = ""
let whoIs = ""
let token = ""
async function createUser(res,next) {
try {
token = await generateJwt(whoIs, process.env.JWT_SECRET_KEY);
const nAccount = new usuarios({
nombre: userProfile.name.givenName,
apellido: userProfile.name.familyName,
auth0Id: whoIs,
email: userEmail,
token: token
});
await nAccount.save()
return res.status(201).json({Status: "Cuenta creada exitosamente", token: token});
} catch (error) {
console.log(error)
return res.redirect('/api/auth0/logged')
}
}
async function findUser(res, next){
try{
let email = userEmail
let mailEncontrado = await usuarios.findOne( {email} )
if (!mailEncontrado ){
return res.redirect('/api/auth0/register')
}
else {
token = await generateJwt(whoIs, process.env.JWT_SECRET_KEY);
let userID = await usuarios.findOneAndUpdate(
{email},
{ nombreAuth0: userProfile.name.givenName,
apellidoAuth0: userProfile.name.familyName,
auth0Id: whoIs,
token: token},
{ new: true }
)
return res.redirect('/api/auth0/logged')
}
}
catch (err) {
console.log(err)
}
}
async function userAuthenticated(res, next) {
if( req.isAuthenticated() === true){
console.log(req.isAuthenticated())
return true
} else{
console.log(req.isAuthenticated())
return false
}
}
router.get('/api/auth0/login', passport.authenticate('openidconnect',{prompt: 'login', failureMessage: true}));
router.get('/api/auth0/users', async (req, res,next) => {
findUser(res, next)
})
router.get('/api/auth0/register', async (req, res,next) => {
createUser(res, next)
})
router.get('/login/callback', passport.authenticate('openidconnect', {
successRedirect: '/api/auth0/users',
failureRedirect: '/api/auth0/login'
}));
router.get('/api/auth0/logged', (req, res) => {
if(whoIs === ""){
return res.status(401).json('Error de autenticacion')
}
else {
console.log(whoIs)
return res.status(201).json({Status: 'Usuario logueado. ID = '+ whoIs, Token: token, Email: userEmail})
}
})
router.get('/api/auth0/logout', (req, res) => {
if(!req.user){
res.json("No hay usuario autenticado")
}
req.logout()
res.status(201).json("Sesion finalizada exitosamente.")
})
module.exports = {router, userAuthenticated}
I'm using a static array to scaffold a user table, prior to refactoring with actual postgres db and some fetch()-ing code. At present, the tests work, but obviously they are working synchronously. Here's the placeholder API code:
// UserAPI.js
let findUserById = (credentials = {}) => {
const { userId } = credentials
if (userId) {
const foundUser = users.find(user => user.id === userId)
if (foundUser !== undefined) {
const { password: storedpassword, ...user } = foundUser
return user
}
}
return null
}
exports.byId = findUserById
And an example test as follows:
// excerpt from TokenAuth.test.js
const UserAPI = require('../lib/UserAPI')
describe('With TokenAuth middleware', () => {
beforeEach(() => {
setStatus(0)
})
it('should add user to req on authorised requests', () => {
const token = createToken(fakeUser)
const authReq = { headers: { authorization: 'Bearer ' + token } }
const myMiddleware = TokenAuth(UserAPI.byId)
myMiddleware(authReq, fakeRes, fakeNext)
// expect(authReq.user).toStrictEqual({ id: 1, username: 'smith#example.com' });
expect(authReq.user.username).toStrictEqual('smith#example.com')
expect(authReq.user.id).toStrictEqual(1)
})
})
This runs fine, and along with other tests gives me the coverage I want. However, I now want to check that the tests will deal with the async/await nature of the fetch() code I'm going to use for the proper UserAPI.js file. So I re-write the placeholder code as:
// UserAPI.js with added async/await pauses ;-)
let findUserById = async (credentials = {}) => {
const { userId } = credentials
// simulate url resolution
await new Promise(resolve => setTimeout(() => resolve(), 100)) // avoid jest open handle error
if (userId) {
const foundUser = users.find(user => user.id === userId)
if (foundUser !== undefined) {
const { password: storedpassword, ...user } = foundUser
return user
}
}
return null
}
exports.byId = findUserById
... at which point I start getting some lovely failures, due I think it's returning unresolved promises.
My problem is two-fold:
How should I alter the UserAPI.test.js tests to deal with the new async nature of findUserByCredentials() ?
Am I ok in my assumption that ExpressJS is happy with async functions as request handlers? Specifically, due to the async nature ofUserAPI.findUserByCredentials is this ok?
Main App.js uses curried UserAPI.byId() for the findUserById.
// App.js (massively simplified)
const express = require('express')
const TokenAuth = require('./middleware/TokenAuth')
const RequireAuth = require('./middleware/RequireAuth')
const UserAPI = require('./lib/UserAPI')
let router = express.Router()
const app = express()
app.use(TokenAuth(UserAPI.byId))
app.use(RequireAuth)
app.use('/users', UserRouter)
module.exports = app
My TokenAuth middleware would now run along these lines:
// TokenAuth.js (simplified)
const jwt = require('jsonwebtoken')
require('dotenv').config()
const signature = process.env.SIGNATURE
let TokenAuth = findUserById => async (req, res, next) => {
let header = req.headers.authorization || ''
let [type, token] = header.split(' ')
if (type === 'Bearer') {
let payload
try {
payload = jwt.verify(token, signature)
} catch (err) {
res.sendStatus(401)
return
}
let user = await findUserById(payload)
if (user) {
req.user = user
} else {
res.sendStatus(401)
return
}
}
next()
}
module.exports = TokenAuth
A partial answer us simply to add an async/await on the middleware call:
it('should add user to req on authorised requests', async () => {
const token = createToken(fakeUser)
const authReq = { headers: { authorization: 'Bearer ' + token } }
const myMiddleware = TokenAuth(UserAPI.byId)
await myMiddleware(authReq, fakeRes, fakeNext)
// expect(authReq.user).toStrictEqual({ id: 1, username: 'smith#example.com' });
expect(authReq.user.username).toStrictEqual('smith#example.com')
expect(authReq.user.id).toStrictEqual(1)
})
I am building a simple app that uses JWT for authentication. But I keeps on getting the error saying the route I GET to require a call back function.
What do I expect?
I should be getting the current user's data back.
What do I actually get?
Error: Route.get() requires a callback function but got a [object Object]
Route:
const authenticate = require("../middlewares/authenticate");
const usersController = require("../controllers").users;
app.get("/users/me", authenticate, usersController.getMe);
Model:
"use strict";
const jwt = require("jsonwebtoken");
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define(
"User",
{
email: DataTypes.STRING,
password: DataTypes.STRING
},
{
classMethods: {
associate: function(models) {
// associations can be defined here
},
findByToken: function(token) {
const User = this;
let decoded;
try {
decoded = jwt.verify(token, "leogoesger");
} catch (e) {
console.log(e);
}
return User.find({ where: { email: decoded.email } });
}
}
}
);
return User;
};
Middleware:
const { User } = require("../models/user");
const authenticate = (req, res, next) => {
console.log("called here");
const token = req.header("x-auth");
User.findByToken(token)
.then(user => {
if (!user) {
}
req.user = user;
req.token = token;
next();
})
.catch(e => {
res.status(401).send(e);
});
};
module.exports = { authenticate };
Controller:
module.exports = {
getMe(req, res) {
res.status(200).send({ message: "hello" });
}
};
Your authenticate module exports an object, yet you do this:
const authenticate = require("../middlewares/authenticate");
which means your const authenticate is an object, not your function. Change that to this:
const authenticate = require("../middlewares/authenticate").authenticate;
Or, change the module to export the function directly instead of exporting an object with the function in it.