I've recently switched to Cognito for the authentication on my website. I'm using NodeJS/Express to run the server. With each API call having a callback in between the declaration and the main function to check the if the user is authenticated, currentAuthenticatedUser(), this should return a cognito user object for the current req/session.
What I've found is that this function works fine until someone logs in. If I log in like normal, my account then becomes authenticated, I gain access to the main page etc.
But then if I send someone else the website link, they automatically bypass the login because this function returns my user object, as opposed to filtering by request or session and replying with not authenticated. This seems like too basic of an issue to be right, in the sense that the Amplify function will return the user object of whoever is the last to sign in and authenticate, regardless of the auth status of any new incoming requests from elsewhere.
The two auth checks:
function checkAuthenticated(req, res, next) {
auth.currentAuthenticatedUser()
.then(user => {
console.log(user);
next();
})
.catch(err => {
console.log(err);
return res.redirect('/login');
});
}
function checkNotAuthenticated(req, res, next) {
auth.currentAuthenticatedUser()
.then(user => {
console.log(user);
return res.redirect('/');
})
.catch(err => {
console.log(err);
next();
});
}
Examples of API calls:
app.get('/', checkAuthenticated, (req, res) => {
res.render('index.ejs');
});
app.post('/login', checkNotAuthenticated, async (req, res, next) => {
// Some code to login
});
Any guidance is appreciated.
Related
I am using the library auth0/nextjs. I am trying to handle the email verification. I have access to the email_verification variable. If not verified, it will redirect to the page /please-verifiy-your-email.
At the moment I am using handleCallback method which is provided by auth0/nextjs.
Code:
const afterCallback = (req, res, session, state) => {
if (!session.user.email_verified) {
res.status(200).redirect('/please-verifiy-your-email')
}
return session;
};
export default auth0.handleAuth({
async login(req, res) {
try {
await auth0.handleLogin(req, res, {
authorizationParams: {
audience: 'https://dev-okz2bacx.us.auth0.com/api/v2/',
scope: 'openid profile email read:branding'
},
returnTo: "/dashboard"
});
} catch (error) {
res.status(error.status || 400).end(error.message);
}
},
async callback(req, res) {
try {
await auth0.handleCallback(req, res, { afterCallback });
} catch (error) {
res.status(error.status || 500).end(error.message);
}
}
});
How can I make sure, the user is still logged in, to get his email for a resend or the possibility to change his email.
He also needs the chance to do a new sign up , because when I will call api/auth/login after login with the unverified email, it will redirect automatically to /please-verifiy-your-email. I guess the session is not killed and auth0 goes back redirecting even tho I didn’t had the chance to sign up again.
Would be really cool if I get a few inputs.
It would solve the problem if I could log in the user and then it would redirect to /please-verifiy-your-email. I would be able to get his email address, name for further functions like resend verification. Right now I call api/auth/me I get:
{"error":"not_authenticated","description":"The user does not have an
active session or is not authenticated"}
I am running into an issue with Passport.js in which I want to get the currently logged in users information from a Post request and process some stuff. When I console.log(req.user) it comes up as 'undefined'. The set up and authentication all works, I can also retreive user's info using a Get request as seen from the first code snippet.
router.get('/', function(req , res){
console.log("The current logged in user is: " + req.user.first_name);
res.render('index.ejs' , {
user: req.user
});
});
^ returns user's name as expected
router.post('/testPost' ,function(req , res){
console.log("The current logged in user is: " + req.user);
res.json({
status: "success"
});
});
^returns undefined even when the user is logged in.
I have seen the same question raised here How to get req.user in POST request using passport js two years ago but there was no answer.
It's because the user might not be logged in at the time you're checking it.
To ensure that a user is logged in when accessing a route you should have a middleware that checks it for you.
You can write it as a separate module and import it in every single one of your routes if it's required.
The module:
module.exports = {
EnsureAuthenticated: (req, res, next) => {
if (req.isAuthenticated()) {
return next();
} else {
res.sendStatus(401);
}
}
};
The routes:
//Destructuring | EnsureAuth Function
const {
EnsureAuthenticated
} = require('../path/to/the/module');
//You should get your user here
router.get('/', EnsureAuthenticated, (req, res) => {
console.log(req.user)
});
I am implementing an auth0 login flow for a node js server that serves a react app. I have implemented the login and log out flows correctly, but in the /callback URL I am given a false token that cannot be decrypted.
So, if I visit /login, it takes me to the Auth0 form correctly; and I can log in successfully, according to the logs in Auth0. But when Auth0 redirects back to the callback url, I get a false token.
app.get("/callback", (request, response, next) => {
passport.authenticate("auth0", (auth0Error, token) => {
if (!token){
// HERE, token is false
}
...
})(request, response, next);
});
What could cause this false token? How does the authenticate function work in a callback? And how should I handle this? Should I try auth0 again?
To understand the issue, I started the project in debug mode and added some breakpoint. If you look carefully, passport.authenticate() method calls Auth0Strategy . Then, Auth0Strategy exchange code for token (Authorization Code flow) and returns user profile. Therefore, in the the callback route , token is not available. I added the following lines of code to access accessToken in the callback route.
const strategy = new Auth0Strategy(
{
domain: process.env.AUTH0_DOMAIN,
clientID: process.env.AUTH0_CLIENT_ID,
clientSecret: process.env.AUTH0_CLIENT_SECRET,
callbackURL: '/callback',
},
function(accessToken, refreshToken, extraParams, profile, done) {
// accessToken is the token to call Auth0 API (not needed in the most cases)
// extraParams.id_token has the JSON Web Token
// profile has all the information from the user
console.log(JSON.stringify(profile))
console.log(accessToken);
return done(null, profile, accessToken); // Passing access token
}
);
Then , callback route should have accessToken available.
router.get('/callback', function (req, res, next) {
passport.authenticate('auth0', function (err, user, token) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function (err) {
if (err) { return next(err); }
const returnTo = req.session.returnTo;
delete req.session.returnTo;
res.redirect(returnTo || '/user');
});
})(req, res, next);
});
This was added just to explain the flow. But you can ignore passing the token for production application.
I'm trying to make Node.js app with Nuxt.js and Passport.js.
I login and set user data in vuex.
action:
nuxtServerInit ({ commit }, { req }) {
if (req.session && req.session.authUser) {
commit('SET_USER', req.session.authUser)
}
}
mutation:
SET_USER: function (state, user) {
state.authUser = user
}
And it works fine, but when I tried to access page that can be accessed only by loged in user there came problems.
axios.get('http://localhost:3000/api/articles/add')
router.get('/api/articles/add', ensureAuthenticated,
(req, res) => {
res.send({
title: 'Add Article'
})
})
function ensureAuthenticated (req, res, next) {
if (req.isAuthenticated()) {
return next()
} else {
res.redirect('/users/login')
}
}
I login and go to http://localhost:3000/articles/add, make request for data restricted for this user (GET http://localhost:3000/api/articles/add). Checking by ensureAuthenticated if user is loged in and isAuthenticated() returns false all the time and when I want to send user data without ensureAuthenticated it's returning undefined
app.get('/api/articles/add', (req, res) => {
res.send(req.user) // undefined
})
BUT if I will send this data to the same api route as page, which I want access, I'm getting right data on screen.
app.get('/articles/add', function(req, res) {
res.send(req.user) // {...}
})
Can someone explain me that? And in some situation I can't make redirection from node.js side. Like in this prev example
function ensureAuthenticated (req, res, next) {
if (req.isAuthenticated()) {
return next()
} else {
res.redirect('/users/login') // ignored
}
}
I am trying to set up a simple authentification system with Parse Server:
app.js
...
app.get('/login', (req, res) => {
res.render('login.ejs');
});
app.post('/login', (req, res) => {
console.log('POST /login\t' + util.inspect(req.body));
driver.login(req, (err, user) => {
//Here, user is defined
if(err) {
res.redirect('/login');
} else {
res.redirect('/user');
}
});
});
...
driver.js:
...
function login(req, callback) {
var username = req.body.username,
password = req.body.password;
Parse.User.logIn(username, password, {
success: (user) => {
callback();
},
error: (user, error) => {
callback(JSON.stringify(error));
}
});
}
function isLoggedIn(req, callback) {
console.log('isLoggedIn?');
console.log(util.inspect(req.user)); //undefined
if(req.user) {
callback();
} else {
callback('Not logged in');
}
}
...
When I access /login, I can login just fine, and get redirected to /user without any error, but on /user, which use isLoggedIn as a middleware, req.user is undefined.
I have seen others with the same problem when searching, but the post where either old (<2015), using another part of the JSSDK (react/browser), or just didn t get any answer.
I know I could use session, and recreate the user each time based on that, but it feels really hackish, is it really the supported way?
You have two routes to go, either have a REST-full server, which means users are not persistent between route calls, STATE-full and use sessions.
Luckily there is a really good nodejs authentication middleware already build that will handle all this session managment. This is called passportJS. Documentation can be found here: http://passportjs.org/docs
You can not only have authentication through local logins, but have support for authentication with google, facebook, github and many more. This is done through what are called Strategies. You use google-strategy for having google oauth, facebook-stradegy for facebook oauth, etc.
What you would be looking for is a local-strategy, which is called this because you want to authenticate with local user credentials. This strategy can be found here: https://www.npmjs.com/package/passport-local
you will need both passport and passport local and to install simply run
npm install passport passport-local
From there, just go through the documentation I have linked above for how to set everything up.
To develop my answer to blablabla comment, who asked what I ended up using.
In my case, I was develloping a REST API, and the session data wasn't expected to change once connected.
So what I did is delegate the session to the client, and go full stateless, by using JWT.
When the client is authentified, I encrypt his session data in a Json Web Token, and send him. When he try to access a protected page, he send me the JWT, which I can decrypt, and recreate req.user based on the information within.
My middleware look like this:
function isLoggedIn(req, res, next) {
//If there is a token
if(req.headers != null && req.headers.token != null) {
//Verify it and extract the user's data
verify(req.headers.token, (err, user) => {
if(err != null) {
res.status(401);
res.json({error: err});
} else {
//Recreate req.user
req.user = user;
next();
}
});
} else {
res.status(401);
res.json({error: 'No token'});
}
}
function verify(token, callback) {
//Verify the token
jwt.verify(token, jwtSecret, (error, user) => {
if(error != null) {
callback(error);
} else {
Separately check if logged into Parse
parse.isLoggedIn(user, (error, loggedIn) => {
if(error != null) {
callback(error);
} else if(!loggedIn) {
callback('Not logged in the Parse');
} else {
callback(null, user);
}
});
}
});
}