after successful login the user is redirected to the home page where the SPA loads. Is using session cookie with JWT a bad idea? - node.js

I have an express + postgres backend, and I'm using passport-facebook for FB oauth.
If a user hits my app at / without having a valid token in localStorage, they're taken to /login.
My /login page (where you're greeted with the familiar "Continue with Facebook" message) is server rendered (for various reasons). Upon clicking this button, I either verify the user if they exist and send them a session cookie with the initial JWT, or create a new user and send them a session cookie with the initial JWT. In both cases, the success condition is that they are redirected to / and served the SPA assets.
One of the first things the SPA does is take the JWT from the session cookie and put it into localstorage, and then deletes the cookie.
Is this a terrible approach, or is it valid in my use case?

You are using the session cookie as a means to store the JWT on the client. This means that you create a server session that will remain open until it expires, by spending server resources
Session cookies are not readable from javascript, so I guess you make a request to the server to get the JWT, right?
The process does not seem problematic, but I think you could optimize it by sending in your redirection process directly the JWT in the response using a regular cookie with set-cookie header. The cookie will be stored in client and you could access it directly

Related

Securely handling refresh token on a Vue application

I have a server backend that provides an access token and a refresh token when a user login is successful, and I want to store them somehow in the client's browser. For the access token, since it's short lived, I can store it in the browser's local storage, without having to worry too much. But for the refresh token, I'd like to set a more secure flow.
I've read this article fragment: Sending refresh token as an HttpOnly cookie, and using a cookie sounds like a safer approach to me, obviously not perfect though, so what I want to do is send the refresh token as a HttpOnly cookie to the Vue application.
So after logging in, for example, I'd like the server to set up that cookie and make the client include it with every request sent to the backend (is that how it should work?).
The problem I think I have, correct me if I am wrong please, is that since only the browser and not the javascript has access to that HttpOnly cookie, I can't make the library I use to make the requests (axios) to send the set refresh token alongside its future requests as a HttpOnly cookie as well.
How can I make that flow properly? Did I misunderstand something about how these cookies work?
Thank you in advance!

JWT auth in cookies with stateless server and no server side rendering

I am trying to implement jwt in cookies for auth on a single page application react front end which communicates with various node microservices running express.
I am doing this as it appears storing the jwt in sessionstorage makes the app vulnerable to XSS.
However, by using cookies, the apis are now vulnerable to csrf attacks.
Traditionally, csrf attacks are mitigated by creating a csrf token, storing it in a server session, then rendering it in a hidden form field.
Then, upon submitting the form, the value of the csrf token is checked against the server session value to check they match.
I cannot use this approach as:
- servers are stateless
- have no server side rendering.
So I am confused as to which csrf method I should employ.
I have read about double submit method, where you submit a csrf token on every ajax request, and have the same value stored in a cookie, then the server checks both for a match.
However, I cannot get the intial csrf token into the html in the first place as there is no server side rendering.
What is the best practice for achieving jwt in cookies with csrf protection in a stateless architecture with no server side rendering?
Simply don't store the JWT token in a cookie
CSRF attacks are possible because browsers will send cookies with HTTP requests, even if they are initiated by a script running on a 3rd party site. Thus evilsite.com might send a DELETE http://yoursite.com/items/1 request to your web service. This endpoint requires you to be logged in, but because the browser will send any cookies stored for yoursite.com, if authentication is cookie based then evilsite.com can piggy back on your authentication method and call authenticated methods that your user didn't intend to call on their behalf.
However, authentication doesn't have to be cookie based. If you are creating a client-rendered JavaScript app, then it is simple to send the authentication token as an HTTP header rather than in a cookie. If you do this then it is impossible for evilsite.com to make use of your token (they can only use tokens stored in cookies), and you never have the problem in the first place.

Using HTTPOnly Cookie in GET request (Retrieve user info from server using user_id cookie)

I'm following a tutorial where, after logging in a user, the backend sends a HTTPOnly cookie to the frontend containing the user id. However, HTTPOnly cookies are not accessible from the frontend (ex. document.cookie will not be able to read the cookie).
My question is, how is this cookie able to be used to retrieve user data? My thought process was that you would do something like GET 'server_address'/user/'id' where 'id' would be the user id stored in the cookie. But this obviously cannot work since the frontend can't access the cookie because it's HTTPOnly. A possible workaround I thought of was for the server to send the user id in the JSON response after logging in, but if this is the solution what is the point of even setting a cookie in the first place? That workaround makes it seem like there's no point in using cookies at all to save user sessions if you can just send the id back in the JSON response.
Please bear with me, this is my first time working with cookies. If it helps at all, I am using an Angular 4 frontend and a Node/Express backend
An httponly cookie is stored in the browser and is automatically resent back to the server with any future requests that match the origin of the cookie. So, the cookie can be used by the server to identify which client is making the request. If, for example, it was an authentication cookie that identifies who an authenticated user was, then the server would know which authenticated user this request is coming from and could use that information to authenticate the request and to know which user it was.
As you seem to already know, the httponly cookie cannot be retrieved by browser Javascript. That is the meaning of httponly.
how is this cookie able to be used to retrieve user data?
The cookie is sent to the server with any request from that client so the server can use the cookie to identify which user is making the request.
A possible workaround I thought of was for the server to send the user id in the JSON response after logging in
If the server wants the client to know the userID, then it should return it in the response. Or, it can stop using an httpOnly cookie so that the client can read the cookie. But, usually cookies that denote any sort of authenticated state are encrypted on the server so they often aren't intelligible to the client, even if they aren't httpOnly.
if this is the solution what is the point of even setting a cookie in the first place
Cookies are used for a variety of reasons. They allow the server to set some state that is associated with that particular client and each future request from that client will send that cookie back to the server so the server can have access to that info. The info could be authentication info, userID info, user preferences, etc...
That workaround makes it seem like there's no point in using cookies at all to save user sessions if you can just send the id back in the JSON response.
You don't really tell us much about your application, but cookies are often involved in implementing login and security and because they are automatically sent along with all future requests, they save the client the both of having to attach credentials to every single future request (because the cookie credential are automatically included). And, for requests such as a user clicking on a link in a page, the cookies are required because those types of links won't have credentials in them (and shouldn't).
My thought process was that you would do something like GET 'server_address'/user/'id'
So you plan to have any security associate with that request? If so, then you need an authentication scheme so that not just anyone can request info for any user. That's often what cookies are used for. You login, the server sets a credential into an encrypted cookie. That credential identifies a particular authenticated user so that for future requests from that same client, the server can use that cookie to see who the user is and whether they are authenticated.
We set cookie as httponly to prevent XSS, imagine if there is a security flaw that allow hacker the inject script <script>sendToHackerServer(document.cookie)...</script>, so user's cookie ( include session) will be sent to hacker server, then hacker can gain access to user data with that session. since these httponly cookie will be readable through http request only, session cookie will not be sent by injected script, and ur express backend can read these cookie with req.cookies.

Steam authentication API, passing data back to Angular

I have this problem with Express(NodeJS)/Angular web app where I rely on Steam's login authentication. Essentially when the user clicks "Login" he's redirected to the Steam authentication(Steam's website), once logged in the user is redirected back to a specific route on my backend called /verify. Once the user hits /verify there are session variables containing necessary user data to access. Therefore I use JWT to generate a token with this data to send back to the client(Angular in this case).
The problem is sending this token back to the frontend(the client) to save in local storage.
Any help is highly appreciated! Currently, I pass the token via a query string with a redirect back to the frontend, but this doesn't seem like a good solution.
Maybe I should stick to server-side sessions and write HTTP routes to GET user data. The problem with this approach is once again the client is completely unaware when the user authenticates himself on the backend, since the only callback is triggered is on the backend.
EDIT:
Tried another approach, however once again unsure of it's the right way to go both code-wise and security-wise.
Redirect the user to the Steam authentication page.
Wait for the authentication callback on server side, in my case it hits the route '/verify'.
Once at /verify the session cookie is already set, therefore I redirect the user back to my Angular app to a specific route called '/login'.
On /login the user requests a token based on the session cookie on the server, the token in my case is a JSON Web Token(JWT).
Once the token is saved in local storage I simply redirect the user to any page in my Angular app.
If this is the wrong way to do it, please let me know!

A different way to manage sessions

I'm working in a cookie-less way to manage sessions in my project (expressjs), keeping all session data server side and using a token at client side (previously generated by the server) to validate the session on every request.
A new token will be created on user login and kept hide somewhere in the page, then, on every request this token will be written to the request header and validated server side. at this point server will search for the token in a session store, lets say redis, and get the session data if the token is found or respond with a message of session expired otherwise.
There are some things i'm considering for this:
Redis keys are created on user login with a settled expiration.
Every time session data is found in redis i have to 'touch' the key
so expiration time gets postponed.
Token will be validated along side with the ip address of the client so can't be used by other person.
My question is if this is can be considered a secure way to work with, and if there is anything i'm missing here. Thanks
OK, cookies are required for storing session. Express does it the ideal way.
In express session(not cookiesession) it is completely stored at the server, only a key is sent to the client. The whole session is serialized to a key which is then sent. I assume you want that user cannot tamper with the session cookies. You can use httponly cookies to prevent tampering. They are only handled by browser and cannot be accessed by user. This prevents cookie theft or session hijacking. You can enable httponly cookies with:
app.use(express.session({cookie: { path: '/', httpOnly: true}, secret:'password'}));
Still you should use some encryption to prevent eavesdropping of cookies. Use secure : true for that. You can also mention where you want to store the session with redis, mongo or simply in memory.
The request token validation that you mention is a technique commonly used to prevent Cross-site request forgery. It keeps changing the token dynamically to keep user from getting the token. You can use this in express with csrf middleware.
app.use(express.csrf())
IP matching will not work as IP of user can change over time.

Resources