does JWT containing userID need verification from the database? - node.js

I sign a JWT (JSON Web Token) with userID and iat (issues at) like so
jwt.encode({sub: user.id, iat: timestamp}, jwtSecret);
When I receive a JWT from the client, I decode it to extract the userID. Do I need to validate the userID by checking its existence in the database every time I need to allow the user to access a secure route (see first example)? Or can I just assume that the user is who she says she is, and allow her to access the secure path?
My feeling is that I need to access the database to validate the user on every request, this would be expensive and defeat the purpose of using a JWT.

Your token is signed. If someone changes the token on client side, it would fail validation and the server side framework would reject it. Therefore you can trust your token.
Of course, the jwtSecret should be a secret only known by your authentication server and resource server.
You generate the token only if you trust the user who requested it.
You trust the token as long as it has not expired and can be verified with the secret.

The whole idea of JWT is that can verify the integrity of the claims contained within it. If you can decode successfully the token you can be sure that this token contains information previously encoded by you. For someone to pass malformed data has to also know the secret you use to sign the tokens.
For more information read this.

Related

For user verification, you do need to store data on server side even when using JWT correct?

While I understand how jwt works for authentication, I'm trying to build registration.
Registration has a step that requires verification.
User enters the phone number
Code is sent via sms to user
User enters the code and device is verified
Since it's an API for mobile app there is no session/cookie built in.
I'm wondering if I can not implement cookie like system for mobile. And just make it work with JWT. But I don't have much experience with this.
This is my current flow:
User makes a POST request with Phone #
I respond with JWT (Time:Number)
I also send code via SMS
User sends the code via POST and JWT
Problem:
I don't know if code belongs to user or not, as I didn't save the code in DB.
I can't put into payload as it's just encoded not encrypted. (why is it not encrypted, what's the point of sending plain payload, what's even the point of JWT & didn't signed cookies already do that? they had session string encrypted so you couldn't change session string without invalidating the cookie)
JWT is overcome authentication/authorization mostly in APIs. JWT Access Token/Refresh Token is nothing but a JSON data in an encrypted form. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA. Key pair using RSA or ECDSA is more preferable as a security point of view. You can check authentication/authorization by decryption JWTs.
JWT token itself contains expiry date, so you can just configure expiration time to it. Access tokens are to check that user is authorized or not. Refresh tokens is necessary to get a new access token, generally used when the old access tokens are expired. Refresh token and Access token both expire but refresh token is long-lived compare to access tokens.
Generally developers use access token only but it is preferable to use access and refresh token both.

JWT Verify client-side?

I have a nodejs api with an angular frontend. The API is successfully using JWT with passport to secure it's endpoints.
I am now conscious that after the tokens have expired, my front end will still allow the user to request my api endpoints without prompting them to reenter their log in details to get a fresh token.
This is how my backend generates the token:
function generateToken(user) {
return jwt.sign(user, secret, {
expiresIn: 10080 // in seconds
});
}
So to implement this logic I think I need to verify the JWT token client-side. Q1, is this a sensible approach.
Q2, the JWT library I am using seems to require a public key to use it's verify() function. I don't seem to have a public key, only a secret, which I just made up, so it wasn't generated with a pair. Where does my public key come from, or is there another way of verifying my token without this?
This all seems like it should be obvious and that I have missed something, so apologies if this is a stupid question, but I can't seem to find the answer?
TL;DR
You must verify the signature of JWS in the server always.
Client-side signature verification doesn't gives much, unless you have a specific case where it makes sense don't do it.
You don't need to verify the signature of a JWS token to check expiration in the client. (unless you were encrypting the claims, aka using JWE, in that case you need to do something similar because you need a key to decrypt the claims).
You don't need to verify the signature of a JWS to check expiration in the server neither, but you should because this gives you the certainty that nobody has altered the expiration (otherwise the verification will fail because if the claims change then the recalculated signature will differ)
To read non encrypted claims you just only need to decode them. You could use jwt-decode in the client.
I am now conscious that after the tokens have expired, my front end will still allow the user to request my api endpoints [...]
So to implement this logic I think I need to verify the JWT token client-side
If I understood you correctly you are talking about checking if a JWS has expired in the client side.
In order to do this you don't need to verify the token signature (although the library you are using seems to be doing both things at the same time for you, but also lets you to disable expiration control with ignoreExpiration flag). (Unless you're encrypting the claims, aka using JWE)
The RFC 7515 (JWS) says nothing about expiration. Message Signature or MAC Validation doesn't control expiration (and it shouldn't because signatures gives you authenticity and integrity).
Even the RFC 7519 (JWT) doesn't control the expiration claim for resolve if a JWT is valid or not.
Also, all the claims are optional.
So, you could check if a JWT has expired or not without verifying the signature, hence you don't need neither a public key (for asymmetric encryption like RSA) or a secret key (for symmetric encryption like AES).
In JWT and JWS tokens, the claims are just plaintext base64 encoded so you could just decode the payload without verifying if the signature is valid and read the expiration claim.
If you are encrypting the payload (aka using JWE) then you will not be able to do this.
A note from jjwt library
JWTs can be cryptographically signed (making it a JWS) or encrypted (making it a JWE).
Here is a ligthweigth library from auth0 to decode the base64encoded claims of a JWT/JWS token.
A guy is even asking about checking expiration.
I don't know why you think that you should be doing this control client-side, the only advantage is avoiding sending API request that the client knows that will fail. And they should fail because the server should be validating that the token hasn't expired, previous signature verification (with secret/private key) obviously.
The RFC 7519 says about this claim:
The "exp" (expiration time) claim identifies the expiration time on
or after which the JWT MUST NOT be accepted for processing.
In a web app like the one you say the use of tokens is to allow stateless servers to authenticate client requests.
The goal of the OPTIONAL expiration claim is to allow the server have some control over the generated JWS (if we are using JWT for authentication signing them is a must so we should be talking about JWS).
Without expiration, the tokens will be valid forever or until the key used to signing them change (this will make the verification process to fail).
By the way, invalidating sessions is one of the most notorious disadvantages of using stateless authentication.
Session invalidation becomes a real problem if we are including information in the JWS payload (aka claims) used for authorization, for example which roles the user have.
From Stop using JWT for sessions
but more seriously, it can also mean somebody has a token with a role of admin, even though you've just revoked their admin role. Because you can't invalidate tokens either, there's no way for you to remove their administrator access
The expiration control doesn't solve this problem and I think is more oriented to avoid session hijacking or CSRF attacks.
An attacker using CSRF will be able to make a request with an expired JWS to your API skipping the expiration control.
A different issue is verifying the signature in the client using the public or secret key.
Regarding your question
I am using seems to require a public key to use it's verify() function. I don't seem to have a public key, only a secret, which I just made up, so it wasn't generated with a pair.
The verify method you pointed out says explicitlly that it accepts a public or secret key.
jwt.verify(token, secretOrPublicKey, [options, callback])
secretOrPublicKey is a string or buffer containing either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA
I assume you are using neither and you are using a string like 'shhhh'.
var token = jwt.sign({ data: '¿Donde esta Santiago?'}, 'shhhh');
Then you should do
var decoded = jwt.verify(token, 'shhhhh');
However, the question here is: Is client-side signature verification really needed?
I think is not, at least not for this kind of application where the client just uses the JWS to send subsequent request to the server saying: "Hey server, I'm Gabriel and I have a paper (token) here that assures that and that paper is signed by you."
So if the client doesn't validate the JWS and a MITM had successfully gave to that client a JWS signed by himself (instead to the JWS signed by the server), then the subsequent request will simply fail.
Like expiration control, signature verification only prevent the client to make request that will fail.
Now, client side verification requires sending the public or secret key.
Sending public key doesn't represent a security concern but it's extra effort and processing with little benefits.
Sending secret keys (like 'shhhh') can represent a security issue because is the same key that is used to sign tokens.
I'll just put it here for those who got here looking for jwt verification on the browser with a public key.
Library:
https://kjur.github.io/jsrsasign/
Example:
https://kjur.github.io/jsrsasign/tool/tool_jwtveri.html
Code example:
https://github.com/kjur/jsrsasign/blob/master/tool/tool_jwtveri.html
API:
https://kjur.github.io/jsrsasign/api/symbols/KJUR.jws.JWS.html#.verifyJWT
P.S. Don't use your secret key for browser jwt verification! Public key only!
I think verifying JWT token at client-side is not a good idea.
IMO;
Whenever a user logs in, generate access and refresh token and return to user something like this;
{
"accessToken": <<accessToken>>
"refreshToken": <<refreshToken>>
"expiresAt": <<expiresAt>>
}
So client can understand when access token expire and can refresh it with refresh token.
Encrypt the data that you put in the access token because there is a chance to access the data without secret key. But of course someone needs to secret key to verify.
Q1: Token verification on client is a bad idea. What you can do is to save a token together with a same expired date on client and then refresh/remove a token. But my thought that it is better to have some date checkig on server side cause exist simple rule: Don't trust the client cause it can always send malicious code.
Q2: JWT don't need any public key. It always must have private key storing on server side cause if someone known your secret key your token don't make any sense. You only can add some payload to do it more complex.
Managing when the token expires on the client side so you can avoid sending tokens which you know will be rejected is purely an optimisation to avoid an extra roundtrip with the server. Its a perfectly valid concern but it's not a security concern. Its up to you to decide if you need that level of optimisation. The server must validate the token signature and reject expired tokens as a security concern. Tokens don't need to be encrypted unless they contain sensitive data that you don't wish to be visible to an end user or an attacker that obtains a copy of the token somehow. Tokens should be transmitted over HTTPS / SSL as good security practice. Access Tokens are usually short lived. If you also use refresh tokens, never store one in a browser unless it's a secure cookie set by the server for the same origin domain and not accessible to browser scripting. In that case Refresh tokens should still be regularly rotated.
Answer 1: It is not considered to be a good approach to verify your auth token on the client side as it involves secret key while encoding/decoding it and keeping the secret key on the client side is not secure.
Creating Token
jwt.sign({
data: 'foobar'
}, 'secret', { expiresIn: 60 * 60 });
Verifying Token
jwt.verify(token, 'secret', function(err, decoded) {
console.log(decoded.foo) // bar
});
Answer 2: JWT involves secretORPublic key while encoding and decoding token. It has to be declared or kept in the config file somewhere on the server side.
Explanation:
Decoding means decoding from Base64, there's no secret key involved in that process. On the other hand, verifying a JWT would require a secret key because it would involve a cryptographic signature operation.
To sum up, decoding does not need the secret (remember decoding is just interpreting base64) and verifying/signing does require it

Is session authentication more secure than token-based authentication?

I've been trying to understand the real differences between session and token authentication.
What I have gathered so far:
In token authentication, nothing is stored in the server side. What this means is, that the actual token includes the password and username, as well as other possible information. And the server just decrypts the token, and then checks whether the username and password are correct. Am I right about this?? If the token includes the password and username, then how can the token still be different everytime?
In session-based authentication, the session token is just a random (unique in time) id, that is mapped to the user in the server side. So that when the server receives the session_id (in cookie for example), it will check whether it maps to any user, and if it does, then the user is authenticated. So the session_id does not contain any user related information, that could be decrypted?
In session authentication, the server will send back the user related information (not password) without encryption (unless https is used).
In token authentication, the server will not send back direct user information, but just the token, which contains the user information, once decrypted?
I have a feeling that I haven't really understood how token and session authentication works. Something is definitely wrong in the statements above.
But, let's play along that the statements would be correct. Then wouldn't session-based authentication be more secure? Because in session based authentication, you do not reveal user password (in browser for example). Since it's just a random id, one cannot get information from it. But this is not the case with Token authentication. Since token authentication contains the password, if someone manages to decrypt it, he will get your password. So isn't the session authentication actually more safe than the token authentication, as it doesn't reveal password nor username information?
Your question has not an absolute answer YES/NO. For example session cookies are vulnerable to CSRF and tokens can be stolen with XSS injection. Both mechanism are also vulnerable to ManInTheMiddle if you do not use HTTPS. Therefore additional security measures are needed usually for each solutions. Depends on your use case.
I guess you are talking about a token mechanism like JWT which is self-contained and protected to alterations because you said
In token authentication, nothing is stored in the server side.
But you are confusing some concepts. I will try to answer your additional questions using JWT tokens as reference. If not, most concepts also can be applied to opaque tokens
In token authentication, nothing is stored in the server side. What this means is, that the actual token includes the password and username, as well as other possible information. And the server just decrypts the token, and then checks whether the username and password are correct. Am I right about this??
The token is issued by server (not client) requiring users to present their credentials and digitally signed with server private key. The token includes an identifier of the principal in the sub claim and other fields of interest like expiration time or issuer. Never the password
When the client send to token to authenticate, the server verifies the signature to determine the authenticity an has not been altered
If the token includes the password and username, then how can the token still be different everytime?
The token does not include the password. The token will be different due to some variant claims like expiration time exp or issued at iat. Also the computed signature will be different
So the session_id does not contain any user related information, that could be decrypted?
Yes, it is a ramdom sequence. Relationship with user server is stored on server
In token authentication, the server will not send back direct user information, but just the token, which contains the user information, once decrypted?
The JWT token includes some user information, but it is not encrypted, it is signed. If you need to hide the payload, JWT also allows to use JWE encryption
But, let's play along that the statements would be correct. Then wouldn't session-based authentication be more secure? Because in session based authentication, you do not reveal user password (in browser for example). Since it's just a random id, one cannot get information from it. But this is not the case with Token authentication. Since token authentication contains the password, if someone manages to decrypt it, he will get your password. So isn't the session authentication actually more safe than the token authentication, as it doesn't reveal password nor username information?
The base approach is wrong. Password is never included in the token. If you do not want to reveal user data you can use opaque tokens or JWE encryption with JWT. The proper solution depends on your use case. See my first paragraph
Sensitive information such as password or items like Social Security Numbers shouldn't be stored in a token.
A typical example of token signing is this
function createToken(user) {
 return jwt.sign(_.omit(user, 'password'), config.secret, { expiresIn: 60*60*5 });
}
Here, we are creating a signed token with the user's details but we are leaving out the password.
I gave a very detailed information about this in this thread How is JSON Web Token more secure than cookie/session?
Check it out. I hope this information helps!

JWT: How much I can trust to my payloads

suppose I create a jwt token for a user and set a payload as:
['userID'=>1, 'role'=>'user']
In case of using HTTPS and SSL, Is it safe to send role or any other sensitive information via payload? Is it possible for sender to manipulate payload values?
UPDATE: Now I know that JWT tokens are decodable. But because they carrying a signature, any update on the values shall invalidate the token. If you want the payload be totally encrypted, try JWE!
Claims in the payload can not be manipulated with out the key, a common example is admin=false, both the client and server can see that this user is not an admin. If the user was to try and manipulate the token (to become an admin) it would not validate correctly. This is why its critically important you validate your tokens before reading any claims from them.
However you wouldn’t normally put sensitive information (like credit card numbers) in them because the claims are not encrypted however no one should be able to access your token otherwise they would be able to take over your session.
Have a play with manipulating tokens here https://jwt.io/
JWT tokens are digitally signed by the issuer, so they cannot be modified without invalidating the signature.
HTTPS is only required to prevent the token from being stolen.

Token Based Authentication advantages?

In token-based-authentication, some information is encoded into a token and that token is sent to the client (usually as an http-only cookie). The client responds with the same token, and the token is decoded to the server to verify that the client is who they say they are.
I have a couple of questions that I can't google the answers to, so was hoping to get some coherent help :)
Is there anything in the token that ties it to the specific client? i.e. if Alice copies Bob's token then can Alice send authenticated requests to the server?
Given that, is the token actually providing anything that can't be provided with a random token stored on the server database? i.e. my server generates a random UUID, stores a hash of it in a cache with Alice's data, sends it to the client. Client responds with the same token, server looks it up in the cache and gets the credentials.
In other words, is JWT just an expensive way of generating a UUID? (I'm assuming you can't encode all the client data you want into the token and will have to do a database/cache lookup on the server end even with a token).
Yes, a JWT token typically has a number of claims. The Subject claim would typically identify the user that was authenticated. If Alice copies Bob's token, she can use the API/application as if she were Bob. That's why it is important to use https to prevent bearer tokens from being stolen.
'iss' => Issuer of the token (Authority)
'sub' => Subject identifying the principal, typically the authenticated user
'aud' => Audience, the application trying to use the token
'exp' => Expiration, until when the token is valid.
See here for more info on the JWT token used in OAuth 2.0.
The thing that security tokens have over session tokens as you describe is that they can be validated without having to go back to the issuer (or central database). The issuer signs the token with its private key. The application is configured with the corresponding public key and can verify that the token was not compromised without going to the issuer.

Resources