having trouble getting user authorization variables working - node.js

In am having trouble passing the token information to my controller for authorization. In the below code, I have console logged the relevant information and I am able to get the token correctly, and the decoded information, but not the req.user information. When I console.log for that information I receive null, and when I console.log for decoded.id, I get undefined. I believe this is what is hanging up my authorization, however I'm not sure what to look at to fix it? Any thoughts very helpful!
Here's a github link:https://github.com/roxanneweber/projectmanager
const jwt = require('jsonwebtoken');
const asyncHandler = require('express-async-handler');
const User = require('../models/userModel');
const protect = asyncHandler(async (req, res, next) => {
let token;
if (
req.headers.authorization &&
req.headers.authorization.startsWith('Bearer')
) {
try {
// Get token from header
token = req.headers.authorization.split(' ')[1];
console.log(token);
// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET);
console.log(decoded);
// Get user from token
req.user = await User.findById(decoded.id).select('-password');
console.log(req.user);
console.log(decoded.id);
next();
} catch (error) {
console.log(error);
res.status(401);
throw new Error('Not authorized');
}
}
if (!token) {
res.status(401);
throw new Error('Not authorized');
}
});
module.exports = { protect };

hi i am handling the token like this in my auth.middleware.ts
import jwt from 'jsonwebtoken';
export default function (req, res, next) {
try {
const token = req.headers.authorization.split(' ')[1];
const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
// add userData object to request
req.userData = {
email: decodedToken.email,
userId: decodedToken.userId,
username: decodedToken.username,
role: decodedToken.role,
};
next();
} catch (error) {
return res.status(401).json({
message: 'not authenticated',
});
}
}
then my frontend handles setting the token like this:
import { HttpInterceptor, HttpRequest, HttpHandler, HttpHeaders } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { AuthenticationService } from '../services/authentication.service';
export interface HttpConfig {
body?: any;
headers?: HttpHeaders;
observe?: any;
}
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthenticationService) {}
intercept(req: HttpRequest<any>, next: HttpHandler) {
const authToken = this.authService.getToken();
const authRequest = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + authToken),
});
return next.handle(authRequest);
}
}
then i am using the auth.middleware.ts in my backend route files like this:
import express from 'express';
import authMiddleware from '../middleware/auth.middleware';
import FooController from './foo.controller';
class FooRoutes {
router = express.Router();
fooController = FooController;
constructor() {
this.configureRoutes();
}
configureRoutes() {
this.router.post('/foo/start', authMiddleware, this.fooController.start);
this.router.put('/foo/stop/:id', authMiddleware, this.fooController.stop);
this.router.get('/foo/:userId', authMiddleware, this.fooController.getAll);
this.router.delete('/foo/delete/:id', authMiddleware, this.fooController.delete);
}
}
export default new FooRoutes().router;

Related

How can I make an "isAdmin" verification middleware?

I have an authentication middleware, where I check through my route if the user is authenticated in the header with the security token
middlewareAuth
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
interface TokenPayload {
id: string;
iat: number;
exp: number;
}
export default async function authMiddleware(
req: Request, res: Response, next: NextFunction
) {
const { authorization } = req.headers;
if (!authorization) {
return res.status(401).json('Invalid Authorization');
};
const token = authorization.replace('Bearer', ' ').trim();
try {
const secret = process.env.JWT_SECRET as string;
const data = jwt.verify(token, secret);
const { id } = data as TokenPayload;
req.userId = id;
return next();
} catch (err) {
return res.status(401).json(err);
}
}
I import this middleware in my route, thus verifying as I describe below:
import { Router } from "express";
import CreatePost from "../controllers/postControllers/CreatePost";
import authMiddleware from "../middlewares/AuthMiddlewares";
const router = Router();
router.post('/', authMiddleware, CreatePost.store);
export default router;
Within my user entity, I have a boolean called "isAdmin" which by default returns false. I would like a middleware that checks if also within my profile isAdmin is true and thus authenticate and put in the route along with AuthMiddleware. For that I tried to import my AuthMiddleware and verify, but without success.
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import authMiddleware from './AuthMiddlewares';
export default async function authAdminMiddleware(
req: Request, res: Response, next: NextFunction,
) {
authMiddleware(req, res, () => {
if (req.userId.isAdmin) {
next();
} else {
res.status(403).json("You are not alowed to do that!");
}
})
}
Property 'isAdmin' does not exist on type 'string'.ts(2339)
What would be the most effective way to create this middleware? Can anyone give me some help? Thanks

React Application error "The server responded with error 401 (unauthorized) "

I am working on a user registration project on ReactJS and got stuck on a problem when I try to activate the user account. The backend server is giving me the error 401: Failed to load resource: the server responded with a status of 401 (Unauthorized). What might be the problem here, I was not able to find out any solution related to my code, can anyone help ??
Here is my code for Activation.jsx:
import React, { useState, useEffect } from 'react';
import authSvg from '../assests/welcome.svg';
import axios from 'axios';
import jwt_decode from 'jwt-decode';
import { isAuth } from '../helpers/auth';
import { Navigate , useParams} from 'react-router-dom';
const Activate = ({ match }) => {
const [formData, setFormData] = useState({
name: '',
token: '',
show: true
});
match = useParams();
useEffect(() => {
let token = match.token;
console.log(token);
let { name } = jwt_decode(token);
if (token) {
setFormData({ ...formData, name, token });
}
console.log(token, name);
}, [match.params]);
const { name, token, show } = formData;
const handleSubmit = e => {
e.preventDefault();
axios
.post(`${process.env.REACT_APP_API_URL}/activation`, {
token
})
.then(res => {
setFormData({
...formData,
show: false
});
console.log(res.data.message);
})
.catch(err => {
console.log(err);
});
};
Here is the code from activation controller :
const User = require('../models/auth.model');
const expressJwt = require('express-jwt');
const _ = require('lodash');
const { OAuth2Client } = require('google-auth-library');
const fetch = require('node-fetch');
const { validationResult } = require('express-validator');
const jwt_decode = require('jwt-decode')
const { errorHandler } = require('../helpers/dbErrorHandling');
const nodemailer = require('nodemailer')
exports.activationController = (req, res) => {
const { token } = req.body;
if (token) {
jwt_decode.verify(token, process.env.JWT_ACCOUNT_ACTIVATION, (err, decoded) => {
if (err) {
console.log('Activation error');
return res.status(401).json({
errors: 'Expired link. Signup again'
});
} else {
const { name, email, password } = jwt_decode(token);
console.log(email);
const user = new User({
name,
email,
password
});
user.save((err, user) => {
if (err) {
console.log('Save error', errorHandler(err));
return res.status(401).json({
errors: errorHandler(err)
});
} else {
return res.json({
success: true,
message: user,
message: 'Signup success'
});
}
});
const apiKey = user._id;
user.apiKey = apiKey
user.save((err) => {
console.log(err);
})
}
});
} else {
return res.json({
message: 'error happening please try again'
});
}
};
As you have said in the comments , I think you have apiKey and path as an object properties in your user model which are not filled , and also the problem is you are using jwt_decode for verify and sign purposes which is wrong , the purpose for jwt_decode here is for decoding the token and nothing else , so use jsonwebtoken library for verfication and sign purposes .
Also remove the api key generation code , as what are you doing you are calling user.save() method 2 times in a row so the first one hasn't even finished saving before the 2nd one gets called .

angular + nodejs console shows "GET http://localhost:4200/user/profile 401 (Unauthorized) "

I'm trying to store data into /profile after logging in. However, I keep getting these 2 errors in the console after logging in.
"VM276:1 GET http://localhost:4200/user/profile 401 (Unauthorized)"
and "HttpErrorResponse {headers: HttpHeaders, status: 401, statusText: "Unauthorized"".
Since i'm following different tutorials to work this out so I know that I've made some mistake with the token code, I just don't know how to fix it. And I would like to thank anyone who's spending time to help! This is my authentication.service.ts
import { Injectable } from '#angular/core';
import {HttpClient} from "#angular/common/http";
import {Observable, of} from 'rxjs';
import { map } from 'rxjs/operators';
import {Router} from '#angular/router';
export interface UserDetails{
username: string
email: string
password: string
exp: number
iat: number
}
interface TokenResponse{
token: string
}
export interface TokenPayload{
username: string
email: string
password: string
}
#Injectable({
providedIn: 'root'
})
export class AuthenticationService {
private token: string
constructor(private http: HttpClient, private router: Router) {}
private saveToken(token: string): void{
localStorage.setItem('usertoken', token)
this.token = token
}
private getToken(): string{
if(!this.token){
this.token = localStorage.getItem('usertoken')
}
return this.token
}
public getUserDetails(): UserDetails{
const token = this.getToken()
let payload
if(token){
payload = token.split('.')[1]
payload = window.atob(payload)
return JSON.parse(payload)
}else{
return null
}
}
public isLoggedIn(): boolean{
const user = this.getUserDetails()
if(user){
return user.exp > Date.now()/ 1000
}
else{
return false
}
}
public login(user: TokenPayload): Observable<any>{
const base = this.http.post('/user/login', user)
const request = base.pipe(
map((data: TokenResponse) => {
if(data.token){
this.saveToken(data.token)
}return data
})
)
return request
}
public register(user: TokenPayload) : Observable<any>{
const base = this.http.post('/user/register', user)
const request = base.pipe(
map((data: TokenResponse) => {
if(data.token){
this.saveToken(data.token)
}
return data
})
)
return request
}
public profile(): Observable<any>{
return this.http.get('/user/profile',{
headers: {Authorization: `${this.getToken()}`}
})
}
public logout(): void{
this.token = ''
window.localStorage.removeItem('usertoken')
this.router.navigateByUrl('/')
}
}
This is my profile.component.ts
export class ProfileComponent implements OnInit {
details: UserDetails
constructor(private auth: AuthenticationService) {}
ngOnInit() {
this.auth.profile().subscribe(
user => {
this.details = user
},
err => {
console.error(err)
}
)
}
}
this is my auth.js
const jwt = require("jsonwebtoken");
module.exports = function(req, res, next) {
const token = req.header("token");
if (!token) return res.status(401).json({ message: "Auth Error" });
try {
const decoded = jwt.verify(token, "randomString");
req.user = decoded.user;
next();
} catch (e) {
console.error(e);
res.status(500).send({ message: "Invalid Token" });
}
};
and this is my /routes/user.js
// Filename : user.js
const express = require("express");
const {check, validationResult} = require("express-validator");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const router = express.Router();
const auth = require("../middleware/auth");
const User = require("../model/User");
/**
* #method - POST
* #param - /signup
* #description - User SignUp
*/
router.post(
"/register",
[
check("username", "Please Enter a Valid Username")
.not()
.isEmpty(),
check("email", "Please enter a valid email").isEmail(),
check("password", "Please enter a valid password").isLength({
min: 6
})
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
errors: errors.array()
});
}
const {
username,
email,
password
} = req.body;
try {
let user = await User.findOne({
email
});
if (user) {
return res.status(400).json({
msg: "User Already Exists"
});
}
user = new User({
username,
email,
password
});
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
const payload = {
user: {
id: user.id
}
};
jwt.sign(
payload,
"randomString", {
expiresIn: 10000
},
(err, token) => {
if (err) throw err;
res.status(200).json({
token
});
}
);
} catch (err) {
console.log(err.message);
res.status(500).send("Error in Saving");
}
}
);
router.post(
"/login",
[
check("email", "Please enter a valid email").isEmail(),
check("password", "Please enter a valid password").isLength({
min: 6
})
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
errors: errors.array()
});
}
const { email, password } = req.body;
try {
let user = await User.findOne({
email
});
if (!user)
return res.status(400).json({
message: "User Does Not Exist"
});
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch)
return res.status(400).json({
message: "Incorrect Password!"
});
const payload = {
user: {
id: user.id
}
};
jwt.sign(
payload,
"randomString",
{
expiresIn: 3600
},
(err, token) => {
if (err) throw err;
res.status(200).json({
token
});
}
);
} catch (e) {
console.error(e);
res.status(500).json({
message: "Server Error"
});
}
}
);
/**
* #method - POST
* #description - Get LoggedIn User
* #param - /user/me
*/
router.get("/profile", auth, async (req, res) => {
try {
// request.user is getting fetched from Middleware after token authentication
const user = await User.findById(req.user.id);
res.json(user);
} catch (e) {
res.send({ message: "Error in Fetching user" });
}
});
module.exports = router;
In your angular app you are sending the token with the authorization header
Authorization: token
But in your API (auth.js), you are trying to access the token header
req.header("token")
Replace you api code with
req.header("authorization")

ReactJS - How to get authenticated users data from Node js API?

so I have tested my API route /getUser using Postman which is receiving data successfully being received in json format. However the Jwt token which is stored in localstorage and past in the headers is not being verified as within my browser I receive 'Access denied. No JWT provided' which is sent with a 401 status.
Nodejs API is below this includes my authentication route and /getUserwhich users a middleware file found below also which verifies the token
const express = require('express');
const users = express.Router();
const cors = require('cors');
const moment = require('moment');
const jwt = require('jsonwebtoken');
// var exjwt = require('express-jwt');
const auth = require('../middleware/auth');
const bcrypt = require('bcrypt');
const Sequelize = require('sequelize');
const bodyParser = require('body-parser');
const User = require('../models/User');
const config = require('config');
// const secret = 'dassdfdd';
users.use(
bodyParser.urlencoded({
extended: false
})
);
users.use(bodyParser.json());
users.use(cors());
users.post('/authenticate', (req, res) => {
User.findOne({
where: {
email: req.body.email
}
}).then(user => {
if (user) {
if (bcrypt.compareSync(req.body.password, user.password)) {
const payload = {
id: user.id,
name: user.first_name
};
var token = jwt.sign(payload, config.get('secret'), {
expiresIn: 1440 // expires in 24 hours
});
// res.cookie('auth', token);
res.cookie('jwt', token, { httpOnly: true, secure: true });
// return the information including token as JSON
// // res.setHeader('token', token);
// res.setHeader('Authorization', 'Bearer ' + token);
res.send({
message: 'authentication done ',
token: token,
user: user.toJSON()
});
console.log(token);
console.log('Successful Login');
console.log(user.first_name);
} else {
res.json({ message: 'please check your password !' });
console.log('incorrect password');
}
} else {
res.json({ message: 'user not found !' });
console.log('user cannot be found');
}
});
});
users.get('/protected', (req, res) => {
res.send('protected');
});
users.get('/getUser', auth, function(req, res) {
// const currentUser = req.;
// const id = parseInt(req.params.id);
const users = User.findOne({
where: { id: req.user.id }
});
// }
// });
// if (!users) {
// return res.status(404).send('Cannot find your team players');
// }
console;
res.status(200).json(users);
});
module.exports = users;
Login Component
import React, { Component } from 'react';
import axios from 'axios';
import { withRouter } from 'react-router-dom';
class Login extends Component {
constructor() {
super();
this.state = {
email: '',
password: '',
errors: {}
};
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
onSubmit(e) {
e.preventDefault();
// const user = {
// email: this.state.email,
// password: this.state.password
// };
axios
.post('http://localhost:5000/api/authenticate', {
email: this.state.email,
password: this.state.password
})
.then(res => {
localStorage.setItem('token', res.data.token);
this.props.history.push('/Profile');
});
}
auth.js this is my middleware file
const jwt = require('jsonwebtoken');
const config = require('config');
module.exports = function(req, res, next) {
const token = req.header('Authorization');
if (!token) {
return res.status(401).send('Access denied. No JWT provided.');
}
try {
const decoded = jwt.verify(token, config.get('secret'));
res.set('Authorization', token);
req.user = decoded;
next();
} catch (ex) {
res.status(400).send('Invalid JWT.');
}
};
Profile Component( this is the page , i want the users data to appear)
import React, { Component } from 'react';
import { getJwt } from '../helpers/jwt';
import axios from 'axios';
import { withRouter } from 'react-router-dom';
class Profile extends Component {
constructor(props) {
super(props);
this.state = {
// users: []
};
}
componentDidMount() {
const jwt = getJwt();
if (!jwt) {
this.props.history.push('/Login');
}
axios
.get('http://localhost:5000/api/getUser', {
headers: { Authorization: `Bearer ${jwt}` }
})
.then(res => {
this.profile = res.data;
console.log('profile is:', res.data);
})
.catch(error => console.log(error));
}
Inside your auth.js middleware file, you have const token = req.header('Authorization');. This includes the Bearer prefix which is not part of the JWT itself, and will need to be removed before the token can be parsed by the JWT library.
The Bearer prefix identifies the token type as a Bearer token under the OAuth 2.0 Authorization Framework. If you wish to support other token types the prefix will be different to identify the respective type and framework.

Authentication issues using token in angular 6 + node js

I trying to build an Authentication function in angular with node js as my server,
and i have issues with the identification of the token that sent from angular.
I using the angular HttpInterceptor service to handle with the headers, and i am created a middelware function inside my node js. the error that i receiving is:
{headers: HttpHeaders, status: 401, statusText: "Unauthorized"..
Any help will be appreciated
Middleware function
const jwt = require("jsonwebtoken");
module.exports = (req, res, next) => {
try {
const token = req.headers.authorization.split(" ")[1];
jwt.verify(token, "this_is_the_secret");
next();
} catch (error) {
res.status(401).json({ message: "Auth failed!" });
}
};
Middleware implantation
router.post('/orders', checkAuth, function(req,res,next){
Order.create(req.body.order, function(err, createdOrder){
if (err) return next(err)
.then()
Show.findByIdAndUpdate({"_id": req.body.showId}, {"$push":{"takenSeats": req.body.takenSeatsIds}})
.exec(function(err, updatadShow){
if (err) return next(err)
console.log(updatadShow)
})
res.json(createdOrder)
})
})
Auth service in angular
import { Injectable } from "../../../node_modules/#angular/core";
import { HttpClient } from "../../../node_modules/#angular/common/http";
import { AuthData } from "../models/auth-data.model";
#Injectable({ providedIn: "root"})
export class AuthService {
private token: string
signupUrl = "http://localhost:3000/signup";
loginUrl = "http://localhost:3000/login"
constructor(private http: HttpClient){}
getToken(){
return this.token
}
createUser(email: string, password:string){
const authData: AuthData = {email: email, password: password}
this.http.post(this.signupUrl, authData)
.subscribe(response => {
console.log(response)
});
}
login(email: string, password){
const authData: AuthData = {email: email, password: password}
this.http.post<{token: string}>(this.loginUrl,authData)
.subscribe(response => {
console.log(response)
const token = response.token
this.token = token;
console.log("token" + this.token)
});
}
}
AuthInterceptor service
import { HttpInterceptor, HttpRequest, HttpHandler } from "../../../node_modules/#angular/common/http";
import { Injectable } from "../../../node_modules/#angular/core";
import { AuthService } from "./auth.service";
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService:AuthService){}
intercept(req: HttpRequest<any>, next: HttpHandler) {
const authToken = this.authService.getToken();
const authRequest = req.clone({
headers: req.headers.set('Authorization', "Bearer" + authToken)
})
return next.handle(authRequest)
}
}
[Edit] Sates of the Authentication token
console.log of the login response
{token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6I…Q3OH0.fCgCuHQkDHHgJHq8LFqeVxLayyr-9U-Y6_23_9FGHkU", expiresIn: 3600}
auth.service.ts:35 tokeneyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Imlnb3JybzYyMUBnbWFpbC5jb20iLCJ1c2VySWQiOiI1YjU4YjYwYTUxMDkyNDI4Njg1MDM3MzIiLCJpYXQiOjE1MzI1NDc4NzgsImV4cCI6MTUzMjU1MTQ3OH0.fCgCuHQkDHHgJHq8LFqeVxLayyr-9U-Y6_23_9FGHkU
console.log of the req.headers.authorization after posting to a route without implementation of the middleware
BearereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Imlnb3JybzYyMUBnbWFpbC5jb20iLCJ1c2VySWQiOiI1YjU4YjYwYTUxMDkyNDI4Njg1MDM3MzIiLCJpYXQiOjE1MzI1NDc4NzgsImV4cCI6MTUzMjU1MTQ3OH0.fCgCuHQkDHHgJHq8LFqeVxLayyr-9U-Y6_23_9FGHkU
console.log of the states inside the middleware function
logging points
const jwt = require("jsonwebtoken");
module.exports = (req, res, next) => {
try {
console.log(" Before the split " + req.headers.authorization)
const token = req.headers.authorization.split(" ")[1];
console.log(" After The split " + req.headers.authorization)
jwt.verify(token, "this_is_the_secret");
next();
} catch (error) {
res.status(401).json({ message: "Auth failed!" });
}
};
Result
Before the split BearereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Imlnb3JybzYyMUBnbWFpbC5jb20iLCJ1c2VySWQiOiI1YjU4YjYwYTUxMDkyNDI4Njg1MDM3MzIiLCJpYXQiOjE1MzI1NDc4NzgsImV4cCI6MTUzMjU1MTQ3OH0.fCgCuHQkDHHgJHq8LFqeVxLayyr-9U-Y6_23_9FGHkU
After The split BearereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Imlnb3JybzYyMUBnbWFpbC5jb20iLCJ1c2VySWQiOiI1YjU4YjYwYTUxMDkyNDI4Njg1MDM3MzIiLCJpYXQiOjE1MzI1NDc4NzgsImV4cCI6MTUzMjU1MTQ3OH0.fCgCuHQkDHHgJHq8LFqeVxLayyr-9U-Y6_23_9FGHkU
Ok. I found up what was the problem, I didnt put space after the "Bearer "
In the HttpInterceptor

Resources