How can I access ["x-access-token"] in Vue.js front end? - javascript

I have an application that uses ["x-access-token"] as token in the header, when I try to access the token in the header I keep gettting "no token provided". I use jwt for authentication
This is how I'm accessing it in the script tag:
<script>
import axios from "axios";
export default {
data() {
return {
name: "",
email: "",
};
},
created() {
//user is not authorized
if (localStorage.getItem("token") === null) {
this.$router.push("/login");
}
},
mounted() {
axios
.get("http://localhost:5000/api/auth/user", {
headers: {
Authorization:'Bearer' + token,
token: localStorage.getItem("token") }
})
.then(res => {
console.log(res)
this.name = res.data.foundUser.name;
this.email = res.data.foundUser.email;
});
},
};
</script>
this is my authorization middleware for verifying tokens in the browser, my header uses "x-access-token"
const jwt = require("jsonwebtoken");
module.exports = function (req, res, next) {
let token = req.headers["x-access-token"] || req.headers["authorization"];
let checkBearer = "Bearer ";
if (token) {
if (token.startsWith(checkBearer)) {
token = token.slice(checkBearer.length, token.length);
}
jwt.verify(token, process.env.SECRET, (err, decoded) => {
if (err) {
res.json({
success: false,
message: "Failed to authenticate"
});
} else {
req.decoded = decoded;
next();
}
});
} else {
res.json({
success: false,
message: "No token Provided"
});
}
};
and my authenticated route to get the current logged in user
// Get Profile
router.get("/auth/user", verifyToken, async (req, res) => {
try {
let foundUser = await User.findOne({
_id: req.decoded._id
}).populate(
"address"
);
if (foundUser) {
res.json({
success: true,
user: foundUser
});
}
} catch (err) {
res.status(500).json({
success: false,
message: err.message
});
}
});
When I check my local storage I see the token but can't seem to understand why I keep getting no token provided when trying to get the user in my front end

try
const token = localStorage.getItem("token")
axios
.get("http://localhost:5000/api/auth/user", {
headers: {
Authorization:'Bearer ' + token,
'x-access-token': token
}
})

Related

getting Cannot set headers after they are sent to the client error in express js

I have created a middleware that authenticate the user that whether he is verified or not. At the first request when i try to go on protected routes it gives me success messages and verifies the jwt token but when i hit the same request again i get this error.
here is my code !
const Anime = require("../models/admin_model");
const jwt = require("jsonwebtoken");
const checkUserAuthentication = async (req, res, next) => {
const token = req.headers.token;
if (token) {
jwt.verify(token.toString(), "secret", async (err, token_decode) => {
if (err) {
return res.json({
status: 0,
err: err,
msg: "Authorization failed",
});
}
console.log(token_decode);
res.json({ data: token_decode });
next();
return;
});
}
return res.json({
status: 0,
msg: "Authorization failed",
});
};
module.exports = checkUserAuthentication;
res.json({ data: token_decode });
next();
You are responding with JSON, then you are handing control over to the next middleware or route endpoint which (presumably) is making its own response (but it can't because you already responded).
I changed my code to this.
Well maintained if-else statements.
const Anime = require("../models/admin_model");
const jwt = require("jsonwebtoken");
const checkUserAuthentication = async (req, res, next) => {
const token = req.headers.token;
if (token) {
jwt.verify(token.toString(), "thisissecs", async (err, token_decode) => {
if (!err) {
console.log(token_decode);
res.json({ data: token_decode });
next();
} else {
return res.json({
status: 0,
msg: "Authorization failed",
});
}
});
}
else{
return res.json({
status: 0,
msg: "Authorization failed",
});
}
};
module.exports = checkUserAuthentication;

how to set a new cookie without response object(express.js)

Before talking about issue, you need some background knowledge about my application.
I use node.js, express.js and mongoDB (with mongoose).
I was making a basic login function to do that I choose JWT for token and passport.js for authentication. and login flow is like below
Issue access token(expires in 10mins) and refresh token (expires in 2 weeks)
Store both token in cookies and store refresh token in DB too
Make a strategy for authentication.
Use strategy when you go to '/current' page.
Below is my code:
user.js:
router.post('/login', (req, res) => {
const { userid, password } = req.body;
// find email
User.findOne({ userid })
.then(user => {
if (!user) {
return res.json({
loginSuccess: false,
message: "Auth failed, ID not found"
});
}
// compare password
bcrypt.compare(password, user.password)
.then(isMatch => {
if (isMatch) {
const accessPayload = {
id: user.id,
userid: user.userid,
role: user.role
};
// console.log(accessPayload.id);
const refreshPayload = {
id: user.id
}
jwt.sign(accessPayload, JWT_ACCESS_SECRET, { expiresIn: JWT_ACCESS_EXPIRATION_TIME}, (err, token) => {
const accessToken = 'Bearer ' + token
const accessT = token
jwt.sign(refreshPayload, JWT_REFRESH_SECRET, { expiresIn: JWT_REFRESH_EXPIRATION_TIME }, (err, refreshT) => {
//note that maxAge is in milliseconds
res.cookie('accessToken', accessT, { httpOnly: true }) //secure: true
res.cookie('refreshToken', refreshT, { httpOnly: true })
res.json({
success: true,
refreshToken: 'Bearer ' + refreshT,
accessToken: accessToken
})
User.saveRefreshToken(refreshT)
//이거 모듈화 왜앙돼
});
});
} else {
return res.json({ loginSuccess: false, message: "Wrong password" });
}
});
});
});
router.get('/current',passport.authenticate('custom', { session: false }), (req, res) => {
res.json({
id: req.user.id,
userid: req.user.userid,
role: req.user.role
// id: req.user.id,
});
})'
and my strategy(custom) is like below
require('dotenv').config();
const { auth } = require('../middleware/auth');
const { append } = require('express/lib/response');
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const passportCustom = require('passport-custom');
const CustomStrategy = passportCustom.Strategy;
// const res = require('express/lib/response');
const jwt = require('jsonwebtoken');
const mongoose = require('mongoose');
const User = mongoose.model('User');
const { verifyToken } = require('../utils/jwt');
module.exports = custom => {
custom.use('custom', new CustomStrategy(
function (req, done) {
const accessToken = req.cookies['accessToken'];
const refreshToken = req.cookies['refreshToken'];
//when both token are valid
if (
req && verifyToken('access', accessToken)
&& verifyToken('refresh', refreshToken)
) {
const verifyAccessToken = verifyToken('access', accessToken);
const user = {
id: verifyAccessToken.id,
userid: verifyAccessToken.userid,
role: verifyAccessToken.role
};
console.log(user)
return done(null, user);
}
// when refresh token is valid but access token expired
else if (
req && !verifyToken('access', accessToken)
&& verifyToken('refresh', refreshToken)
) {
console.log('you need new access token')
const refreshTokenInfo = verifyToken('refresh', refreshToken);
User.findById({ _id: refreshTokenInfo.id }, (err, user) => {
const Payload = {
id: user.id,
userid: user.userid,
role: user.role
}
console.log('old access token : ' +req.cookies['accessToken'])
jwt.sign(Payload, JWT_ACCESS_SECRET, { expiresIn: JWT_ACCESS_EXPIRATION_TIME }, (err, accessToken) => {
if (err) {
console.log(err)
}
console.log('new accesstoken : ' + accessToken)
});
return done(null, true)
})
return done(null, true)
}
}
))
}
The problem is at the case of ' // when refresh token is valid but access token expired'
When accessToken is expired but refresh one is valid I want to make new access token via information from DB(access DB when refresh token is correct) and set in cookie before done() However, I couldn't set cookie because there is no response object in parameter :/.
As far as I know, people use cookie to store access token and sometimes refresh it. I wonder how can I refresh my cookie in jwtStrategy and pass it to /current router so it recognize my refreshed access cookie
Thanks for reading, your help will be appreciated.

Where should I set the authorization header after create the token?

I am triying to implement a securuty system based on tokens. The problem is that I dont know where I must set the authorization header after create it in order to check it in all of my diferent routes. My code is the next.
I want to do it WITHOUT USING POSTMAN or any program like that.
This is the route for user login, where I create the token
router.post('/login',(req,res)=>{
const user = req.body.user;
const token = jwt.sign({user},'secret_key');// generamos un identificador para el usuario que acaba de registrarse
res.json({
token
});
});
Then, I have this route to test it works
router.get('/protected',ensureToken,(req,res)=>{
jwt.verify(req.token,'secret_key',(err,data)=>{
if(err){
res.sendStatus(403);
}else{
res.json({
text:'protected'
});
}
});
});
And finally, this is the middleware
function ensureToken(req,res,next){
const bearerHeader = req.headers['authorization'];
console.log(bearerHeader);
if(typeof bearerHeader != 'undefined'){
const bearer = bearerHeader.split(" ");
const bearerToken= bearer[1];
req.token = bearerToken; //almacenamos el token en el objeto de la peticion
next();
}else{
res.sendStatus(403);//status de no permitido
}
}
Where I should set the authorization header for all of my routes type 'get' as the protected route?
Verifying
router.get('/verify', async (req, res, next) => {
try {
const token = req.headers['x-access-token']//client should this value
if (!token){
return res.status(401).send({
success: false,
message: 'Unauthorized request',
})
}
else if (isExpiredToken(token)){
return res.status(300).send({
success: false,
message: 'Token is expired',
})
}
const decoded = jwt.verify(token, SECRET_KEY)
const expiredAt = moment.unix(decoded.exp).subtract(#YOUR_EXPIRED_TIME, 'minutes')
const now = moment()
let newToken = null
if (now.isAfter(expiredAt)) {//refresh the token
const userFromDB = await User.findOne({
where: {
id: decoded.id,
},
})
const content = util.sanitize(userFromDB)
newToken = await jwt.sign(content, SECRET_KEY, {
audience: content.email,
issuer: 'YOUR_APP',
expiresIn: 'YOUR_EXPIRED_TIME',
})
console.log(
`VERIFY\tToken refreshed automatically for user-${content.id}`
)
}
res.send({
success: true,
nextToken: newToken,
})
} catch (e) {
console.log(e)
res.status(500).send({
success: false,
message: 'Internal server error',
})
}
})
Middleware
async function authMiddleware(req, res, next){
/* In this case, user can authenticate with header['x-access-token'] or body['accessToken']*/
const token = req.header['x-access-token'] || req.body['accessToken'] || undefined
if(!token) return res.status(401).send({ success: false, message: 'unauthorized' })
try{
const user = await jwt.verify(token, secret)
req.user = { ...user }
return next()
}
catch(e){
console.log(e)
return res.status(500).send({ success : false, message : 'internal server error' })
}
}

Getting bad request for twitter request token endpoint and invalid request for create tweet endpoint?

I am trying to make requests on behalf of users so for that I have successfully generated oauth_access_token and oauth_access_token_secret but whenever I make call to tweets https://api.twitter.com/2/tweets
it gives following error message: post daata {"errors":[{"parameters":{},"message":"Requests with bodies must have content-type of application/json."}],"title":"Invalid Request","detail":"One or more parameters to your request was invalid.","type":"https://api.twitter.com/2/problems/invalid-request"}
code:
oauth.js:
const OAuth = require('oauth');
module.exports = (oauthCallback) => {
const TWITTER_CONSUMER_KEY = process.env.TWITTER_CONSUMER_KEY;
const TWITTER_CONSUMER_SECRET = process.env.TWITTER_CONSUMER_SECRET;
const twitter_request_token_url = 'https://api.twitter.com/oauth/request_token';
const twitter_access_token_url = 'https://api.twitter.com/oauth/access_token';
const _oauth = new OAuth.OAuth(
twitter_request_token_url,
twitter_access_token_url,
TWITTER_CONSUMER_KEY, // consumer key
TWITTER_CONSUMER_SECRET, // consumer secret
"1.0",
oauthCallback,
"HMAC-SHA1"
);
const oauth = {
post: (url, oauth_access_token, oauth_access_token_secret, post_body, post_content_type) => {
return new Promise((resolve, reject) => {
_oauth.post(url, oauth_access_token, oauth_access_token_secret, post_body, post_content_type,
(error, data, response) => {
console.log("post daata", data)
console.log("post response", response)
if (error) {
reject(error);
} else {
resolve({ data, response });
}
}
);
});
}
};
return oauth;
};
route.js:
router.post('/twitter/tweet', async (req, res) => {
try {
const { response } = await oauth.post('https://api.twitter.com/2/tweets', oauth_access_token, oauth_access_token_secret, { "text": "Hello World!" }, 'application/json')
console.log("response backend data", response.data);
res.status(201).send({ message: "Tweet successful" });
} catch (error) {
res.status(403).json({ message: "Missing, invalid, or expired tokens" });
}
});
I thought there is some problem with node-oauth package (FYR: https://github.com/ciaranj/node-oauth/issues/364#issue-1076029771) so I switched to oauth1a but then I am getting 400 bad request for request token endpoint
code:
const crypto = require('crypto');
const OAuth = require('oauth-1.0a');
const axios = require('axios');
router.post('/twitter/oauth/request_token', async (req, res) => {
try {
const oauth = OAuth({
consumer: {
key: process.env.TWITTER_CONSUMER_KEY,
secret: process.env.TWITTER_CONSUMER_SECRET
},
signature_method: 'HMAC-SHA1',
hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64')
});
const authHeader = oauth.toHeader(oauth.authorize({
url: `https://api.twitter.com/oauth/request_token?oauth_callback=http://localhost:3000`,
method: 'POST'
}));
console.log("authHeader", authHeader)
const response = await axios.post(`https://api.twitter.com/oauth/request_token?oauth_callback=http://localhost:3000`, {
headers: {
Authorization: authHeader["Authorization"]
}
});
console.log("response", response)
res.status(200).send({ status: "ok" });
} catch (error) {
console.log("error", error)
res.status(404).json({
message: "Twitter request token failed",
});
}
});
Not sure if this issue is specific to node-oauth but using axios I was able to tweet using twitter v2 APIs. Working code snippet added for reference:
const express = require('express');
const router = express.Router();
const OAuth = require('oauth-1.0a');
const axios = require('axios');
router.post('/twitter/tweet', async (req, res) => {
try {
const oauth = OAuth({
consumer: {
key: process.env.TWITTER_CONSUMER_KEY,
secret: process.env.TWITTER_CONSUMER_SECRET
},
signature_method: 'HMAC-SHA1',
hash_function: (baseString, key) => crypto.createHmac('sha1', key).update(baseString).digest('base64')
});
const token = {
key: '',
secret: ''
};
const authHeader = oauth.toHeader(oauth.authorize({
url: 'https://api.twitter.com/2/tweets',
method: 'POST'
}, token));
const data = { "text": "Hello world!!" };
await axios.post('https://api.twitter.com/2/tweets',
data,
{
headers: {
Authorization: authHeader["Authorization"],
'user-agent': "v2CreateTweetJS",
'content-type': "application/json",
'accept': "application/json"
}
}
);
res.status(201).send({ message: "Tweet successful" });
} catch (error) {
console.log("error", error)
res.status(403).send({ message: "Missing, invalid, or expired tokens" });
}
});

JWT token cannot be verified with the same secret

I have two different API routes, with several endpoints embedded in them. One of them is protected and is only accessible if you send a JWT token in the request. The other one, of course, is for Auth that allows a user to generate a token and then append it to every request. Assuming the relevant imports and that my Auth code is in Auth.jsand that the Add Candidate is in Candidate.js:
Auth.js
router.post('/login', (req, res) => {
let { email, password } = req.body;
db.collection('users').findOne({ email: email }, { projection: { email: 1, password: 1, accessGranted: 1 } }, (err, userData) => {
console.log(userData);
if (!err) {
let passwordCheck = bcrypt.compareSync(password, userData.password);
if (passwordCheck) {
if (userData.accessGranted) {
const payload = {
email: userData.email,
id: userData._id
}
let token = jwt.sign(payload, tokenSecret);
res.status(200)
.send({ token, email: userData.email });
} else {
//.. Other Code
}
} else {
// Other code
}
} else {
// Other code
}
})
})
Now, I have added a middleware in the other file as such:
Candidate.js
router.use((req, res, next) => {
const token = req.body.token;
if (token) {
jwt.verify(token, tokenSecret, function (err, decoded) {
if (!err) {
req.decoded = decoded;
next();
} else {
// Other Code
}
})
} else {
// Other Code
}
}
);
Error: jwt complains that the token I have supplied is invalid.
For prototyping, I have saved the token in a JS const variable and I have double-checked that the tokenSecret in both the files is the same. What's wrong?

Categories

Resources