I am trying to deploy an application that uses passport facebook strategy. I've been testing my app on localhost first and then tried to deploy it to AWS.
Everything seemed working fine on my local machine, but when i deployed i tried logging in with multiple facebook accounts.
I saved the received variables in an api call and retrieved those via angular
However, my first authenticated user, everything seems working fine, but when the second user authenticates it will override his variables like username, profile image etc.
I know why it is doing this. But i don't immediatly have a solution in mind.
Here is my server side code when i authenticate
app.get('/login/facebook',
passport.authenticate('facebook'));
app.get('/login/facebook/return',
passport.authenticate('facebook', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
UserID = req.user.id;
UserDisplayName = req.user.displayName;
UserProfileImage = req.user._json.picture.data.url;
console.log(req.user._json.picture.data.url)
var User = UserID + UserDisplayName;
var ProfilePicture = UserProfileImage
res.json({name: User , url: ProfilePicture});
});
app.get('/profileInfo', function(req, res){
var User = UserID + UserDisplayName;
var ProfilePicture = UserProfileImage
res.json({name: User , url: ProfilePicture});
});
How do you store your users?
From your code i quess that you save your user's id in UserID variable but when next user logs in it will get overwritten.
I'm only quessing since i can't see your whole code but try something like this:
var users = {};
app.get('/login/facebook/return',
passport.authenticate('facebook', { failureRedirect: '/login' }),
function(req, res) {
// save user to users object
users[req.user.id] = {
displayName: req.user.displayName,
profileImage: req.user._json.picture.data.url
}
res.redirect('/');
});
// you need to use some kind of sessions or cookies to know which user this is
// for simplicity let's assume you get profile by user's id /profileInfo/:id
app.get('/profileInfo/:id', function(req, res) {
res.json(users[req.params.id]);
});
Related
In my node project I have the following basic code to connect to Azure via a token. The login/logout works great together with our Azure:
const express = require("express");
const msal = require('#azure/msal-node');
const SERVER_PORT = process.env.PORT || 3000;
const config = {
auth: {
clientId: "XXX",
authority: "https://login.microsoftonline.com/common",
clientSecret: "XXX"
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: msal.LogLevel.Verbose,
}
}
};
const pca = new msal.ConfidentialClientApplication(config);
const app = express();
app.get('/', (req, res) => {
res.send("Login Logout");
});
app.get('/dashboard', (req, res) => {
// check here for valid token...
});
app.get('/login', (req, res) => {
const authCodeUrlParameters = {
scopes: ["user.read"],
redirectUri: "http://localhost:3000/redirect",
};
pca.getAuthCodeUrl(authCodeUrlParameters).then((response) => {
res.redirect(response);
}).catch((error) => console.log(JSON.stringify(error)));
});
app.get('/logout', (req, res) => {
res.redirect('https://login.microsoftonline.com/common/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000/');
});
app.get('/redirect', (req, res) => {
const tokenRequest = {
code: req.query.code,
scopes: ["user.read"],
redirectUri: "http://localhost:3000/redirect",
};
pca.acquireTokenByCode(tokenRequest).then((response) => {
console.log("\nResponse: \n:", response);
res.sendStatus(200);
}).catch((error) => {
console.log(error);
res.status(500).send(error);
});
});
app.listen(SERVER_PORT, () => console.log(`Msal Node Auth Code Sample app listening on port ${SERVER_PORT}!`))
But how to properly check after that logging in if the token is still valid?
So the question is, how can I be save that the user on /dashboard has still a valid token or is logged in?
app.get('/dashboard', (req, res) => {
// check here for valid token...
});
At the end I need a node.js application that:
is safe (token-based)
has user auth (msal)
can give granular permissions on routes
Can I do all that in node.js or better doing that in client-side? But am I then reducing the security?
Once you get your authentication result the first time, this should have received tokens if authentication was successful. You should be able to parse the Id token to get information about the user. You can then use that information to create a session via the web framework that you are using. The session can be used thorough out the web app to give you information like if the user is authenticated or not, how long they are authenticated for, and what they have permission to access. Usually web frameworks will create a cookie with a session id so that requests coming in will be able to have session information, and the user won't have to authenticate every time.
If the session expires, you can try acquiring a token silently (without prompting the user) by using the token cache that is part of MSAL. When you call acquire token silent, MSAL will automatically check if the access token is valid, if not it will try to refresh the access token via the refresh token. If neither are valid, they will return an error. At this point you can fall back to prompting the user again to authenticate (via the code that you have already shared).
I found a kind of dirty way to solve my issue. Could you maybe tell me if that is a proper way? Also my solution is not safe as the user could change the client-side JS code and ignore the user auth.
Create HTML file for /dashboard:
app.get('/dashboard', function(req, res) {
res.sendFile(__dirname + "/" + "index.html");
});
and here using this JS code:
var headers = new Headers();
var bearer = "Bearer " + "ey...........Ac"; // <---- accessToken
headers.append("Authorization", bearer);
var options = {
method: "GET",
headers: headers
};
var graphEndpoint = "https://graph.microsoft.com/v1.0/me";
fetch(graphEndpoint, options)
.then(resp => {
// when error redirect to ... otherwise do log:
console.log(123);
});
on the <---- accessToken putting a valid token and it works. Only when token is valid the console.log is done.
So this works, but as I said, if the user is manipulating the code he can still see the page. Also the page is loading until the script is fired. So I cannot see a real value on this. This should happen on server-side somehow. Any idea?
Using the silent-flow was a good idea. It works great on my example.
https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/samples/msal-node-samples/standalone-samples/silent-flow
This works with the PublicClientApplication and acquireTokenSilent works also as expected.
Hello guys I'm new to Node so please bear with me.
Anyway I am currently working on authentication for my new Node app. So far I was capable of getting everything basic working (login, register, logout). I am now entering the settings page of my user profile but I cannot access {{username}} or {{email}} for example, it either stays blank or throws back an error.
I was wondering how I can make the username, email and other info stay in the session or able to access it once my user is logged in, and how I can add more information to the session later (this is important as I will need to do it).
Here is my code:
Registration (not including verification)
var newUser = new User({
username: username,
email:email,
password: password
});
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
req.flash('success_msg', 'You are registered and can now login');
Login:
router.post('/login',
passport.authenticate('local', {successRedirect:'/', failureRedirect:'/users/login',failureFlash: true}),
function(req, res) {
res.redirect('/');
});
I'm not sure exactly what code I need to show but if you guys need to see anything else to help me please let me know.
I'm using Node.JS with express, passport and handlebars.
Thank you!
I was wondering how I can make the username, email and other info stay
in the session or able to access it once my user is logged in, and how
I can add more information to the session later (this is important as
I will need to do it).
There is a pretty good NPM module for this use case :
https://github.com/expressjs/session
I have made quite good experiences with it.
Just install it via NPM and then :
var session = require('express-session')
This is how you use it:
// Use the session middleware
app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
// Access the session as req.session
app.get('/', function(req, res, next) {
if (req.session.views) {
req.session.views++
res.setHeader('Content-Type', 'text/html')
res.write('<p>views: ' + req.session.views + '</p>')
res.write('<p>expires in: ' + (req.session.cookie.maxAge / 1000) + 's</p>')
res.end()
} else {
req.session.views = 1
res.end('welcome to the session demo. refresh!')
}
})
As i am getting from your description is that you have problem regarding sessions.
for this you can visit https://www.npmjs.com/package/session-storage to Include session-storage into your project it will help you better.
I'm using express framework , Lets say I have this line in the API :
router.delete('/user',(req, res) => { //deleting...}
Now I want that only an Admin will be able to access this line.
In the rest of the code there are lines that only user can access like :
router.put('/post')
And lines only admin can access like:
router.put('/killDB)
what is the best way (tokens, sessions or something like that) that will be able to help me differenitate between the two?
Use password to authenticate users and then check if the user is an admin. And then simply add password logic to your route. Below I will provide my code where I just check if user is logged in (it was enough for me)
router.get('/delete', isLoggedIn, function (req, res) {
Page.collection.drop();
var page = new Page();
page.save(function (err) {
if(err) throw err;
res.redirect('/admin');
});
});
// render login form
router.get('/login', function (req, res) {
res.render('login',{ message: req.flash('error'), layout: null});
});
// process the login form
router.post('/login', passport.authenticate('local-login', {
successRedirect : '/admin', // redirect to the secure profile section
failureRedirect : '/login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
You can use the connect-roles package to authorize your users, and then route them to those URL's which they are allowed to access.
You can also opt for passport.js, however it is more or like a authentication package where as the connect-roles just aims at to provide only the "authorization" part. And this package works well with Express.
Once you implement this package, you can use the "role" attribute to check the user's authorization level and allow them to perform their respective actions.
For eg.,
if (req.user.role === 'admin') {
router.put('/killDB)
}
You can check out the package here: https://www.npmjs.com/package/connect-roles
Hope this helps!
I have 3 files : app.js, index.js(routes), Users.js(controller)
Once my user is loggedIn (verification done between POST information and DB) i want to save data in a session using expressjs/session.
Here is the declaration of my session in the app.js :
var session = require('express-session');
app.use(session({
resave: true,
saveUninitialized: true,
secret: 'trolololo'
}));
Here are my routes :
router.post('/login', function(req, res, next) {
Users.login(req, res);
});
router.get('/getSessionInfos', function(req,res,next){
console.log(req.session);
});
And here is the controller for the login :
login : function(req, res){
var formEmail = req.body.email;
var formPassword = req.body.password;
User.findOne({ where: {email: formEmail} }).then(function(user) {
if(user){
if (user.password == formPassword){
console.log('User connected');
req.session.email = formEmail;
req.session.password = formPassword;
console.log(req.session);
res.status(200).send('User Authentified');
}else{
res.status(401).send('Invalid Password');
}
}else{
res.status(401).send('Username');
}
});
},
The Login works I get the 200 status and my console.log in the login function displays a function with my infos. But when i try fetching my session from the /getSessionInfos URL it is empty... Please send help
I know you did not ask this, but i will state it either way, sessions are not recommended in node any more, json web tokens are pretty much the at the throne.In essence it's a signed piece of data in JSON format. Because it's signed the recipient can verify its authenticity. Because it's JSON it weights very little.
In very simple terms, JWT are cool because you don't need to keep session data on the server in order to authenticate the user.
The user calls authentication service, usually sending username and
password.
The authentication service responds with a signed JWT, which says who
the user is.
The user requests access to a secured service sending the token back.
Security layer checks the signature on the token and if it's genuine
the access is granted.
You can use jwt-simple in npm.
Your Code seems correct only some changes
app.use(session({
secret : 'yourSecret',
resave : false,
saveUninitialized : false,
}));
Not forget to login first as you are storing the session value over there and then it will surely display the object with the email and password key .
Let me know if You face any problem.
I have a node express app , using express-stormpath for authentication/authorization
I have a GET route which is called with certain jquery parameters.
If the user is logged in everything is working as expected.
If not the user login screen is shown.
After stormpath authentication and authorization is done my query params are lost.
Is there any way to retain those?
app.get('/myRoute', stormpath.groupsRequired(['admin']), function(req, res){
console.log('req.query ',req.query);
//do somehting with the query data
res.sendStatus(200);
});
after authentication req.query is {}.
Any ideas?
Thank you for the question, I work at Stormpath and I'm more than happy to help. Our express-stormpath library is open source, and we're always happy to fix bugs and review pull requests.
Can you tell me which version of our library you are using? At the moment I'm not able to reproduce the problem you are seeing. Here is a quick example that I put together with the latest version, 3.0.1:
'use strict';
var express = require('express');
var stormpath = require('express-stormpath');
var app = express();
var port = process.env.PORT || 3000;
app.use(stormpath.init(app));
app.get('/admins', stormpath.groupsRequired(['admins']), function(req, res){
res.json(req.query);
});
app.on('stormpath.ready',function () {
console.log('Stormpath Ready');
});
app.listen(port, function () {
console.log('Server listening on http://localhost:' + port);
});
With this example, I do the following:
1.) Assert that I'm not logged in, by deleting all my cookies for localhost.
2.) Type /admin?foo=bar into the URL bar.
3.) I am redirected to the login page.
4.) I login with valid credentials.
5.) I am redirected to /admins?foo=bar, as expected, and I see the req.query object in the body of the page that is rendered. This is only true if the user is in the admins group, if they are not I will see the "Unauthorized" error message page.
Can you compare my steps and my example to your application, and let us know if there are any differences? Thanks!
I don't think that stormpath is removing query from request.
But we can check it by adding middlewhare before stormpath initialization:
var express = require('express');
var stormpath = require('express-stormpath');
var app = express();
// binding middleware to assign req.query to req.q param
app.use(function(req, res, next) {
req.QUERY = req.query;
next();
});
function restoreQuery(req, res, next) {
req.query = req.QUERY;
next();
}
app.use(stormpath.init(app, {
// Optional configuration options.
}));
app.get('/myRoute',
stormpath.groupsRequired(['admin']),
restoreQuery,
function(req, res){
console.log('req.query ',req.query);
//do somehting with the query data
res.sendStatus(200);
});