I have one issue, where I would need some inputs.
In my current application, using Node,Express I have a auth token which is generated by third party post login. I need to save this token on Node layer, as I cannot expose this token on client side.
Is there a better way to save this token on Node layer for each user specific once user gets logged in into the system and invalidate if user logout.
Please note that, there is no authentication done on node layer, it all verifies on some third party API's and that API generates a token.
So my question:
How I can save this token on node level.
Is there any way available by which I can save token for each user,Currently I am thinking to use Redis as it is just key value pair.
If I compare Mongo Vs Redis, which will be a better option?
Is there any other way around to solve such scenarios?
For example If I will save this on client cookie, how I can make
this token more secured, so that client cannot read this token.
This is not a complete answer since I do not know whether there is a secure approach to save a token on a cookie. I think that using Redis database is the way to go for its greater performance compared to MongoDb since you would be storing key value pairs as you stated.
Related
So, I've implemented some form of auth on my API, I'm not sure which kind it classifies as.
What my app does is, it generates a token once a user signs up/logs in and then before every endpoint call, I have a middleware function that checks if a token exists, then decrypts it, and if it's correct then its stores the user info in req.user. I then use the user info in req.user for other stuff later.
Does this classify as Token based auth?
I looked up online and read that instead of storing the token as a cookie on the client side, if I store the user info on the server side as session and a sessionid as a cookie on the client side, it classifies as Session based auth.
Thus clearly, my app has Token based auth right?
(I'm sorry if I'm seeking clarification for very basic stuff, I'm very much a beginner)
Yes you have implemented the token based authentication in your scenario, session based is totally different thing on that approach you need to store session in your backend to track is client valid or not, but in token based you don't need to store sessions but you will have two tokens as ACCESS TOKEN and REFRESH TOKEN and need to store refresh token in database incase of future regeneration of access token that's how token based authentication works!
You write that you "check if a token exists" and I assume this means that you look it up on a database. This is rather similar to an express-session, where the cookie contains a token and the session is also looked up on the database. The difference could be that you transport your token not in a cookie but in a request header (you don't say which technique you use).
However, one important aspect of token-based authorization is that the token need not be looked up on a database, but can be validated entirely in memory by verifying a signature. This is quicker and consumes fewer resources. Especially if your server receives many (malicious) requests with invalid tokens, it can detect and reject them without putting load on the database. See also the answer to Some questions about refresh tokens.
You could combine this with a session-based approach if the session ID also contains a signature and this is validated before the session is looked up on the database.
Read more about signed tokens and signature validation under the jwt tag.
I am developing a Demo WebApp using the MERN stack and using JWT for Authentication.
In the Backend, when a user requests to log in, I am preparing a JWT token by adding the MongoDB ObjectID for that user in the token's payload with necessary timestamps.
On User login, I want to store the User details for that session on Frontend.
I know that I can share all those details via API response & store it using React Context/ Redux. But is it a good practice to create a JWT token from the backend with all the session-specific User details stored on DB (Apart from secure information) into Payload during login & sending the encrypted token in the response? So that, I can decrypt & destructure the user details from the JWT token and store them for that session.
Eager to know the Pros and Cons of the above process keeping best coding practices into consideration.
It seems like you need something like an ID token from OpenID Connect (https://openid.net/). This is a JWT which contains user data used on the frontend to identify user, maybe print their username somewhere, etc. It is a common practice to use it, but you should remember that if you put too much information into that token it will get quite large (which can have an impact on slower connections, or slower computers which will need to decode it, verify signatures, etc.)
Another viable option is to have an endpoint which returns all that information when needed (see the userinfo endpoint in OIDC).
You also have to remember that all that information will be readable to anyone who has access to that JWT, so no personal information should be kept there.
Just a note - I can decrypt & destructure the user details from the JWT token - you probably mean decode here. Decoding is the act of changing the JWT from a base64 encoded string into a JSON object. You can have truly encrypted JWTs (JWE), which guards them from being read by eavesdroppers, but you wouldn't use them in a frontend app. They are also much more complicated to set up and use more CPU.
Right now I am using a JWT token to validate the user and on the client side I store it in cookies. On the server side, I just generate this token and send it to the client side.
As I have seen, there are several approaches where server side tokens / authorization are stored in redis. I don't understand why I would use this. Can you provide me with some use cases for this? And maybe I should store the client side token somewhere else?
Storing JWT on the server with Redis gives you more control over how authentication/authorization works on your app.
Consider the logout process, ideally, it should invalidate a token, but JWT doesn't really give you an easy way to revoke a token.
The best bet is to have it stored somewhere (Redis) and when a logout request is received, the saved token is deleted.
Redis is relatively fast, because of its cache feature, which basically allows you to save/retrieve the token in memory, and it also provides some cool features, one of which is to expire/self-delete a saved token after a set time.
I want to implement JWT in my next project. I just want to know if there is any best way to implement logout from all devices in JWT. As JWT is stateless mechanism, do we have to involve redis/db?
I have found the following as the best way to handle few thing with jwt.
As jwt is stateless mechanism, I've faced the following problems.
How to implement logout? When someone tries to logout, as it is stateless there comes an issue to invalidate the token.
Solution:
Use redis as in-memory database which handles all tokens, save token(with same ttl as token has) every time user logs in, cross check it with each request along with token validation. When someone wants to logout, remove the token from redis along with client side.As we are cross checking in redis, when user logs out and try to access with same token system will not find token in redis, so handle it and throw
Unauthenticated error.
How to invalidate all tokens of same user when user changes password?
How to implement logout from all devices feature?
Solution: As we are storing tokens in redis either we have to search for all tokens related to given user and delete them from redis or store tokens in database too when user signs in, find out all tokens related to a user, get token ids and delete them from redis. Storing in db is better as dbs are better at find operations.
Can we Save a random JWT secret in the DB when new user is created? If we want to sign out all devices, just generate new Secret, so all OLD Tokens are invalid now. And for normal Logout, just delete the Token in the Front End
If you just want to remove the token, it will be simple as removing it from the front end application, In you case clear the cookies that stores the token
On the other hand if you mean to invalidate the token, there is couple of ways to do it, below are some ways
(1) If all the token ever generated is stored in backend, It will be just simple as clearing that storage, if tokens have been mapped to users you can just clear tokens for a particular user.
(2) You can add a date field like "invalidate_before" along with user which should be updated at a event of changing password, logout from all devices etc.
Simply update the invalidate_before to currentTime() on such events.
Every time a new token is created, add the created time in token payload,
to validate the token on incoming request just check if the created time in payload is greater than invalidate_before time for that user in db
(3) When you create a new user, create a secret for just that user, then you can sign every user token with that specific secret, and just like in (2) events like changing password, logout from all devices etc, Should create a new secret.
This way also you can invalidate by checking the token signature.
overhead with (2) and (3) is that, validation will be a 2 step process and it involves db reading
EDIT: For (3) you may use a salt instead (final secret will be common secret + salt for particular user), So that you hava a way to invalidate either a single user's token by changing salt or the all user's token by changing common secret
I need to generate a secure token for access to an api. User will auth and on successful auth I will need to generate a token.
Important: I do have a requirement that I need to be able to revoke a users access to the api at any time.
Option 1:
I can generate a random string and use that as the token. Store the token and the user in the db. When the user passes the token I check the DB for the token, if it exists go to go...
This gives me the ability to revoke access by removing a users token. If they tried to log back in and the token was gone they won't have access. I can also expire tokens from the DB based on time.
I am using nodejs and have seen this:
Secure random token in Node.js
require('crypto').randomBytes(48, function(ex, buf) {
var token = buf.toString('hex');
});
Is that really secure in that someone could not guess a token that I have generated?
Option 2:
Use something like jwt. On auth generate a jwt with the users id. When the user passes that jwt on a request I make sure jwt is valid and if so grab user id and good to go. This seems a lot more secure as jwt prevents tampering.
Problem is revoking access to the api. I could store all jwts (until they expire) in the db, on request validated jwt and make sure its in my db. If I want to revoke I can just remove it from the db. Con here is that I now have the overhead of validating the jwt and looking it up to ensure its in my db.
Is there a good way to revoke access using jwt?
This question will probably invoke a lot of opinion in the answers, so ultimately its up to you and your security requirements.
One solution I like is generating random characters in the same way you've suggested, and include with it something the user has (such as an email address or an ID). Then also include a timestamp to know when it was generated. Take those things and concat them together into a single string (perhaps using some character to split the parts up). So you'd end up with something like:
<random-string-of-characters>|<user-email-address>|<timestamp>
Now encrypt that string, perhaps using something like bcrypt, and that blob ends up being what you would call the "token". The internal users of this don't have to understand it, they just need to store it and later access it to send it to your security layer to validate. You validate it by unencrypting it and verifying the parts.
This solution gives you complete control on how you grant the user access. You can continue to store the generated characters in the database and revoke it at any time, or look at the timestamp to see if they are "timed out".
I suppose there are a lot of solutions to this, so this is just one :)