stateless session api request - express

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.

Related

authorization header undefined, empty

Can you explain what I'm doing wrong, I don't understand why my header is empty. Login is working but when I trigger the me query it's not working, not authenticated appear and if I console log this it's undefined.
How to keep the user logged, and be able to acces the data ?
Here is my code, if you know what's wrong.
Thanks
import * as dotenv from 'dotenv';
dotenv.config();
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import { PrismaClient } from '#prisma/client';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
const JWT_SECRET = 'abc123';
const typeDefs = `
type User {
id: ID
username: String
}
type Query {
me: User
}
type Mutation {
signup(username: String!, password: String!): User
login(username: String!, password: String!): User
}
`;
const resolvers = {
Query: {
async me(_, __, context) {
// Check if the request has a valid JWT
const auth = context.req.headers.authorization;
if (!auth) {
throw new Error('Not authenticated');
}
// Get the user ID from the JWT
const token = auth.split('Bearer ')[1];
const { userId } = jwt.verify(token, JWT_SECRET);
// Retrieve the user from the database
return context.prisma.user({ id: userId });
},
},
Mutation: {
async signup(_, { username, password }, context) {
// Hash the password
const hashedPassword = await bcrypt.hash(password, 10);
// Create a new user in the database
const user = await context.prisma.user.create({
data: {
username,
password: hashedPassword,
},
});
// Create a JWT for the new user
const token = jwt.sign({ userId: user.id }, JWT_SECRET);
return { token, ...user };
},
async login(_, { username, password }, context) {
// Retrieve the user from the database
const user = await context.prisma.user.findUnique({
where: {
username: username,
},
});
if (!user) {
throw new Error('Invalid login');
}
// Compare the provided password with the hashed password
const valid = await bcrypt.compare(password, user.password);
if (!valid) {
throw new Error('Invalid login');
}
// Create a JWT for the user
const token = jwt.sign({ userId: user.id }, JWT_SECRET);
return { ...user, token };
},
},
};
const main = async () => {
const app = express();
const prisma = new PrismaClient();
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => ({ req, prisma }),
});
await server.start();
server.applyMiddleware({ app });
app.listen(4000, () =>
console.log(`GraphQL server running on http://localhost:4000`)
);
};
main().catch((err) => {
console.error(err);
});

is there a way to use Laravel sanctum token to be able to access protected routes (Laravel Project)

I'm building a website witch has some protected routes that I want to prevent non-authenticated users from accessing it, So I'm using Laravel Sanctum for that purpose. I was testing this using postman, but now I want to actually use it in production from backend, So how I suppose to do that token that was generated after login!
Thanks in advance.
I think the answer is late, but it may be useful to someone else
You will set your login routes
// Login Route
Route::middleware('guest')->group(function () {
Route::post('/login', LoginAction::class)->name('auth.login');
});
// Logout Route
Route::middleware('auth:sanctum')->group(function () {
Route::post('/logout', LogoutAction::class)->name('auth.logout');
});
public function __invoke(AuthRequest $request)
{
$username = $request->input('username');
$password = $request->input('password');
$remember = $request->input('remember');
// I use filter_var to know username is email or just the regular username
$field = filter_var($username, FILTER_VALIDATE_EMAIL) ? 'email' : 'username';
// User::where('username', $username)->first();
// User::where('email', $username)->first();
$user = User::where($field, $username)->first();
if (
!$user || !Hash::check($password, $user->password)
|| !Auth::attempt(
[
$field => $username,
'password' => $password
],
$remember
)
) {
// Return Error Message
return $this->error(['message' => trans('auth.failed')], Response::HTTP_UNAUTHORIZED);
}
// After Check Useranme And Password Create Token
$token = $user->createToken($request->device)->plainTextToken;
// Return Success Message With Token
return $this->success(['message' => trans('auth.login', ['user' => $user->username]), 'token' => $token, 'user' => $user]);
in vuex Actions
export const loginAction = ({ commit }, userInfo) => {
let urlParams = new URLSearchParams(window.location.search);
return new Promise((resolve, reject) => {
login(userInfo)
.then((response) => {
if (response.success) {
commit("SET_LOGIN_USER", response.payload.user);
// Set Token Mutaion
commit("SET_TOKEN", response.payload.token);
// Notify User for success logged in
Notify.create({
type: "positive",
message: `welcome ${response.payload.user.username}`,
});
// Redirect to dashboard
router.push(
urlParams.get("redirect") || { name: "dashboard" }
);
}
resolve(response);
})
.catch((error) => {
// For any error remove any auth user details and notify him
Notify.create({
type: "negative",
message: `${error.response?.data.payload}`,
});
commit("REMOVE_AUTH_DETAILS");
reject(error);
});
});
};
in vuex mutations 3 methods
// Helpers Fuctions
import { setLoginUser, setToken, removeToken, removeLoginUser } from '../../../utils/auth';
export const SET_LOGIN_USER = (state, user) => {
state.loginUser = user
setLoginUser(user)
}
export const SET_TOKEN = (state, token) => {
state.token = token
setToken(token)
}
export const REMOVE_AUTH_DETAILS = (state) => {
state.loginUser = null
state.token = null
removeLoginUser()
removeToken()
}
My Helper Functions
// I use Quasar Framework But you can use any cookie package like js-cookie
import { Cookies } from "quasar";
const TokenName = "TOKEN";
const LoginUser = "LOGIN_USER";
export function setToken(token) {
return Cookies.set(TokenName, token);
}
export function getToken() {
return Cookies.get(TokenName);
}
export function removeToken() {
return Cookies.remove(TokenName);
}
export function setLoginUser(loginUser) {
return Cookies.set(LoginUser, JSON.stringify(loginUser));
}
export function getLoginUser() {
return Cookies.get(LoginUser);
}
export function removeLoginUser() {
return Cookies.remove(LoginUser);
}
I use Vue js for frontend and axios for making requests
in axios file request.js
// It's helper function to get token from cookie
import { getToken } from "./auth";
import router from "../router";
import store from "../store";
import axios from "axios";
// Create axios instance
const service = axios.create({
baseURL: "/api/v1/",
timeout: 10000 // Request timeout
});
// Request intercepter
service.interceptors.request.use(
config => {
if (getToken()) {
config.headers["Authorization"] = "Bearer " + getToken(); // Set Token
}
return config;
},
error => {
// Do something with request error
console.log("error-axios", error); // for debug
Promise.reject(error);
}
);
// response pre-processing
service.interceptors.response.use(
response => {
return response.data;
},
error => {
// remove auth user informations from cookies and return to login page if unauthorized
if ([401].includes(error.response.status)) {
store.commit('auth/REMOVE_AUTH_DETAILS')
router.push({ name: "login" });
}
return Promise.reject(error);
}
);
export default service;
// Logout Fuction in controller or action
public function __invoke(Request $request)
{
if(! $request->user()) {
return $this->error(['message' => trans('auth.no_auth_user')]);
}
// Remove Token
$request->user()->tokens()->delete();
return $this->success([
'message' => trans('auth.logout', ['user' => auth()->user()->username])
], Response::HTTP_OK);
}
// Logout mutation (vuex)
export const logoutAction = ({ commit }) => {
return new Promise((resolve, reject) => {
logout()
.then(() => {
Notify.create({
type: "negative",
message: `see you later ${getLoginUser().username}`,
});
commit("REMOVE_AUTH_DETAILS");
router.push({ name: "login" });
resolve();
})
.catch((error) => {
router.push({ name: "login" });
commit("REMOVE_AUTH_DETAILS");
reject(error);
});
});
};
Any other help I will not be late

Passport local authentication fails on request after authenticated

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

Router export failing while exporting multiple functions (TypeError: app.use() requires a middleware function)

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}

Bcrypt + Sequelize password not saving as hash in DB

Sequelize + Bcrypt not storing passwords in DB as hash
As the title says, whenever I attempt to store a user into my SQLite DB the console outputs the password as a hash but when I look into the DB with DBbrowser I can see the plaintext password.
Model
// const Promise = require('bluebird')
const bcrypt = require('bcrypt')
async function hashPassword (user, options) {
if (!user.changed('password')) {
return 0
}
const SALT_FACTOR = 8
await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
if (err) {
console.log(err)
}
// user.setDataValue('password', hash)
user.password = hash
console.log(user)
})
}
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes.STRING,
unique: true
},
password: DataTypes.STRING
}, {
hooks: {
beforeSave: hashPassword,
beforeCreate: hashPassword
}
})
User.prototype.comparePassword = function (password) {
bcrypt.compare(password, this.password, function (res, err) {
if (res) {
console.log(res)
} else {
console.log(err)
}
})
return bcrypt.compare(password, this.password)
}
return User
}
Controllers
module.exports = {
async register (req, res) {
try {
const user = await User.create(req.body)
const userJson = user.toJSON()
res.send({
user: userJson,
token: jwtSignUser(userJson)
})
} catch (err) {
// e-mail already exists or such
res.status(400).send({
error: 'This email address is already in use'
})
}
},
async login (req, res) {
try {
// Grab user input
const { email, password } = req.body
const user = await User.findOne({
where: {
email: email
}
})
// Check to see if user is in db
if (!user) {
res.status(403).send({
error: 'the login information was incorrect / Not Found'
})
}
// Check to see if password is valid
const isPasswordValid = await user.comparePassword(password)
if (!isPasswordValid) {
return res.status(403).send({
error: 'The login information was incorrect'
})
}
// return user using toJSON()
const userJson = user.toJSON()
res.send({
user: userJson,
token: jwtSignUser(userJson)
})
} catch (e) {
res.status(500).send({ error: 'An error occured attempting to login' })
console.log(e)
}
}
}
To elaborate a little more, whenever I create a user, I receive the following:
{
"user": {
"id": 1,
"email": 'test#test.com",
"password": "$2b$08$SYYXU/GDSCFsp3MVeuqrduI0lOLHeeub7whXiaMMoVxO53YJry.1i",
"updatedAt": "2018-09-07T22:44:12.944Z",
"createdAt": "2018-09-07T22:44:12.944Z"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZW1haWwiOiJTVVBCUkhVQGxvbC5jb20iLCJwYXNzd29yZCI6IiQyYiQwOCRTWVlYVS9HRFNDRnNwM01WZXVxcmR1STBsT0xIZWV1Yjd3aFhpYU1Nb1Z4TzUzWUpyeS4xaSIsInVwZGF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImNyZWF0ZWRBdCI6IjIwMTgtMDktMDdUMjI6NDQ6MTIuOTQ0WiIsImlhdCI6MTUzNjM2MDI1MywiZXhwIjoxNTM2OTY1MDUzfQ.mDaeIikzUcV_AGTuklnLucx9mVyeScGpMym1y0kJnsg"
}
Which to me says the DB successfully hashed my password, and stored it. The overhanging issue for me with this is the fact that I believe it's causing the bcrypt.compare function to spit out 'false'. As always, any insight or help would be greatly appreciated!
I'm pretty sure that this answer is too late for you, but might help others landing on this same question.
The main issue I can see is how you are using the async/await pattern. Changing this:
async function hashPassword (user, options) {
if (!user.changed('password')) {
return 0
}
const SALT_FACTOR = 8
await bcrypt.hash(user.password, SALT_FACTOR, (err, hash) => {
if (err) {
console.log(err)
}
// user.setDataValue('password', hash)
user.password = hash
console.log(user)
})
}
to this, worked for me:
async function hashPassword(user, options) {
if (!user.changed("password")) {
return 0;
}
user.password = await bcrypt.hash(user.password, SALT_FACTOR);
}
Can you please try to add only one hook
hooks: {
beforeSave: hashPassword,
}
Because I think your password is getting hashed two times. as beforeSave and beforeCreate both hooks get executed.
Hope it helps