For whatever reason, the token generated by jsonwebtoken never expires.
Here is my code so far.
auth.ts Middleware.
// Libs
import { Express, Request, Response, NextFunction } from "express";
import { PassportStatic } from "passport";
import { Strategy as JWTStrategy, ExtractJwt } from "passport-jwt";
// Users
import { usersDB } from "../users";
const setupAuth = (api: Express, passport: PassportStatic) => {
const strategy = new JWTStrategy(
{
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: "123456qwerty",
algorithms: ["HS256"],
},
(payload, cb) => {
try {
const { sub } = payload;
const user = usersDB.find((u) => u.username === sub);
if (user) {
return cb(null, user);
} else {
return cb(null, false);
}
} catch (e) {
return cb(e);
}
}
);
api.use(passport.initialize());
passport.use(strategy);
};
export default setupAuth;
Login route
import { Request, Response } from "express";
import { usersDB, validatePassword } from "../../users";
import { genJWT } from "../../utils/auth";
const login = (req: Request, res: Response) => {
const { username, password } = req.body;
const user = usersDB.find((u) => u.username === username);
if (!user) {
return res
.status(401)
.json({ status: "fail", message: "Invalid username or password" });
}
if (!validatePassword(password, user.salt, user.hash)) {
return res
.status(401)
.json({ status: "fail", message: "Invalid username or password" });
}
const token = genJWT(user.username);
res.status(200).json({ status: "success", token });
};
export default login;
And the jwt token generator
import jwt from "jsonwebtoken";
export const genJWT = (username: string) => {
const token = jwt.sign({ sub: username, iat: Date.now() }, "123456qwerty", {
expiresIn: "1min",
algorithm: "HS256",
});
return token;
};
Then the secured routes
// Lib
import { Express } from "express";
import { PassportStatic } from "passport";
// GET
import root from "./GET/root";
import currentUser from "./GET/current-user";
import privateContent from "./GET/private-content";
// POST
import register from "./POST/register";
import login from "./POST/login";
import logout from "./POST/logout";
const setupRoutes = (api: Express, passport: PassportStatic) => {
api.get("/", root);
api.get(
"/current-user",
passport.authenticate("jwt", { session: false }),
currentUser
);
api.get(
"/private-content",
passport.authenticate("jwt", { session: false }),
privateContent
);
api.post("/register", register);
api.post("/login", login);
api.post("/logout", logout);
};
export default setupRoutes;
So the API is working, able to generate jwt token, able to authenticate with the token. It is able to validate too if I modify the token. But the problem is I can forever use the token. It never expires.
Is there something I missed?
Thanks in advance.
Ok when I removed
iat: Date.now()
from the jwt.sign, now the token does expire. So never put iat, let jsonwebtoken generate it.
Related
Hi guys i am newbie in react js, i have a problem about getting data from server side and routing in reactjs, i am using axios and jsonwebtoken to get the data, but it's not working,
i have check the inspect from browser and there's no error in there, but my website is still not responding
maybe you can help me to fix this problem
thanks in advance
Here is my code from "AuthController.js"
import UserModel from "../Models/userModel.js";
import bcrypt from 'bcrypt'
import jwt from "jsonwebtoken";
// Registering a new User
export const registerUser = async (req, res) => {
const { username, password, firstname, lastname } = req.body
const salt = await bcrypt.genSalt(10)
const hashedPass = await bcrypt.hash(password, salt)
// req.body.passowrd = hashedPass
const newUser = new UserModel({
username,
password: hashedPass,
firstname,
lastname
})
try {
// check username
const oldUser = await UserModel.findOne({ username })
if (oldUser) {
return res.status(400).json({ message: "The username is already exist" })
}
const user = await newUser.save()
const token = jwt.sign({
username: user.username, id: user._id
}, process.env.JWT_KEY, { expiresIn: '1h' })
res.status(200).json({ user, token })
} catch (error) {
res.status(500).json({ message: error.message })
}
};
// login user
export const loginUser = async (req, res) => {
const { username, password } = req.body;
try {
const user = await UserModel.findOne({ username: username })
if (user) {
const validity = await bcrypt.compare(password, user.password);
validity ? res.status(200).json(user) : res.status(400).json("Wrong Password")
const token = jwt.sign(
{ username: user.username, id: user._id },
process.env.JWTKEY,
{ expiresIn: "1h" }
);
res.status(200).json({ user, token });
} else {
res.status(404).json("User not found");
}
} catch (error) {
res.status(500).json({ message: error.message })
}
}
here is my Auth Reducer
const authReducer = (state = { auhtData: null, loading: false, error: false }, action) => {
switch (action.type) {
case "AUTH_START": return { ...state, loading: true, error: false };
case "AUTH_SUCCES":
localStorage.setItem("profile", JSON.stringify({ ...action?.data }))
return { ...state, authData: action.data, loading: false, error: false };
case "AUTH_FAIL": return { ...state, loading: false, error: true }
default: return state;
}
}
export default authReducer
my Auth action
import * as AuthApi from '../api/AuthRequests.js';
export const logIn = (formData) => async (dispatch) => {
dispatch({ type: "AUTH_START" });
try {
const { data } = await AuthApi.logIn(formData);
dispatch({ type: "AUTH_SUCCESS", data: data });
} catch (error) {
console.log(error);
dispatch({ type: "AUTH_FAIL" });
}
};
export const signUp = (formData) => async (dispatch) => {
dispatch({ type: "AUTH_START" })
try {
const { data } = await AuthApi.signUp(formData)
dispatch({ type: "AUTH_SUCCES", data: data })
} catch (error) {
console.log(error)
dispatch({ type: "AUTH_FAIL" })
}
}
my Auth Request for API
import axios from 'axios'
const API = axios.create({ baseURL: "http://localhost:5000" });
export const logIn = (formData) => API.post('/auth/login', formData);
export const signUp = (formData) => API.post('/auth/register', formData);
here is my index.js
import express from "express";
import bodyParser from "body-parser";
import mongoose from "mongoose";
import dotenv from 'dotenv';
import cors from 'cors'
import AuthRoute from './Routes/AuthRoute.js'
import UserRoute from './Routes/UserRoute.js'
import PostRoute from './Routes/PostRoute.js'
//Routes
const app = express();
// Middleware
app.use(bodyParser.json({
limit: '30mb', extended: true,
}))
app.use(bodyParser.urlencoded({
limit: '30mb', extended: true,
}))
app.use(cors())
dotenv.config();
mongoose.connect(process.env.MONGO_DB, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => app.listen(process.env.PORT, () => console.log(`Listening to ${process.env.PORT}`)))
.catch((error) => console.log(error));
// usage of routes
app.use('/auth', AuthRoute)
app.use('/user', UserRoute)
app.use('/post', PostRoute)
It's probably because of validity ? res.status(200).json(user) : res.status(400).json("Wrong Password"). You are sending a response multiple times.
Try with:
export const loginUser = async (req, res) => {
const { username, password } = req.body;
try {
const user = await UserModel.findOne({ username: username })
if (user) {
const validity = await bcrypt.compare(password, user.password);
if (!validity) return res.status(400).json("Wrong Password");
const token = jwt.sign(
{ username: user.username, id: user._id },
process.env.JWTKEY,
{ expiresIn: "1h" }
);
res.status(200).json({ user, token });
} else {
res.status(404).json("User not found");
}
} catch (error) {
res.status(500).json({ message: error.message })
}
}
var passport = require("passport");
var passportJWT = require('passport-jwt');
var User = require("../models/user");
var config = require('../config');
var ExtractJwt = passportJWT.ExtractJwt;
var Strategy = passportJWT.Strategy;
var opts = {
secretOrKey: config.secret,
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
}
module.exports = function () {
var strategy = new Strategy(opts, function(payload, done) {
User.findById(payload.id, function(err, user) {
if (user) {
return done(null, {id: user.id, payload: user});
}else {
return done(new Error("User not found"), null);
}
});
});
passport.use(strategy);
return {
initialize: function() {
return passport.initialize();
},
authenticate: function () {
const a = passport.authenticate("jwt", {session: false});
return a;
}
};
};
You can use Passport and middleware.
Also it seems your process.env.JWTKEY is missing.
So please check the value via console.log(process.env.JWTKEY)
hy am building an forum in next js using httponly cookie for jwt authantication but get this error
this is my auth middleware
import jwt from "jsonwebtoken";
import createError from "http-errors";
import Cookies from "cookies";
/**
* #param {import('next').NextApiRequest} req
* #param {import('next').NextApiResponse} res
*/
module.exports = (req, res, next) => {
const cookies = new Cookies(req, res);
const token = cookies.get("token");
console.log(token);
// const { cookies } = req;
// const token = cookies.token;
if (!token) return next(createError("Unauthorized"));
try {
const user = jwt.verify(token, process.env.NEXT_PUBLIC_JWT);
req.user = user;
console.log(req.user);
next();
} catch (error) {
return next(createError("Login to gain access "));
}
};
this my api to get questions posted by user
import nextConnect from "next-connect";
import connect from "../../../utils/connectMongo";
import Question from "../../../models/question";
import auth from "../../../middleware/auth";
import Cookies from "cookies";
/**
* #param {import('next').NextApiRequest} req
* #param {import('next').NextApiResponse} res
*/
connect();
const apiRoute = nextConnect({
onError(error, req, res) {
res.status(501).json({ error: ` ${error.message}` });
console.log(error);
},
onNoMatch(req, res) {
res.status(405).json({ error: `Method '${req.method}' Not Allowed` });
},
});
apiRoute.use(auth);
apiRoute.get(async (req, res, next) => {
console.log(req.cookies);
try {
const { _id } = req.user;
console.log(req.user);
let { page, size } = req.query;
const limit = parseInt(size);
const skip = (page - 1) * size;
const question = await Question.find({ user: _id })
.limit(limit)
.skip(skip)
.populate("user", "name picture")
.sort({ createdAt: -1 });
res.status(200).json({
success: true,
data: question,
});
} catch (error) {
console.log(error);
res.status(400).json({ success: false });
}
});
// export const config = {
// api: {
// bodyParser: false, // Disallow body parsing, consume as stream
// },
// };
export default apiRoute;
in postman api works fine but in axios it says Unauthorized form auth middleware
my axios configs are
this is how i made req to server
export async function getStaticProps(page, size) {
const response = await instance.get(
`${baseUrl}/api/question/userquestion`,
{ withCredentials: true }
);
const questions = await response.data.data;
return {
props: {
questions,
},
};
}
enter image description here
Good morning people
I am setting up the front-end for testing, In my application I use Passport, Token Jwt for authentication. At Postman, everything is ok! I can authenticate myself.
Now in the Browser, I log in it generates the token, however when trying to execute a route protected by the passport it returns me unauthorized
Follow my code. I'm a beginner, first post on the stackoverflow.
Routes.js
app.route('/rifas')
.all(app.config.passport.authenticate())
.post(app.api.rifas.saverifa)
Passport.js
const authSecret = process.env.authSecret
const passport = require('passport')
const passportJwt = require('passport-jwt')
const { Strategy, ExtractJwt } = passportJwt
module.exports = app => {
const options = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: authSecret
}
const strategy = new Strategy(options,(payload, done) => {
app.db('users')
.where({id: payload.id})
.first()
.then( user => {
if(user) {
done(null, {id: user.id, email: user.email})
}
else {
done(null,false)
}
})
.catch(err => done(err,false))
})
passport.use(strategy)
return {
initialize: () => passport.initialize(),
authenticate: () => passport.authenticate('jwt', {session: false})
}
}
Archive api.js
import axios from 'axios'
const api = axios.create({
baseURL: 'localhost:3333',
})
export default api
Archive of front-end
async function handleLogin (e) {
e.preventDefault()
try {
const {data: token} = await axios.post('http://localhost:3333/signin', {
name: name,
email: email,
password: password
})
api.defaults.headers.Authorization = `Bearer ${token}`
window.location.href="http://localhost:3000/Header"
alert(`Logado com sucesso ${name}`)
}catch(e) {
alert('Erro no login')
}
}
am using angular 6 and express when am developing this api on authentcate uri it returning Http failure response for http://localhost:3000/api/authenticate: 404 Not Found
i have tried removing of the responses on my user.controller.js but the problem persisits it seems am missing out some point here and i dont know here it is at first i got an error saaying cant send headers after they are sent and the error was on my user.controller.js on this line else return res.status(404).json(info);
Here is my user.controller.js
const mongoose = require('mongoose');
const User = mongoose.model('User');
const passport = require('passport');
const _ = require('lodash');
module.exports.register = (req,res, next) => {
const user = new User();
user.fullname = req.body.fullname;
user.email = req.body.email;
user.College = req.body.College;
user.Department = req.body.Department;
user.password = req.body.password;
user.admintype = req.body.admintype;
user.save((err, doc) => {
if(!err) { res.send(doc)}
else
{
if(err.code == 11000)
res.status(422).send(['Duplicate email Address Found.'])
else
return next(err);
}
})
}
module.exports.authenticate = (req, res, next ) => {
//calll for passport authentication
passport.authenticate('local', (err, user, info) => {
//error form paasport middleware
if(err) return res.status(400).json(err);
//registered user
else if (user) return res.status(200).json({ "token":user.generateJwt() });
//unknown user or wrong password
else return res.status(404).json(info);
})(req, res);
}
module.exports.userProfile = (req, res, next) =>{
User.findOne({ _id:req._id},
(err,user) =>{
if(!user)
return res.status(404).json({ status: false, message : 'User Record not Found. '});
else
return res.status(200).json({ status:true , user : _.pick(user, ['fullname','email','university','College','Department','admintype'])});
} );
}
Here is my user.service.ts
```import { Injectable } from '#angular/core';
import { User } from './user.model';
import{ HttpClient, HttpHeaders } from '#angular/common/http';
import{ environment } from '../../environments/environment';
import { from } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class UserService {
selectedUser: User = {
fullname:'',
email:'',
university:'',
College:'',
Department:'',
password:'',
admintype:''
};
constructor(private http: HttpClient) { }
postUser(user:User)
{
return this.http.post(environment.apiBaseUrl+ '/register' ,user)
}
login(authCredentials)
{
return this.http.post(environment.apiBaseUrl+ '/authenticate',authCredentials);
}
setToken(token:string)
{
localStorage.setItem('token',token);
}
}```
Here is my sign-in.components.ts
```import { Component, OnInit } from '#angular/core';
import { NgForm } from '#angular/forms';
import { UserService } from 'src/app/shared/user.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-sign-in',
templateUrl: './sign-in.component.html',
styleUrls: ['./sign-in.component.css']
})
export class SignInComponent implements OnInit {
constructor( private userService:UserService, private router:Router) { }
model = {
email:'',
password:''
};
emailRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
serverErrorMessages : string;
ngOnInit() {
}
onSubmit(form :NgForm)
{
this.userService.login(form.value).subscribe(
res =>{
this.userService.setToken(res['token']);
this.router.navigateByUrl('/signup');
},
err =>{
this.serverErrorMessages = err.message;
});
}
}```
Here is my environment.ts
```/ This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false,
apiBaseUrl:'http://localhost:3000/api'
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.```
Here is my auth.js
```const router = require('express').Router();
const User = require('../controller/model/User');
const ctrlUser = require('../controller/user.controller');
const jwthelper = require('../jwtHelper')
//validation
router.post('/register', ctrlUser.register);
router.post('/authenticate',ctrlUser.authenticate);
router.get('/userProfile',jwthelper.verifyJwtToken,ctrlUser.userProfile);
module.exports = router;```
Here is my index.js
```const express = require('express');
const app = express();
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const cors = require('cors')
const bodyParser = require('body-parser');
require('./passportConfig');
const passport = require('passport');
dotenv.config();
//connect to mongodb
mongoose.set('useFindAndModify', false); mongoose.set('useUnifiedTopology', true);
mongoose.connect(process.env.DB_CONNECT,{ useNewUrlParser:true} , () =>
console.log('connected to db!')
);
//import routes
const authRoute = require('./routes/auth');
//middleware
app.use(bodyParser.json());
app.use(cors());
app.use(passport.initialize());
//error handler
app.use((err, req, res, next) =>{
if(err.name =='ValidationError')
{
var valErrs = [];
Object.keys(err.errors).forEach(key => valErrs.push(err.errors[key].message));
res.status(422).send(valErrs);
next();
}
});
//route middleware
app.use('/api',authRoute);
app.listen(3000, () => console.log("server Up and Running"));```
Any Help please on this one please thank you all
The only thing which is remain is to attach the router which you have define in the auth.js file to your express app like this
const authRouter = require('./auth');
And to prefix all routes define in the auth.js file you attach it as a middleware which is trigger on route prifix with \api
const express = require('express');
const app = express();
// define all your middleware and all other route
// and here you attach the auth router
app.use('\api', authRouter);
This will make authentication available on url http://localhost:3000/api/authenticate
You may also get 404 because of this line in authenticate route (by the way I think this must be a 400 - bad request, not 404, which is making confusion.)
else return res.status(404).json(info);
So to understand this, can you replace your authenticate route like this, and see what logs in the api console:
module.exports.authenticate = (req, res, next ) => {
console.log("req.body: ", req.body)
//calll for passport authentication
passport.authenticate('local', (err, user, info) => {
//error form paasport middleware
if(err) return res.status(400).json(err);
//registered user
else if (user) return res.status(200).json({ "token":user.generateJwt() });
//unknown user or wrong password
else {
console.log("info: ", info)
return res.status(400).json(info);
}
})(req, res);
Also it the angular component, can you change your onSubmit like this for easy debug:
be sure your form.value is correct:
onSubmit(form :NgForm)
{
console.log("form.value: ", form.value);
this.userService.login(form.value).subscribe(
res =>{
this.userService.setToken(res['token']);
this.router.navigateByUrl('/signup');
},
err =>{
console.log("err: ", err.message)
this.serverErrorMessages = err.message;
});
}
THE app is suppose to register the new user and send the new users info to the MongoDB, but when i attempt to register the user it throws an error of 500 internal error. the console says the error is in the user file, the terminal say this is the error, Proxy error: Could not proxy request /api/users from localhost:3000 to https://localhost:5000.
[1] See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (EPROTO).
I've already tried changing the proxy in the packet.json by giving it a different path and target but its not working. maybe i'm overlooking something. enter code here
import React, { useReducer } from 'react';
import axios from 'axios';
import AuthContext from './authContext';
import authReducer from './authReducer';
import {
REGISTER_SUCCESS,
REGISTER_FAIL,
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT,
CLEAR_ERRORS
} from '../types';
const AuthState = props => {
//initial state
const initialState = {
token: localStorage.getItem('token'),
isAuthenticated: null,
user: null,
loading: true,
error: null
};
const [ state, dispatch ] = useReducer(authReducer, initialState);
// load user
const loadUser = () => console.log('load user') ;
// register user
const register = async formData => {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
try {
const res = await axios.post('api/users', formData, config);
dispatch({
type: REGISTER_SUCCESS,
payload: res.data
});
} catch (err){
dispatch({
type: REGISTER_FAIL,
payload: err.response.data.msg
});
}
}
// login user
const login = () => console.log('login') ;
//logut
const logout = () => console.log('logout') ;
// clear errors
const clearErrors = () => console.log('clearErrors') ;
return (
<AuthContext.Provider
value= {{
token: state.token,
isAuthenticated: state.isAuthenticated,
loading: state.loading,
user: state.user,
error: state.error,
register,
loadUser,
login,
logout,
clearErrors
}}>
{props.children}
</AuthContext.Provider>
);
};
export default AuthState;
//this is my server.js file with the routes
const express = require('express');
const connectDB = require('./config/db')
//connect MongoDB
connectDB();
const app = express();
//init middleware
app.use(express.json({extended: false}));
app.get('/', (req, res) => res.json({ msg: 'hello welcome'})
);
//define routes
app.use('/api/users', require('./routes/users'));
app.use('/api/auth', require('./routes/auth'));
app.use('/api/contacts', require('./routes/contacts'))
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`server is working on ${PORT}`))
// this is mongoDB code
const mongoose = require('mongoose');
const config = require('config');
const db = config.get('mongoURI');
const connectDB = async () =>{
try{ await
mongoose.connect(db, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false
});
console.log('mongo connected..')
} catch (err){
console.log(err.message);
process.exit(1)
}
};
module.exports = connectDB;
// this the users file where the console is throwing the 500 internal error.
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('config');
const { check, validationResult } = require('express-validator');
const User = require('../models/User')
// This route Post request to api/users,
// description register a user,
// access to public to register an become a user
router.post('/', [
check('name', 'Name is require').not().isEmpty(),
check('email', 'please include email').isEmail(),
check('password', 'enter a password with atleast 6 characters'
).isLength({min: 6})
],
async (req, res) =>{
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({ errors: errors.array()});
}
const { name, email, password } = req.body;
try{
let user = await User.findOne({email});
if(user){
return res.status(400).json({msg: 'user already exist'})
}
user = new User({
name,
email,
password
});
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
// object to send in the token
const payload = {
user: {
id: user.id
}
}
jwt.sign(payload, config.get('jwtSecret'), {
expiresIn: 36000
}, (err, token) => {
if(err) throw err;
res.json({token});
});
} catch (err){
console.log(err.message);
res.status(500).send('server error')
}
});
module.exports = router;
I figure out the problem!!!
I had an unexpected token in my users file that simple colon was interfering with the code