87
votes

Recently I started working with JWT based authentication. After user login, a user token is generated which will look like

"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ".

It consist of three parts each separated with a dot(.).First part is header which Base64 encoded. After decoding we will get something like

{
  "alg": "HS256", //Algorithm used
  "typ": "JWT"
}

Second part is claims and Base64 encoded. After decoding we will get something like

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Third part is signature and is generated with

HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    *secret base64 encoded*
  )  

Now what is this secret key and how to generate this secret key??

I tried some online generator like "http://kjur.github.io/jsjws/tool_jwt.html" but dint get much help.

6

6 Answers

59
votes

The algorithm (HS256) used to sign the JWT means that the secret is a symmetric key that is known by both the sender and the receiver. It is negotiated and distributed out of band. Hence, if you're the intended recipient of the token, the sender should have provided you with the secret out of band.

If you're the sender, you can use an arbitrary string of bytes as the secret, it can be generated or purposely chosen. You have to make sure that you provide the secret to the intended recipient out of band.

For the record, the 3 elements in the JWT are not base64-encoded but base64url-encoded, which is a variant of base64 encoding that results in a URL-safe value.

81
votes

A Json Web Token made up of three parts. The header, the payload and the signature Now the header is just some metadata about the token itself and the payload is the data that we can encode into the token, any data really that we want. So the more data we want to encode here the bigger the JWT. Anyway, these two parts are just plain text that will get encoded, but not encrypted.

So anyone will be able to decode them and to read them, we cannot store any sensitive data in here. But that's not a problem at all because in the third part, so in the signature, is where things really get interesting. The signature is created using the header, the payload, and the secret that is saved on the server.

And this whole process is then called signing the Json Web Token. The signing algorithm takes the header, the payload, and the secret to create a unique signature. So only this data plus the secret can create this signature, all right? Then together with the header and the payload, these signature forms the JWT, which then gets sent to the client. enter image description here

Once the server receives a JWT to grant access to a protected route, it needs to verify it in order to determine if the user really is who he claims to be. In other words, it will verify if no one changed the header and the payload data of the token. So again, this verification step will check if no third party actually altered either the header or the payload of the Json Web Token.

So, how does this verification actually work? Well, it is actually quite straightforward. Once the JWT is received, the verification will take its header and payload, and together with the secret that is still saved on the server, basically create a test signature.

But the original signature that was generated when the JWT was first created is still in the token, right? And that's the key to this verification. Because now all we have to do is to compare the test signature with the original signature. And if the test signature is the same as the original signature, then it means that the payload and the header have not been modified. enter image description here

Because if they had been modified, then the test signature would have to be different. Therefore in this case where there has been no alteration of the data, we can then authenticate the user. And of course, if the two signatures are actually different, well, then it means that someone tampered with the data. Usually by trying to change the payload. But that third party manipulating the payload does of course not have access to the secret, so they cannot sign the JWT. So the original signature will never correspond to the manipulated data. And therefore, the verification will always fail in this case. And that's the key to making this whole system work. It's the magic that makes JWT so simple, but also extremely powerful.

Now let's do some practices with nodejs:

Configuration file is perfect for storing JWT SECRET data. Using the standard HSA 256 encryption for the signature, the secret should at least be 32 characters long, but the longer the better.

config.env:

JWT_SECRET = my-32-character-ultra-secure-and-ultra-long-secret
//after 90days JWT will no longer be valid, even the signuter is correct and everything is matched.
JWT_EXPIRES_IN=90

now install JWT using command

npm i jsonwebtoken

Example after user signup passing him JWT token so he can stay logged in and get access of resources.

exports.signup = catchAsync(async (req, res, next) => {
  const newUser = await User.create({
    name: req.body.name,
    email: req.body.email,
    password: req.body.password,
    passwordConfirm: req.body.passwordConfirm,
  });
  const token = jwt.sign({ id: newUser._id }, process.env.JWT_SECRET, {
    expiresIn: process.env.JWT_EXPIRES_IN,
  });

  res.status(201).json({
    status: 'success',
    token,
    data: {
      newUser,
    },
  });
});

output: enter image description here

In my opinion, do not take help from a third-party to generate your super-secret key, because you can't say it's secret anymore. Just use your keyboard.

36
votes

What is the secret key

The secret key is combined with the header and the payload to create a unique hash. You are only able to verify this hash if you have the secret key.

How to generate the key

You can choose a good, long password. Or you can generate it from a site like this.

Example (but don't use this one now):

8Zz5tw0Ionm3XPZZfN0NOml3z9FMfmpgXwovR9fp6ryDIoGRM8EPHAB6iHsc0fb
12
votes

You can write your own generator. The secret key is essentially a byte array. Make sure that the string that you convert to a byte array is base64 encoded.

In Java, you could do something like this.

String key = "random_secret_key";
String base64Key = DatatypeConverter.printBase64Binary(key.getBytes());
byte[] secretBytes = DatatypeConverter.parseBase64Binary(base64Key);
5
votes

What is the secret key does, you may have already known till now. It is basically HMAC SH256 (Secure Hash). The Secret is a symmetrical key.

Using the same key you can generate, & reverify, edit, etc.

For more secure, you can go with private, public key (asymmetric way). Private key to create token, public key to verify at client level.

Coming to secret key what to give You can give anything, "sudsif", "sdfn2173", any length

you can use online generator, or manually write

I prefer using openssl

C:\Users\xyz\Desktop>openssl rand -base64 12
65JymYzDDqqLW8Eg

generate, then encode with base 64

C:\Users\xyz\Desktop>openssl rand -out openssl-secret.txt -hex 20

The generated value is saved inside the file named "openssl-secret.txt"

generate, & store into a file.

One thing is giving 12 will generate, 12 characters only, but since it is base 64 encoded, it will be (4/3*n) ceiling value.

I recommend reading this article

https://auth0.com/blog/brute-forcing-hs256-is-possible-the-importance-of-using-strong-keys-to-sign-jwts/

1
votes

If you are someone looking for the secret key for the JWT_AUTH_SECRET_KEY then you can use any generated here:

https://api.wordpress.org/secret-key/1.1/salt/

This usually for the "JWT Authentication for WP REST API" ( https://wordpress.org/plugins/jwt-authentication-for-wp-rest-api/ )

Maybe you are someone like me who got here looking for that instead :D