How can I access User Info with AngularJS after NodeJS verification? - javascript

I've seen a few questions regarding this but being new to both Angular and Node I'm struggling to find a proper solution.
I had this code, which worked for the login and I could only access my pages after being authenticated:
router.post('/login',
passport.authenticate('local',
{
successRedirect: '/',
failureRedirect: '/login',
failureFlash: false,
successFlash: false
}
));
router.all('*', ensureAuthenticated);
function ensureAuthenticated(req, res, next) {
console.log("in ensureAuth", req.isAuthenticated());
console.log("session data", req.session);
console.log("user data", req.user);
if (req.isAuthenticated())
{
return next();
}
res.redirect('/login');
}
The local passport authentication I have returns an object after verifying if the user exists and allows login, as such:
return passportDone(null, result.rows[0]);
with result.rows[0] being the user info I want.
What I had in the front end is a simple ng-submit in the form that calls the "login(credentials)" with credentials being set by ng-model in their respective fields (username and password).
My question is how can I return all the info I want, such as user_role, name and stuff, so I can present it in the front-end as {{user.name}} for example?
The info needs to stay after refreshes so $scope isn't an option from what I've read.

What you probably want to do here, is create a custom route for fetching this information. for example: "/me".
In this route, you can serve the information you now probably store in your session variable.
Another solution, depending on how your application works with authentication, is to inject the userinfo (For example if you log in, and get redirected to a new page, you can inject the userinfo into the new page as a js variable) or to return the userinfo in the response if you send a ajax request to login and dont get redirected to a new page by the server.

I hope you are using passport.js local authentication.I would recommend to store user infomation after authentication in cookies as a json webtoken or using some other encryption.And you should expose an api(/api/is-authenticated) which is used to check whether the user is authenticated, by sending the token stored in cookies.when ever you refresh or navigate to other routes make an api(/api/is-authenticated) call to check whether that particular user has already authenticated or not.

Ok, I got it.
I already had the service and all but the problem was with passport's successfulRedirect. It returns the html you want when it succeeds, which is fine. However, since I wanted the user info, it wasn't enough. What I did was create an /account route that returns the req.user info, which I then handle in the front end and form a cookie with it. What basically happens is:
post_login->verify_user->success->get_account->form_cookie->render_html

Related

I want to understand how passport js work specially req.user and how data is populated

I am new to node js and tried passport for authentication, i found it hard to understand the work flow.
so my question is what is actually req.user where it came from ?
is it something constant related to passport and can't be changed to anything else like req.profile ?
Secondly in the following html code
<p>
<strong>id</strong>: <%= user._id %><br>
<strong>username</strong>: <%= user.local.username %><br>
<strong>password</strong>: <%= user.local.password %>
</p>
From where html is populating user object, neither my database schema nor my passport contain the word user
This is my database schema
local:{
username : String,
password : String
}
Thanks
I'll show you where req.user comes from without using passport. First thing you need to understand is a middleware in express is just a function that takes in request, response and a next function.
let's say I have an endpoint:
POST /auth/login that takes a username and password.
This endpoint could return an access token (random string generated by you and stored on the database, if you don't want to store on your database you could look into JWT).
Ok, now that you have that access token after login success.
You can pass it along with other requests to your server.
Let's say another endpoint:
GET /auth/profile which is protected and only can be access with the right access token.
But what is protecting the route? It's a middleware.
Below we define a checkAuth middleware.
function checkAuth(req, res, next) {
// here I can retrieve accessToken from the request header
const accessToken = req.get('accessToken')
// with this accessToken I can query the database and check if this access token is correct or not
findUserWithTheAccessToken(accessToken)
.then(user => {
if (user) {
// Here's the answer to your question where `req.user` comes from.
req.user = user
next() // call next() so it can go to the request handler
} else {
throw new Error('Invalid access token.')
}
})
}
// then your router would look something like the following
router.get('/auth/profile', checkAuth, handler) // implement your handler ☺️
You can always check express website to learn more.
passport=> Passport is authentication middleware for Node.js. and its easy to implement.
login page send username and password to passport.
It will check with your database which is configured by you.
get success then the passport will store user details into req session form that you can retrieve it wherever you want by using your req

Why "req.user" always empty in the /user/me controller after validation with sails-auth?

I'm currently getting started with Sails.js, and I want to add user accounts to my toy app, so I installed the "sails-auth" package that creates a Passport-based user authentication system. I can create new users by sending POST /user, and I can sign in with POST /auth/local.
The documentation says:
Authenticate with the local strategy via a POST to /auth/local with params identifier (email) and password). This will also create a session. See passport.local for more.
However, when I try to GET /user/me, which routes to a controller action that should return the current user in the session, the page instead gives an empty response. Why is this happening? Is there some kind of configuration step that I'm missing?
By the way, I haven't changed or messed around with the sails-auth package. It's still completely new; the "me" action looks like this:
me: function (req, res) {
res.ok(req.user);
}
EDIT: I've found a temporary workaround by searching the issues in the sails-auth repo. Instead of getting a user object from req.user, you can get a string user ID from req.session.passport.user.
Your me action as written is only going to return whatever you are passing in as the user param. Sails builds on top of Express.js so req is the request from the browser and res is the response to the browser.
Most likely you are sending the data to your me action in the req body which is why your response is blank, simply put, req.user is empty so the response is empty. In that case you would access it with req.body.user, you could also try var user = req.params();
For debugging and just generally getting a feel for how the req and res objects are structured I suggest you always start sails (in development, never in production) with the verbose flag.
sails lift --verbose
Then you can do this:
me: function(req, res){
sails.log.verbose(req);
res.ok(req.user);
}
And have it print out the entire req object so you know what's in req.user.
Typically though you would do a database lookup as the user param would be an id. Which means your me function might look (something, obviously depending on your dbc it might be pretty different) like:
me: function(req, res){
var userId = req.body.user;
User.find({'user_id': userId}.exec(function(err, user){
if(err){
//tell peeps there was an error
}else{
res.ok(user);
}
});
}
Best debugging for routes and for the request object:
'/*' : function(req, res, next) {
sails.log.verbose("method: ", req.method, "\n body: ", req.body, "\n url:", req.url);
next();
},
Just paste that at the start of your routes module.

Server authentication on page request in nodeJS, angularJS Application

I am using passport.js for authentication. My requirement is that, anyone should not be able to access a particular page (say, '/restricted'), if one is not logged in.
Right now, in my application, anyone can access "localhost:3000/#/restricted" url directly.
I am able to stop this and allow only logged in users to access the page by using Rorschach120's solution in
Redirect on all routes to login if not authenticated.
But this is done client side and is not that secure, because anyone can access this code from browser.
So I need that the request for my page goes to server, I tried moka's solution in How to know if user is logged in with passport.js?:
In app.js:
app.get('/restricted', loggedIn, function(req, res, next) {
// req.user - will exist
// load user orders and render them
});
where the loggedIn() function checks if user is logged in or not.
But this middleware is NEVER called and anyone can still access the "restricted" page.
What can I do, so that this gets called?
I am new to AngularJS and NodeJS. Am I doing something wrong here?
Any help will be appreciated.
You can use middleware for that purpose.
app.get('/secure-route', secureMiddleware, myMethod)
let secureMiddleware = function(req, res, next) {
authCheck(...)
.then(function(result) {
// pass
next()
})
.catch(function(err) {
res.status(401).json({
code: 401,
message: 'restricted route'
})
})
}

PassportJS - Dynamically set state to allow redirect on callback

So I'm working off the information that was given here to add the ability that Google will redirect to the page a user was at before it redirected to google. I'm currently using the latest versions of Express, PassportJS, and Google oauth2.
For example, if a user hits page http://example.com/privatecontent, it'll automaticially redirect to Google asking to sign in, and after it's sucessful it returns to my Node App, except it doesn't know the last page was /privatecontent and instead redirects to the index.
If I understand right, I can use the state parameter to let Google know to send the state param back so I can read it and redirect myself.
I essentially would like my function to look a little something like this, but I don't have access to req.headers, or just don't know how honestly within passport.authenticate.
app.get("/auth/google", passport.authenticate("google", {
scope: ["https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/userinfo.email"],
state: base64url(JSON.stringify({
lastUrl: req.headers['referer']
}))
}), function(req, res) {});
Make a custom middleware
function myCustomGoogleAuthenticator(req, res, next){
passport.authenticate({
scope: ...
state: // now you have `req`
})(req, res, next);
//^ call the middleware returned by passport.authenticate
}
Add that to your route instead
app.get("/auth/google", myCustomGoogleAuthenticator, function(req, res) {});

Node and Angular cookie path

I'm working on a login/out functionality for my web application. When the user logged in my NodeJS(Express) server sets cookies variable called "user" on .mydomain.com with path '/'. Then I use AngularJS to access user cookies. It reads it fine from any page under my domain, but when I want to log the user out. I try deleting the cookies value, but it doesn't delete it on any other pages than the index page ('/').
I know there's something to do with the cookies path, but as far as I know it's ok to read/write cookies with path '/' form anywhere in the same domain. Is that not the case?
Setting the cookies, NodeJS
res.cookie('user', JSON.stringify(response.user), {
expires: moment().add('d', 2).toDate(),
path: '/',
domain: '.mydomain.com'
});
Deleting the cookies from /myPage/page2, AngularJS
delete $cookies['user'];
Is there anyway this could work?
Thanks!
I usually post to the server.
So, on the client side, I have something like:
$scope.logout = function() {
$http.post('/logout').then(function(){
$state.go('login');
});
};
and on the server side:
app.post('/logout', function(req, res, next) {
delete req.session.user
req.session.regenerate(done);
res.json(200, 'OK');
});

Categories