Is it ok to store user credentials in the JWT
Asked Answered
S

3

22

Is it ok to store user credentials (username / password) in the JWT (so sign it and verify the resulted token later)?

I heard that

No, it is not secure to send a password in a JWT. This is because the JWT claims are simply encoded and can easily be decoded by anyone that sees them. It is not secure to store any sensitive information in a JWT that returned to a user

but I don't know why does the JWT website recommends using it for authentication purposes then:

When should you use JSON Web Tokens?

Here are some scenarios where JSON Web Tokens are useful:

Authentication: This is the most common scenario for using JWT. Once the user is logged in, each subsequent request will include the JWT, allowing the user to access routes, services, and resources that are permitted with that token. Single Sign On is a feature that widely uses JWT nowadays, because of its small overhead and its ability to be easily used across different domains

Sadowski answered 7/3, 2017 at 15:54 Comment(1)
Nowhere does the JWT website say "you can store passwords in the token". Authentication can be done in other ways, without password.Avulsion
S
34

The JWT is the result of the authentication. For example

  1. User sends his credentials (e.g. username/password) to an authentication service. It could be a third party one or one inside your monolith or your own microservices dedicated to authentication.
  2. The service validates username-password. If authentication success it returns an JWT that represents that the user is already authenticated, in other words he is who claim he is. This JWT could contain a payload without sensitive information (don't store the password here).
  3. The user sends another request to a service business with the JWT. If the JWT isn't expired and is not corrupted (the sign is still valid) then the service could trust in its JWT. Maybe this task will be delegated to an authorization service.

What is inside the JWT token?

Well, the simplest JWT contains information about the sign (I can't enter in much detail here because I'm not a security expert) that allows to check if the sign has been corrupted when a request with the JWT is received.

This information can be verified and trusted because it is digitally signed

Besides that, the JWT allows to send a payload.

More formally, the JWT is composed by:

  • Header: type of the token + hashing algorithm being used
  • Payload: Claims are statements about an entity (typically, the user) and additional metadata.
  • Signature: The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn't changed along the way.

For example, if I send a request to a authentication service with my credentials username:password being gabriel:giussi, it will check these credentials and if they're OK it could create the following JWT: enter image description here

Then with every request I will then the encoded JWT that contains my username and the service will

  • Perform authorization (What Gabriel is authorized to do?) if the JWT sign is valid.
  • Ask me to login again if the JWT has expired
  • Return an authentication error if the sign is broken.
Score answered 7/3, 2017 at 16:2 Comment(11)
"If authentication success it returns an JWT that represents that the user is already authenticated" -- what is it usually?Sadowski
You mean what is inside the JWT? It doesn't necesarilly needs to have a payload but most probably it contain a way to identify the user to perform authorization tasks. The JWT itself says that the user is who says he is, the username in the payload should say who he is. Besides that it may contain anything you want (not sensitive), for example contact information of the user. But the JWT should remain lightweight because it is send in every request.Score
Am I right that the result of signing is JWT which is the same as the original payload but the signed one?Sadowski
No, the original payload will be the credentials. The result of the authentication is the JWT that could contain the username.Score
What does the payload part of the JWT usually contains to differentiate users? Just username?Sadowski
What do you need to store to identify a user? Besides what you actually use to identiy the user you could add any information (again, not sensitive because the token is stored in the client) in JSON format in the form of claims. There are reserved claims like expiration time but you could add your own claims. For example the api of the jose4j contains a method JwtClaims#setClaim(String,Object)Score
"What do you need to store to identify a user?" -- I thought that username should be enough for that. The validation part will be accomplished via the signature part of JWTSadowski
If you refer to your final conclusion validation part will be accomplished via the signature part of JWT you are wright.Score
So username in the JWT's payload should be enough to identify the user, and the signature part will be enough to guarantee that request was actually sent by that user, yeah?Sadowski
username in the JWT's payload should be enough to identify the user this is something you should'n be asking but affirming because depends on your use case. Signature will be enough to guarantee that the JWT is valid. The creation of the JWT is what guarantees that the user is who he says (otherwise the JWT will not be generated), is not the a JWT is not the authentication process but its result. In conclusion, a JWT with a valid signature and a user identifier X in its payload says that the request was actually sent by the user X.Score
@Sadowski "If authentication success it returns an JWT that represents that the user is already authenticated" - I saw a good clarification that a JWT "is a credential by itself". So I read it as follows: A server checks the login / password, if success it generates the JWT that is a credential by itself (though JWT is the dynamic one=changeable, unlike login/pass) . The JWT contains all the data to validate itself except the secret key. Any of JWT validators on server side has to have the same secret key that was used to generate the JWT to validate the provided JWT.Waggish
W
7

Shortly: yes, it is OK to pass/receive sensitive data in JWT if you encrypt the data before placing into JWT's payload and decrypt it after the JWT validation to use it.

  1. In a general case you would not need to keep user credentials in the JWT because the JWT is by itself a dynamically generated credential that represents the login / password (or the other means of authentication) provided at the JWT's first generation time.

    1.1 You could however pass something that is not as sensitive as pure login / password but still bears the valuable information you need at the JWT validation time. It can be user ID (in a sub claim, hashed if desired), or access level code or the like.

  2. Nevertheless if you wish you can pass the sensitive information with JWT. And this is all pretty easy as per below.

    2.1 For sensitive data you could use your specific private claims in the JWT's payload, e.g.:

    {
      // These are registered claims: (see https://www.rfc-editor.org/rfc/rfc7519#section-4.1)
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022
    
      // There can be some public claims you are not afraid to expose to the world
      // these are omitted here for brevity (see https://www.rfc-editor.org/rfc/rfc7519#section-4.2).
      "omitted": "for brevity",
    
      // And here can go some private claims you wish to include in the payload, e.g.:
      "sensitiveInfo": {
        "username": "admin",
        "password": "12345",
        "account_balance": 10000,
        "etc": "something else"
      }
    }
    

    2.2 The sensitiveInfo payload key by default is only base64-encoded (so it is easily read by anyone who gets the JWT). To make it secure you can encrypt it with some external module (e.g. crypto or bcrypt on NodeJS or PHP's techniques of your choice).

    2.3 In this case:

    • At the JWT generation step you have to encrypt the key's data before you provide the entire payload to JWT generator.
    • At the JWT validation step, after the JWT successfully passes the standard validation (e.g. jsonwebtocken jwt.verify() in Node) you get the decoded payload with encrypted data in sensitiveInfo key. You now just have to decrypt the data and use it as you planned.

This is it.

Waggish answered 18/10, 2020 at 7:24 Comment(0)
D
2

You should use jwt only to store a token which your API will consume. The token will be generated after a successful login and it can be attached to any request sent to your API and all request should be proceeded only if the token is valid.

Driscoll answered 7/3, 2017 at 15:58 Comment(6)
The whole process in my web application looks like this: send username / password to the server -> sign them using some secret -> send resulted token to the client -> use this token for the following requests. Is it ok?Sadowski
Yes, so why you want to send the password in each request?Score
@Score not the password, the JWT. But JWT contains signed credentials (username / password)Sadowski
No, the JWT doesn't contain credentials. Or better said, it shouldn't because it doesn't needed it and is a security risk.Score
I mean, the result of signing is JWT which is the same as the original payload but the signed one, right?Sadowski
The result will be a new jwt token, which should be automatically generated and it does not contain any sensitive data. You should then use this token in your requests and not the username/password.Adulteress

© 2022 - 2024 — McMap. All rights reserved.