RIPAN
RIPAN

Reputation: 3906

What is secret key for JWT based authentication and how to generate it?

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

"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ".

It consists 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"
}

The second part is claims and Base64 encoded. After decoding we will get something like:

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

The third part is the 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 generators like: "http://kjur.github.io/jsjws/tool_jwt.html"

But, I didn't get much help.

Upvotes: 240

Views: 531031

Answers (11)

Skidrow
Skidrow

Reputation: 76

The secret key in JWT is used to sign and verify the token. While the payload of a JWT is encoded (and not encrypted), it’s still visible to anyone who has the token. What keeps the token secure is the secret key—it ensures that the token wasn’t tampered with and verifies its authenticity.

Since you didn’t mention the programming language, here’s an example in Ruby to generate a JWT secret key:

require 'securerandom'
secret_key = SecureRandom.hex(64)
puts secret_key

If you’d rather not write code for this, you can use an online secret key generator like this one as it's a one time thing.

Upvotes: 0

Archit Singh
Archit Singh

Reputation: 169

I was implementing JWT-based auth on my fastAPI server using this tutorial, and I came across this question, so sharing my two cents on it.

For the purposes of JWT (JSON Web Tokens), the secret key is a very crucial part that is utilized for signing as well as verifying the tokens.

What is a Secret Key?

JWT-based authentication secret key is used in the process of signing a token. It is very important for JWT security because it helps to check whether in the course of transmission the token has been modified. The secret is applied through a special algorithm (e.g., HMAC SHA256) in a manner that a part of the produced JWT is its signature. The signature is used to check whether the token sent back to the server is authentic and unaltered.

How to Generate the Secret Key

The secret key must also be a random, high-entropy string that is kept secure and confidential. It must be long and random enough to resist both brute-force and guessing attacks. The following are the ways to have a secure secret key:

Method 1: Using OpenSSL

Here is how you can generate a secret key with the help of OpenSSL, a powerful utility with which you can also perform your cryptographic operations. One could, for instance, generate a key of 256 bits:

openssl rand -base64 32

This will create 32 bytes of random data that we can use in Base64 encoding as private key.

Method 2: Programming Languages

Node.js Example

const crypto = require('crypto');
const secret = crypto.randomBytes(64).toString('hex');
console.log(secret);

This script utilizes the inbuilt crypto module in Node.js itself to generate a 64-byte hexadecimal string, which can be perfectly used as a securely random secret key.

Python Example

import secrets
secret = secrets.token_hex(32)
print(secret)

The secrets module of Python is meant for the creation of cryptographically strong random numbers that can be used for managing secrets like passwords, tokens, and other secrets.

Best Practices

  • Keep it Secret: The secret key should be kept secretly. Provided that the secret key leaks, the attackers could issue legitimate tokens themselves.
  • High Entropy: Use a long character combination for the key to reach higher entropy.
  • Regenerate from Time to Time: Doing periodic rekeying of the secret key can be efficient towards minimizing the effect of any leakage that might exist.

Upvotes: 5

Daniel Jonsson
Daniel Jonsson

Reputation: 3931

For JWT, the signing algorithm HMAC SHA256 is commonly used. For that algorithm, 32 bytes is enough.

A 32 bytes array can be expressed as a 64 characters long hexadecimal string, since 2 hexadecimal characters is equal to 1 byte. 32 random bytes, expressed as a hexadecimal string, can be generate with this terminal command:

$ openssl rand -hex 32

An example of what it outputs:

4f1feeca525de4cdb064656007da3edac7895a87ff0ea865693300fb8b6e8f9c

By using the command above, the key is generated locally on your computer. It can be dangerous to use a website for generating passwords, so doing it locally is preferred.

Depending on the language that you use, the next steps may differ. But in C#, you can convert the hexadecimal string to a byte array using this function:

public static byte[] FromHexStringToByteArray(string hexString) 
{
    var byteArray = new byte[hexString.Length / 2];
    for (var i = 0; i < hexString.Length; i += 2)
    {
        byteArray[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
    }
    return byteArray;
}

And in C#, the JWT token can then be generated in this way:

public string GenerateJwtToken()
{
    var issuer = "https://auth.example.com";
    var audience = "https://api.example.com";
    var expiryInMinutes = (int)TimeSpan.FromDays(1).TotalMinutes;
    var secretKey = "4f1feeca525de4cdb064656007da3edac7895a87ff0ea865693300fb8b6e8f9c";
    var key = FromHexStringToByteArray(secretKey);
    var securityKey = new SymmetricSecurityKey(key);
    var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
    var now = DateTimeOffset.UtcNow;
    var claims = new[]
    {
        new Claim(JwtRegisteredClaimNames.Iss, issuer),
        new Claim(JwtRegisteredClaimNames.Aud, audience),
        new Claim(JwtRegisteredClaimNames.Exp, now.AddMinutes(expiryInMinutes).ToUnixTimeSeconds().ToString()),
        new Claim(JwtRegisteredClaimNames.Nbf, now.ToUnixTimeSeconds().ToString()),
        new Claim(JwtRegisteredClaimNames.Iat, now.ToUnixTimeSeconds().ToString()),
        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
        new Claim(JwtRegisteredClaimNames.Sub, "123"), // The user's ID
    };
    var token = new JwtSecurityToken(
        issuer: issuer,
        audience: audience,
        claims: claims,
        expires: now.UtcDateTime.AddMinutes(expiryInMinutes),
        signingCredentials: credentials
    );
    var tokenHandler = new JwtSecurityTokenHandler();
    return tokenHandler.WriteToken(token);
}

In the example above, the key is in the form of a hexadecimal string and is converted to a byte array. Next, an instance of SigningCredentials is created with the key and the algorithm set to HMAC SHA256. Later, the token is created with the credentials.

Upvotes: 16

Svaris
Svaris

Reputation: 19

A secret should be generated securely, in a way that it is not possible for an attacker to guess and predict it.

You may take a look at this for algorithms that can generate secure random numbers: https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#secure-random-number-generation

I prefer python as a way to create secrets https://docs.python.org/3/library/secrets.html

Here is how to generate a thirty two character alphanumeric password with at least one lowercase character, at least one uppercase character, and at least three digits:

import string
import secrets
alphabet = string.ascii_letters + string.digits
while True:
    password = ''.join(secrets.choice(alphabet) for i in range(32))
    if (any(c.islower() for c in password)
            and any(c.isupper() for c in password)
            and sum(c.isdigit() for c in password) >= 3):
        break

Upvotes: 0

Rafiq
Rafiq

Reputation: 11535

A JSON Web Token or JWT is made up of three parts:

  1. The header: contains some metadata about the token itself.
  2. The payload: contains the data that we want to encode into the token, so the more data we want to encode here the bigger is the JWT.
  3. The signature.

These first two parts, the header and the payload, are just plain text that will get encoded, but not encrypted.

So anyone will be able to decode them and read them, we cannot store any sensitive data in here. But that's not a problem at all because in the third part, 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. 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.

Upvotes: 396

Prateek kumar rai
Prateek kumar rai

Reputation: 131

To generate a unique secret key of say 64 bytes, run the following command in node :

crypto.randomBytes(64).toString("hex");

Upvotes: 13

Edison
Edison

Reputation: 81

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

Upvotes: 8

shark1608
shark1608

Reputation: 719

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);

Upvotes: 19

Satish Patro
Satish Patro

Reputation: 4414

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/

Upvotes: 19

Suragch
Suragch

Reputation: 512526

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

Upvotes: 69

Hans Z.
Hans Z.

Reputation: 54088

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.

Upvotes: 80

Related Questions