Passport.authenticate throw Unauthorized error with cookies approach.
Where can be problem, in passport js settins or on frontend side?Interesting that on compyter another developer it works fine
nodeJS
router.post('/check',passport.authenticate("cookie", { session: false }), async (req, res, next) => {
try {
return res.status(200).json({ status: true })
} catch (error) {
res.status(400).json(error);
}
});
frontend
export async function isAuthorized(context, commands) {
let token = getCookie('token')
if (token) {
let settings = {
"method": 'POST',
headers: {
"Content-Type": "application/json",
},
}
try {
let response = await fetch('/api/auth/check', settings) //here unathorized
let result = await response.json()
return result.status
} catch (error) {
throw Error
}
} else {
return false
}
}
the cookie is sent successfully with this
maybe I need use some additional settings for passport or something like this
Related
I have set up JWT to be set in localstorage whenever someone logins or registers. And it works, I can see the token in localstorage. But when I set the token in the headers with axios, node.js in the backend can`t find the token. Like it does not exists. I have checked it in the front end, I get logs of the token in the headers. And also when I request from postman it works. Here is the code.
setAuthToken function = {
const instance = axios.create({
baseURL: "https://localhost:5000",
});
if (token) {
instance.defaults.headers.common["x-auth-token"] = `${token}`;
console.log(instance.defaults.headers.common["x-auth-token"]);
} else {
delete instance.defaults.headers.common["x-auth-token"];
}
}
const loadUser = async () => {
if (localStorage.token) setAuthToken(localStorage.token);
console.log(localStorage.token);
try {
const res = await axios.get("/api/users");
console.log(res);
dispatch({ type: USER_LOADED, payload: res.data });
} catch (err) {
console.log(err.response.data.msg);
dispatch({ type: AUTH_ERROR });
}
The request comes to the await axios statement and goes to catch so error is in the request.
Here is the backend code
// Get current user
router.get("/", auth, async (req, res) => {
try {
const user = await User.findById(req.user.id);
res.status(200).json({ user });
} catch (err) {
console.log(err);
res.status(500).json({ msg: `Server Error` });
}
});
auth middleware function here = {
const token = req.headers["x-auth-token"];
console.log(token, "token in auth.js");
console.log(req.headers, "req.header");
if (!token) {
return res.status(401).json({ msg: `Access denied.` });
}
try {
const decoded = jwt.verify(token, config.get("jwtSecret"));
req.user = decoded.user;
next();
} catch (err) {
res.status(401).json({ msg: `Token is not valid` });
}
}
I`m new to backend develoment and axios. Can someone help me please. Thank you
Here are the console.logs
Logs
Logs
Little update, it looks like there is a problem with proxy, I am using my own backend api, and also movie data base api. So maybe thats why I cant set headers? Here are new logs:
config: Object { url: "/api/users", method: "get", timeout: 0, … }
data: "Proxy error: Could not proxy request /api/users from localhost:3000 to http://localhost:5000/ (ECONNREFUSED)."
headers: Object { connection: "keep-alive", date: "Wed, 05 May 2021 13:18:05 GMT", "keep-alive": "timeout=5", … }
request: XMLHttpRequest { readyState: 4, timeout: 0, withCredentials: false, … }
status: 500
statusText: "Internal Server Error
I think the issue is because you are setting you are setting up your instance wrongly
set up your instance in a new file config.js -
import Axios from 'axios';
const baseURL = "http://localhost:5000";
const axiosInstance = Axios.create({
baseURL: baseURL,
});
axiosInstance.interceptors.request.use(
function (config) {
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = 'Bearer ' + token;
}
return config;
},
function (error) {
return Promise.reject(error);
}
);
export default axiosInstance;
now when making any api request instead of using axios use axiosInstance eg-
axiosInstance.get('/something').then(res => console.log(res)).catch(err => console.log(err))
I'm trying to implement the Facebook OAuth in my express/NodeJS app using authorization code flow. I'm using react-facebook-login node module to fetch the authorization code. In my react app, I could get the authorization code successfully. But in server side, I can't request the access token from the Facebook API as I'm getting an error message "redirect_uri is not identical to the one you used in the OAuth dialog request"
Code in my react app,
facebookLogin = async (signedRequest) => {
return fetch('/api/auth/facebook', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ signedRequest }),
}).then((res) => {
if (res.ok) {
return res.json();
} else {
return Promise.reject(res);
}
});
};
responseFacebook = async (response) => {
try {
if (response['signedRequest']) {
const userProfile = await this.facebookLogin(response['signedRequest']);
console.log(userProfile);
} else {
throw new Error(response.error);
}
} catch (err) {
console.log(err);
}
};
render() {
<FacebookLogin
appId={process.env.FACEBOOK_CLIENT_ID}
fields="name,email"
responseType="code"
redirectUri="http://localhost:3000/"
callback={this.responseFacebook}
/>
In my app.js
const facebookOAuth = require('./config/facebookOAuth');
// facebook oauth route
app.post("/api/auth/facebook", async (req, res) => {
try {
const signedRequest = req.body.signedRequest;
const profile = await facebookOAuth.getProfile(signedRequest);
console.log(profile);
res.send({ profile });
} catch (err) {
console.log(err);
res.status(401).send();
}
});
facebookOAuth.js look like this
const fetch = require('node-fetch');
const getData = async (userId, accessToken) => {
const userData = await fetch(`https://graph.facebook.com/${userId}?fields=name,email&access_token=${accessToken}`, {
method: 'GET'
}).then((res) => {
return res.json();
}).then((userData) => {
return userData;
});
return userData;
};
exports.getProfile = async (signedRequest) => {
const decodedSignedRequest = JSON.parse(Buffer.from((signedRequest.split(".")[1]), 'base64').toString());
const profile = await fetch(`https://graph.facebook.com/oauth/access_token?client_id=${process.env.FACEBOOK_CLIENT_ID}&redirect_uri=${encodeURIComponent('http://localhost:3000/')}&client_secret=${process.env.FACEBOOK_CLIENT_SECRET}&code=${decodedSignedRequest.code}`, {
method: 'GET'
}).then((res) => {
return res.json();
}).then((token) => {
console.log(token);
const userData = getData(decodedSignedRequest.user_id, token.access_token);
return userData;
}).catch((err) => {
console.log(err);
return err;
});
return profile;
}
What I'm getting is this error
"error": {
message: 'Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request',
type: 'OAuthException',
code: 100,
error_subcode: 36008,
fbtrace_id: 'A-YAgSqKbzPR94XL8QjIyHn'
}
I think the problem lies in my redirect_uri. Apparently, the redirect uri I obtained from the Facebook auth dialog is different from the one that I'm passing to the facebook API in my server side (http://localhost:3000/).
I believe there's something to do with the origin parameter of the redirect_uri. Initial auth dialog request uri indicates that it's origin parameter value is something like "origin=localhost:3000/f370b6cb4b5a9c". I don't know why react-facebook-login add some sort of trailing value at the end of origin param.
https://web.facebook.com/v2.3/dialog/oauth?app_id=249141440286033&auth_type=&cbt=1620173773354&channel_url=https://staticxx.facebook.com/x/connect/xd_arbiter/?version=46#cb=f39300d6265e5c4&domain=localhost&origin=http%3A%2F%2Flocalhost%3A3000%2Ff370b6cb4b5a9c&relation=opener&client_id=249141440286033&display=popup&domain=localhost&e2e={}&fallback_redirect_uri=http://localhost:3000/&locale=en_US&logger_id=f1b3fba38c5e31c&origin=1&redirect_uri=https://staticxx.facebook.com/x/connect/xd_arbiter/?version=46#cb=f17641be4cce4d4&domain=localhost&origin=http%3A%2F%2Flocalhost%3A3000%2Ff370b6cb4b5a9c&relation=opener&frame=f3960892790a6d4&response_type=token,signed_request,graph_domain&return_scopes=false&scope=public_profile,email&sdk=joey&version=v2.3
I tried finding everywhere about this but no luck. Anyone has clue about this, much appreciated.
Are you using middleware to parse the body? if you aren't code could be undefined here.
const facebookOAuth = require('./config/facebookOAuth');
// facebook oauth route
app.post("/api/auth/facebook", async (req, res) => {
try {
const code = req.body.code;
const profile = await facebookOAuth.getProfile(code);
console.log(profile);
res.send({ profile });
} catch (err) {
console.log(err);
res.status(401).send();
}
});
I am using react.js as frontend and nodejs for the backend. My client-side code is
export const updatePaymentDetails = (userId, token, paymentDetails) => {
return fetch(`${API}/user/${userId}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `Bearer ${token}`
},
body: JSON.stringify(paymentDetails)
})
.then(response => {
console.log(response);
return response.json();
})
.catch(err => console.log(err));
};
And My server-side code is
exports.updateUser = (req, res) => {
User.findByIdAndUpdate(
{_id: req.profile._id},
{$set: req.body},
{new: true, useFindAndModify: false},
(err, user) => {
if(err) {
return res.status(400).json({
error: "You are not authorized to update this user"
});
}
user.salt = undefined;
user.encry_password = undefined;
user.createdAt = undefined;
user.updatedAt = undefined;
console.log(user);
return res.json(user);
}
);
};
Front-end output
In the server-side code, you can see that I am returning the res.json. but On the client-side, I am not getting the value that I have returned from the server.
Please, can anyone help me?
You need to add one more then(). when you call response.json() it also returns a promise apply a then call when you return response.json()
My client is Vue.js using a Vuex store. I am using passport.js for authentication on the server side. Login and account registration is working. Checking mongodb shows new data. But express is sending an undefined response to the client. This is my first major javascript project so I'm hoping it's something simple my eyes just can't see yet.
client: api.js
export async function registerUser(user) {
console.log("api to register user");
console.log(user);
const route = `${api}/register`;
return fetch(route, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(user)
})
.then(response => {
console.log(response.json());
return response.json();
})
.then(json => {
console.log(json);
return json;
})
.catch(err => {
console.error(err);
});
}
client: index.js (vuex store where res is undefined)
actions: {
async register(state, user) {
apis.registerUser(user).then(res => {
if (res.success) {
this.dispatch("loadUser");
alert("successfully registered");
}
});
},
async loadUser() {
apis.getUser().then(res => {
this.commit("setUser", res.user);
});
}
}
server: app.js
app.post('/api/v1/register', function(req, res) {
const success = true;
Users=new User({email: req.body.email, username : req.body.username});
console.log(req.body);
User.register(Users, req.body.password, function(err, user) {
if (err) {
console.log('account could not be saved');
success = false;
} else {
console.log('account saved');
}
})
res.send({success: success});
});
fetch error printing to console
The server console.logs in the app.js route indicate the req.body has the right data and user account is saved successfully. No errors occur on res.send but the client gets an undefined response.
After much banging my head against the table and some outside assistance, I found a solution. I had two main issues.
I was not preventing the default on the submit button so the form was refreshing before the request was properly handled.
Mishandling of javascript promises.
Working code below:
api.js
export function registerUser(user) {
console.log("api to register user");
console.log(user);
const route = `${api}/register`;
return fetch(route, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(user)
})
.then(response => {
console.log(response.json());
return response.json();
})
}
index.js (vuex store)
actions: {
register(state, user) {
apis.registerUser(user).then(res => {
if (res.success) {
alert("successfully registered");
}
}).catch(err => {
console.error(err);
});
}
}
app.js code remained the same
I'm learning nodejs and trying to make an API call. The API uses JWT to authenticate.
I created these functions to sign a token:
function token() {
const payload = {
iat: Math.floor(new Date() / 1000),
exp: Math.floor(new Date() / 1000) + 30,
sub: "api_key_jwt",
iss: "external",
jti: crypto.randomBytes(6).toString("hex")
};
return new Promise((resolve, reject) => {
jwt.sign(payload, privatekey, { algorithm: "RS256" }, function(
err,
token2
) {
if (err) reject(err);
else resolve(token2);
});
});
}
exports.genToken = async function() {
const header = {
"x-api-key": api
};
const data = {
kid: api,
jwt_token: await token()
};
async function authorization(req, res) {
try {
const auth = await rp({
url: authurl,
method: "POST",
headers: header,
body: data
});
res.send(auth.body);
} catch (error) {
res.send(404).send();
}
}
return {
"x-api-key": api,
Authorization: "Bearer " + authorization()
};
};
This works fine. Then I created a function to make the API call:
const token = require("./index").genToken;
const rp = require("request-promise");
exports.getOrderBook = function(res, error) {
const full_url = url + "order_book";
const auth = token();
rp({
url: full_url,
method: "GET",
headers: auth,
body: {
market: "btceur"
},
json: true
})
.then(function(response) {
res(response);
})
.catch(function(err) {
error(err);
});
};
And I call it using Express:
routes.get("/orderbook", async (req, res, next) => {
try {
const book = await orders.getOrderBook();
res.send(book);
} catch (error) {
next(error);
}
});
However, when I call my API, it shows an error in console:
TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of
type string or Buffer. Received type object.
I guess the error is something with the token generation, because if I console.log(auth) in the getOrderBook function, it shows Promise { <pending> }, so probably an object is being passed as the jwt token.
Is it really the problem? I tried a lot of different solutions that I found on internet, however the concept of Async/Await is new to me, and I'm having some troubles to figure it out.
Thanks a lot in advance guys!
Since getToken is an anync function, the return is wrapped in a Promise as well so you would need another anync/await:
exports.getOrderBook = async function() {
let response;
try {
const full_url = url + "order_book";
const auth = await token();
response = await rp({
url: full_url,
method: "GET",
headers: auth,
body: {
market: "btceur"
},
json: true
});
} catch (e) {
// handle error
throw e
// or console.error(e)
}
return response;
};
In this line as well Authorization: "Bearer " + authorization(), authorization is returning a promise
const bearer = await authorization()
return {
"x-api-key": api,
Authorization: "Bearer " + bearer
};
For error handling wrap entire thing in try..catch block
exports.genToken = async function() {
try {
const header = {
"x-api-key": api
};
const data = {
kid: api,
jwt_token: await token()
};
async function authorization(req, res) {
let auth;
try {
auth = await rp({
url: authurl,
method: "POST",
headers: header,
body: data
});
// res object not available
// res.send(auth.body);
} catch (error) {
// res object not available, better throw error and handle in your middleware
// res.send(404).send();
}
return auth
}
const bearer = await authorization()
} catch (e) {
// handle error
}
return {
"x-api-key": api,
Authorization: "Bearer " + bearer
};
}