Node.js/Express - how to access session data through method(using sockets)? - javascript

I've stored some Oauth data in session, and now I'd like to access it again, so I created a local API endpoint to feed that access token. It appears that if I make that request via a method though, it doesn't contain the request body, so it can't actually get the req.session.access_token.
Visiting this endpoint provides the right data if typed into the address bar, but the response is undefined when requested through a method. The method is being called through a socket, if that helps inform the advice.
//This is the endpoint
app.get('/instagram/accesstoken', function(req,res){
console.log("/instagram/accesstoken: ", req.session.access_token, ", req: ", req);
res.json({access_token: req.session.access_token});
});
//This is the method calling the endpoint
function getAccessToken(callback){
request({url: 'http://localhost:3000/instagram/accesstoken', method: "GET"}, function(err, resp, data){
console.log("getAccessToken: ", data);
if(err) { return callback(err); }
callback(null, data);
});
//Sockets
io.listen(server);
io.on('connection', function(socket){
...
getAccessToken(function(err, token){...}
...
});
I'm open to alternative solutions as well. How can I feasibly get access to the session data? Thanks for your patience, and for taking a look.

Used express and socket.io for just a few days but here's a bit thought:
1. You're having problem getting req.session, which is picked up by the server from its session storage. The server does this with the help of sessionid(usually named sessionid or sid) stored in the browser cookie, which is sent in the headers of every request. So you should probably check the request headers(on the requests made after the socket connection) to see if the cookie is correctly sent and whether it is including the sessionid we want.
2. You're telling the client to request the accesstoken on your site when the socket connects so the server can get the Oauth access_token to request or send infomation to other apps(if I understand correctly). This is a bit of an overhead(one too many request) since you may just get the session id from socket request's header and then get this user's session data with it. However this may need a little tweak since the framework's session functionality can't check the session id from the req object automatically. This can be a bit difficult if the session functionality doesn't provide relevant functions so you'll have to dive in the framework. But it's an alternate if plan 1 doesn't work out(and is also more elegant since it saves one request :) (but may be harder as well :( ))

To access session data via sockets you need to use a plugin like https://www.npmjs.com/package/express-socket.io-session
With this you can access session data via socket calls.

Related

How to handle jsonwebtoken from front end

I'm working on a full stack project where users can create account, visit their profile, create blogs, read their blogs, delete their blogs etc. In order to perform all these tasks (except signup and login) the user has to be authenticated.
I'm done with the back end but i don't understand how do i send jsonwebtoken from the client side to the server side (i know how to send it from the server side). I know how to get tokens from the server and store them in browser's locaStorage but i don't know how to send them back to the server when i'm making request for reading blogs or deleting blogs or visiting back to my profile after reading all my blogs.
If i do this -
window.location.href = "/blogs";
then i won't be able to send authentication token or i should say i don't know how to send authentication token using this approach.
Here on stack overflow i read about this technique-
window.location.href = "/blogs?token=";
but i don't think developers uses this technique in their projects because as far as i know tokens are supposed to be sent through headers.
If i summarize my question i just want to know how do i send authentication token to the server as well as change the page for different routes for example a different page that shows all my blogs and another page that shows only my profile. If someone else who is not authenticated tries to visit profile route or blogs route, would get a 401 error.
It would be a great help if anyone could solve my confusion or suggest me a book or an article that solves my confusion.
I will try to make it simple. As an example, I will use code from one of my project.
First, you do not explain how you check and validate token on server-side. So to make explication more complete, I will provide some code.
On the server-side, I use a simple function to check each request received and depending on verification and validation process, I will update the request received before sending it to resolver.
NB: current code used Express
In my example, I store the token inside the request header Authorization field.
const isAuth = async (req, res, next) => {
const authHeader = req.get('Authorization');
// if is no authorization field in header, we call
if (!authHeader) {
req.isAuth = false;
return next();
}
const token = authHeader.split(' ')[1]; // `Bearer XXXXXXXXXXXXXXXXXXXXX...`
if (!token) {
req.isAuth = false;
return next();
}
// Here i decode the token
const decodedToken = jwt.verify(token, 'SomeSecretWord');
req.isAuth = true;
return next();
}
On each request received, we check if the header contain an authorization token, if yes, we validate and verify token. If validation is successfully completed, I update isAuth field inside request and set it to true.
app.use(isAuth);
Now you will be able to access the isAuth inside resolvers and return data based on its value (example: throw error if false);
So now, for the client-side, since we expect token to be store inside the headers Authorization field, we need to set it before sending request.
Be sure to already have the token save on client-side.
In my case, user need to login to receive a new token so he store the newly created token inside client-side storage.
Now before sending each request, access token from storage and updare request header with it.
const headers = {
Authorization: "Bearer XXXXXXXXXXXXXXXXXXXXXX",
};
const reqInit = {
method: 'GET',
headers: headers,
};
// send request using fetch
fetch('/someLocation', reqInit)
...
The problem I faced here, was to store the token between requests for a user session.
the easiest and secure way is to save it in the local or session cache (according to google after a small research) and access it on each request.
While creating the json web token on server-side you can specify a expirery so if token was not used for a certain time, it will be invalid and user will need to reauthenticating to receive an other token and save it in his client-side storage.
After some research, I decide to rewrite my backend with graphql (apollo-server
/ express) for server-side and apollo-client for client-side.
since apollo-client provides a library to manage local cache on client-side, it simplifies the task.
I hope I have answered your question and that can help you and sorry if I made a mistakes.
Add authorization header to your request
headers: {
"authorization": "Bearer your_token"
}
Its and example for adding header to ajax request.

serverside rendering with no client-side javascript

I am trying to create an application that can post data both through ajax and through traditional form requests. I am surprised by the lack of information I am finding online about the topic. I guess these days we all assume we have access to client side JS?
I went with express-session, but am getting frustrated at how hard it is to determine what's actually happening. From what I can understand it's cacheing cookie data on the client and somehow including those in requests automatically? Then is it safe to assume that this format will NOT work without client-side javascript support?
Given a form like this:
<form method="post" action="/create">
<input name="value1" onChange={this.handleInput} value={this.state.value1} />
<button onClick={this.submitForm}
</form>
My requests sent via ajax will pass auth (due to having session data):
event.preventDefault();
postUrl(`/create`, {value1: this.state.value1})
.then(jsonRes => {
// works
});
being picked up by auth middleware which uses express session and passport:
module.exports.secured = (loginUrl = "/employers") => {
return (req, res, next) => {
if ( (req.isAuthenticated()) ) { return next(); }
req.session.returnTo = req.originalUrl;
res.redirect(loginUrl);
return next();
};
};
which protect a pretty simple api route for creating:
router.post('/create', secured(), (req, res) => {
My thinking is that even if JS is enabled, I could handle the request at this route, but the problem is with authenticating.
What can I do to get my session data sent over in these 'non-js' requests?
I remember in traditional webstacks like Rails or PHP some sort of token is rendered into the form in a hidden field or in the action on render. If this would work, does anyone know how to get the 'vital data' so to speak out of the express session to send as the token? Not possible?
Looking in req.cookies or req.session of the req object that gets parsed in the serverside render, I do not see anything that would be useful for this.
What can I do to get my session data sent over in these 'non-js' requests?
Ussually the response to your login would send a Set-Cookie header to indicate to the client that it should store said cookie, implying it would be used to identify himself
Who stores cookies? its not javascript but the browser, so if you used curl or a scraper , your clients would have to fetch the cookie returned and include it in subsequent requests
What you mention about a token in the form is not for authentication but for cross site request forgery, meaning that since you served a token (and stored it somehow server side) you would only accept a login request including said token (proving someone navigated to your site's login page) so as to prevent other websites or clients who didnt went to your login to attempt POSTing (ie: a scraper )
Also, sessions dont necessarily mean authentication, modern frameworks tend to issue a session regardless if authenticated

What is the best way to access the JWT from node?

I have implemented JWT authentication using Node.js. When the user signs in, Node.js signs/creates a JWT and sends it back. Thereafter, it is stored in the localStorage. Now, this is probably where I am going wrong, but... to move forward, I make use of the express router, and within the router code (which is obviously at the node level) I want to be able to access the token (which is in localStorage) so that I can make a call to the API for further data. However, I just realised that localStorage is at the client-end and that node/express/router doesn't recognise localStorage. So I am stuck. Obviously, I am doing something fundamentally wrong... I should not need to access localStorage from the express router file. Perhaps, I should really be making the API calls not from the express router file, but from client side.
Any hints/directions?
localstorage is bad way to save token. you should save token in cookies and use then where you want.
EXAMPLE:
new Cookies(req,res).set('access_token',token,{
httpOnly: true,
secure: true // for your production environment
});
and then read:
var token = new Cookies(req,res).get('access_token');
You need to send the JWT that is stored on the client side every time you make an API request to the server side.
https://jwt.io/introduction/
Scroll down to the section How do JSON Web Tokens work? The JWT should be sent in the header of the API calls in the form:
Authorization: Bearer <token>
How you do this depends on how exactly you'll send the HTTP requests to the API, but it should be pretty simple in any respects. You can find out about how to add Headers to an angular $http request at this link:
https://docs.angularjs.org/api/ng/service/$http
Then it's up for each of your authenticated express routes to check the headers, pull the JWT out, ensure that it's valid, and then proceed with the request (or halt it if the JWT is invalid).

Express Session and Cookie

I don't understand how serializing and deserializing work with express session.
When I installed Express-session it said that I needed a serialize and deserialize function:
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
Server.js Post route from login form:
router.post('/login', passport.authenticate('login', {
successRedirect: '/home',
failureRedirect: '/',
failureFlash : true
}));
My question is when the user attempts to login from the form on my HTML and hits the endpoint as specified above '/login', is this where express session comes into play? So express session will create a cookie with a session id as user._id as specified in my serializeUser function and it will give this cookie to the client? So now when the client makes any subsequent requests to that same server at the endpoint '/login', it will automatically call deserialize user without going through the passport middleware that is provided in the router.post('/login', ...)?
I am not sure when and where these two serialize functions are called and how express session actually uses them? Any clarification would be appreciated.
To understand this, we have to go through the basic idea of what is a cookie and how does it work?
Cookie:
It is collection of data that is stored in computers browser and is sent with every request to the server in request headers and received by the browser from server in response headers.
What is need of a cookie?
Now we know that http requests are stateless (means every request is a fresh request for server that is for example if u login to some website which is the first request made by you and then u make a second request to display your profile then at this point server does not know who are u), so for authorisation the server needs to know who u are and this information is stored in a cookie.
When u log in , ur credentials are send to the server and server sets these credentials in cookie which is then send to the browser , and after that every request u make , that cookie is send back to the server which is then verified and hence allowing u to access the relevent information.
Now a point should come into your mind that are cookies safe for storing users credentials?
The answer is a big NO , as as the user can manipulate it at his/her leisure . Yes a cookies data can be manipulated anytime , so its not safe to store user credentials in cookie , so whats the solution ?
Here we come to idea of sessions.
Sessions:
Session is an object that is stored in server side instead of browser and hence remains safe. Now how it helps in authorisation , see:
When user signs in , request is sent to server and an object session is made which stores the credential of users and this session object is given a unique id which is encrypted using that serializerUser() function and this id is stored in cookie and which is then send to browser. Now the user if try also to manipulate it , he/she cannot as the cookie just contains the session id which is encrypted and can not be decoded by any means.
And then this cookie is send to browser with another request which then goes through deserializeUser() function and gets decoded which matches with the stored session id hence verifying the user.

Token based authorization in nodejs/ExpressJs and Angular(Single Page Application)

In my application,while registering the users i am saving username,password and jwt generated token with these fields in MONGO DB.When user tries to login with correct credentials then i will send the response with stored token.Then at client side(In my controller) i am using the localstorage to store the token so that i can send the same token for each and every request sent by the client.But I found some issues regarding this procedure:
I am generating same token for one user every time.So if any third person is able to get the token then he can access the restricted page.
Am i wasting space in db by storing the generated token in MONGODB
Can Anyone access the token stored in localstorage other than the user.
for each and every request in my single page application,I am again querying mongodb to get the token for that user and validating.Here,I am checking both client side and server side.
I am using jwt to generate tokens,Node,Express,Mongoose in my application
Am i following the good procedure.If not,can you please provide the solution for my approach or any new approach.
I have searched many sites for token based authorization and session based authorization,But nothing worked for me.
Note:I am beginner for Nodejs,AngularjS
You should store token in advanced key-value cache tool like: Redis
That would improve performance remarkably.
You will get token from database for 1st time then it should be stored in Redis. I used to set token as key and username as value. Next request , the token will be given from cache. with Redis you can set expire for token.
When a user registers, you would need to generate a JWT like you're doing now. That's OK. You don't need to save it to the database however. You didn't ask but I assume that the password should not be stored in clear text. You can use something bcrypt to encrypt before saving it to the database.
When user tries to login with correct credentials then i will send the response with stored token
Yes, that's correct way to do.
Then at client side(In my controller) i am using the localstorage to store the token so that i can send the same token for each and every request sent by the client.
Yes, on the client side, you can save the JWT to local storage and send it in subsequent requests to the server.
Now your bullet points:
So that you won't have the same JWT each time, you can include an "exp" claim in the payload (I'm assuming you're using something like jwt-simple to generate a JWT). Something like:
var payload = {
sub: account.username,
exp: moment().add(10, 'days').unix()
};
var token = jwt.encode(payload, "secret");
You don't need to store the JWTs in the database. In some cases, the token issuers (the authorization servers) are not the same as the resource servers. The resource servers only receives the JWTs in a request but there's no way for the resource servers to touch the database used by the authorization servers. Side note: If you eventually need to support refresh tokens, i.e. the JWTs that you hand to the clients will need to eventually expire, then you can store the refresh token in a database. Refresh tokens are not the same as JWTs (access tokens). The complexity to support refresh tokens will increase.
Local storage is not where you store passwords, but it can be used to store JWTs. For that very reason, a JWT must and should expire after a certain time.
Not sure what you mean by saying you check both client side and server side. When the client needs to access a resource (again it's fair to assume that the resource server might not be the same as the authorization server), the only thing that the resource server is passed is the JWT. Anyone can decode a JWT. For example, try to paste your JWT on this site http://jwt.io/. That's why a JWT should not contain any sensitive data. But if the resource server knows the secret that the authorization server uses when it encode the JWT, the resource server can verify the signature. Back to your third bullet, that's why it's OK to store the JWT in local storage of the client.
Update I'm updating this to answer to some of your questions in the comment box.
User clicks on 'Login' button triggers the Angular controller to post a request to the server, something like:
$http.post(url, {
username: $scope.username,
password: $scope.password
}).success(function(res) { ... })
Server receives the POST request, it checks username/password, then it generates a JWT, and sends back to the browser. Note that it does not have to save the JWT to the database. The code would be something like
var payload = {
sub: account.username,
exp: moment().add(10, 'days').unix()
};
var token = jwt.encode(payload, "secret");
res.status(200).json({
token: token
});
Back on the client side, in the success() callback above, now you can save the JWT in local storage:
.success(function(res) { $window.localStorage.setItem('accessJWT', res.token) })
The user is now authenticated. Now when user wants to access a protected resource, user don't have to provide username/password. With the JWT which can be retrieved from local storage, the client can now put the JWT in the Authorization header of the request using the bearer scheme, and sends the request to the server. In code, it would like:
headers.Authorization = 'Bearer ' + token;
The server receives the request. Again, this server receiving this request does not have to be the same as the server which generates the JWT above. The 2 servers can be in 2 different continents. Even if you save the JWT above, that does not do any good to this server which can not access the database where the JWT is stored. But this server can pull out the bearer token from the header of the request, validates the token and carries on with the normal tasks.
Hope this helps.
You do not want to store the JWT in mongoose because it appears in headers when logging in. You first generate a token then hash it using a module like crypto.
There are different ways to do this and they all use Passport which handles the tokens. Here's an example project Satellizer
I would recommend you generate the angular-fullstack project. Then go through the server/auth folder and the client/account folder. You will see how to securely handle authentication in a MEAN based app.

Categories

Resources