DEV Community

Tayfun Akgüç
Tayfun Akgüç

Posted on • Updated on

JWT with RSA Signature

Hello everyone!

In this article we will learn how to sign JSON Web Token with RSA key.

Let’s start!

Initialize NodeJS Project

First of all, I'm gonna create the project folder. Then install jsonwebtoken package.

cd path/to/your/workspace
# Create project folder
mkdir jwt-rsa
# Change directory
cd jwt-rsa
npm init -y
# Install JWT
npm install --save jsonwebtoken
Enter fullscreen mode Exit fullscreen mode

Generate RSA Token

Now let's generate public and private key. If you increase the key length, token length will be increase too. This means HTTP request body size will be increase. But also it depends what kind of payload we we'll sign.

# Create a folder named keys
mkdir keys
# Minimum RSA key length is 1024 bits
# Maximum RSA key length is 16384 bits 
# Don't add passphrase
ssh-keygen -t rsa -b 1024 -m PEM -f keys/rsa.key
# Write public key to keys/rsa.key.pub file
openssl rsa -in keys/rsa.key -pubout -outform PEM -out keys/rsa.key.pub

Enter fullscreen mode Exit fullscreen mode

Also you can use this online tool to get public/private key pair.

Folder Structure

Folder Structure

Implementation of signToken() and verifyToken() Methods

Note that, I'm not gonna use all jwt options like issuer, audience or expiresIn etc... except algorithm

This is how we sign a token synchronously. This usage, returns the JSON Web Token as string.

  • jwt.sign(payload, secretOrPrivateKey, options)

jwt.js

  1. signToken(): Takes payload object as parameter and returns the token as string.
  2. verifyToken() Takes token as parameter and returns the payload that we signed.
//* jwt.js
const fs = require('fs')
const path = require('path')
const jwt = require('jsonwebtoken')

const privateKey = fs.readFileSync(path.join(__dirname, 'keys', 'rsa.key'), 'utf8')
const publicKey = fs.readFileSync(path.join(__dirname, 'keys', 'rsa.key.pub'), 'utf8')


module.exports = {

    signToken: (payload) => {
        try {
            return jwt.sign(payload, privateKey, { algorithm: 'RS256'});
        } catch (err) {
            /*
                TODO throw http 500 here 
                ! Dont send JWT error messages to the client
                ! Let exception handler handles this error
            */
            throw err
        }
    },

    verifyToken: (token) => {
        try {
            return jwt.verify(token, publicKey, { algorithm: 'RS256'});
        } catch (err) {
            /*
                TODO throw http 500 here 
                ! Dont send JWT error messages to the client
                ! Let exception handler handles this error
            */
            throw err
        }
    }

}

Enter fullscreen mode Exit fullscreen mode

Signing Payload and Verifying Token

//* app.js
const { signToken, verifyToken } = require('./jwt')

const token = signToken({ userId: 1 })
console.log({ token })

const verified = verifyToken(token)
console.log({ verified }) 
Enter fullscreen mode Exit fullscreen mode

Let's See What Happened

Run app.js

node app.js
Enter fullscreen mode Exit fullscreen mode

And you'll see something like this

Output

Github repository

Thanks a lot for reading.

Top comments (2)

Collapse
 
hubertformin profile image
Hubert Formin • Edited

Thank you for this!
For some reason, I keep gettinga JsonWebTokenError: invalid signature error, Can you help me fix this?

Signing

const private_key = readFileSync(
      join(__dirname, "../../.private", "rsa.key"),
      "utf8"
    );

    const token = jwt.sign(
      {
        id: accountId,
        environment: secretKey.environment,
      },
      private_key,
      {
        algorithm: "RS256",
        expiresIn: 3600,
      }
    );
Enter fullscreen mode Exit fullscreen mode

Verifying

const public_key = readFileSync(
      join(__dirname, "../../.private", "rsa.key.pub"),
      "utf8");

const decodedToken = jwt.verify(token, public_key, {
      algorithms: ["RS256"],
 });
Enter fullscreen mode Exit fullscreen mode
Collapse
 
tayfunakgc profile image
Tayfun Akgüç • Edited

Hi Hubert!

I think the problem is about the rsa key file path. Are you trying to access 'private' folder or '.private' folder? If it's possible, feel free to share your GitHub repo.

I'm not sure where did you put the key files. But you can try this;

For Signing
join(__dirname, '..', '..', 'private', 'rsa.key')

For Verifying
join(__dirname, '..', '..', 'private', 'rsa.key.pub')

If the private folder is a hidden folder you can do;

join(__dirname, '..', '..', '.private', 'rsa.key')