Skip to main content

How to Implement JSON Web Tokens (JWT) Authorization with QuickNode

Updated on
Jul 12, 2024

10 min read

Overview

Security is a crucial factor when it comes to protecting web resources. One way to protect those resources is by integrating JSON Web Tokens (JWT) in your web applications. JWT is an open standard that defines a compact way for securely transmitting information between parties. In this guide, you will learn about the core concepts behind JWTs and how to enable JWT on your blockchain node with QuickNode. We will demonstrate this process by creating a React app that will fetch a JWT from our backend server (Express.js) and then use it to request and display the blockchain data on our frontend. 

What You Will Need


  • An Ethereum endpoint powered by QuickNode (create a free account here)
  • Node.js installed
  • A Terminal Window
  • Basic knowledge of React
  • Basic knowledge of Express.js

What You Will Do


  • Learn about JSON Web Tokens (JWT)
  • Generate a script to create JWT tokens
  • Create an API using Express.js to sign JWT tokens
  • Build a frontend with React that calls our QuickNode node endpoint secured by JWT
DependencyVersion
node.js^18.16.0
express^4.19.2
jsonwebtoken^9.0.2
react^18.3.1

What is a JWT?

The idea behind JSON Web Tokens (JWT), also referred to as JOT is to create a standard and secure way for two parties to communicate. JWTs can be beneficial because they allow for stateless session management (no session cookies) where a backend server does not need to communicate with an authorization server. JWTs can be sent through a URL, POST parameter, or inside an HTTP header. They are also efficient due to their size. A JWT is composed of three components: A Header, Payload, and Signature. Each part is separated by a period (".") and is derived from a JSON object, which is then encoded via BASE64 into a text string. All the components put together are represented in the following format:

header.payload.signature

The RFC-7519 has more details on how this standard is defined. To understand each component in depth and how to decode a JWT, visit JWT.io.

These components combined are what make up a JWT. An example of a JWT would look something like this:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2Njk0Mzg4MDAsImlhdCI6MTY0ODgzNjY3Mn0.N4aNN5cwnYcMeZHeElrYtWcLxjfR-PqqLAvZNdCTGa-5wD_O3yFIM3F4ACX7egGXMCdob7UQwytMcMoAtnpKs8wyzdOlJgWyJIg3NsIWYdjnzuLz_EqNvIPdm3TEi7m0mZbgXLOGRQ_JS1RAF2i3XKPmhQuXq_ObSryPFfsLITimXJyoi5fiyX7WkUwJELIQVAlW5M5Um1fqIK791g52lIfM9vTU_PKIEJaMaBfUJMx92M04Mt8kYBjj7Eh1rxbEWeFA545HF_QKJe3j4EKoAx6BhL6oPCmoPoZXIAYlgAX6kf-FcbFfJ76u1ppeWsC0z_tfM5eDpVxHr2GY9d0o-A

kid (Key Id)

With JWTs, the "kid" (key ID) header parameter identifies which key should be used to verify the JWT's signature. This optional case-sensitive string value (e.g., "0123456789") will be useful for us as we may have multiple JWTs under one blockchain node endpoint, and it allows the verifier to know which public key to use when multiple keys are available. More information on this parameter can be found here.

JWT with QuickNode

Users can now use the JWT authentication method to protect their blockchain nodes. QuickNode supports JWT stand-alone or integrated with our other security methods, such as authorization tokens, referral whitelisting, and domain masking. However, note that if multiple authentication services are enabled on a blockchain node, each method must pass its security check, or the user request will return an error.

QuickNode supports JWTs created from key pairs using the RS256 or ECDSA256 algorithm, and there are no limits to how many JWTs you can activate on a blockchain node at once (you will just need to ensure you use your appropriate key ID). Now, we’re ready to create our React app!

Building a React app with JWT

Our app will be created using Express.js for the backend, which will create a REST API that will serve JWT tokens through a specific endpoint. Our React front-end will fetch this JWT and then use it to make a request to our blockchain node. The following steps will show you how to create the required files in your terminal window but feel free to use a code editor such as VScode.

Open a terminal window in the directory you'd like to create the project in and run the following command:

npx create-react-app jwt-app && cd jwt-app

Once our React app is initialized, let's install the required dependencies for this JWT implementation:

npm i express jsonwebtoken 

Then we'll create the required files, one for our backend server in Express.js, and another for our key pair generation.

touch index.js && touch generateKeys.js

We'll also need to configure the package.json file to include a proxy field. The proxy field will allow for a gateway between our React app and our backend server running on Express.js. Include the following field in your package.json file: 

"proxy": "http://localhost:3001"

Create the JWT Tokens

Next, in your terminal window, run the command nano generateKeys.js to open the file (or use a code editor like VSCode). Then include one of the following code snippets below (e.g., the RSA256 JavaScript or ES256 JavaScript example):


// Imported dependencies
const fs = require('fs')
const { generateKeyPairSync } = require('crypto');
var jwt = require('jsonwebtoken');

// Generate RSA keys
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
}
});

// Write key pairs to file
fs.writeFileSync('private_key.pem', privateKey);
console.log('Saved private_key.pem');

fs.writeFileSync('public_key.pem', publicKey);
console.log('Saved public_key.pem');

Save the file by pressing CTRL + X, then click Enter on your keyboard. Once the file is saved, we’ll run the command node generateKeys.js to create a key pair (public_key.pem and private_key.pem) and store it in the same directory. Note that this file should only be ran once, or you will generate new key pairs each time the file is executed.

The next step is to create our server code. Run the command nano index.js and input the following code:

// Import libraries
const express = require("express");
const fs = require("fs")
const jwt = require("jsonwebtoken")

// Server code
const PORT = process.env.PORT || 3001;
const app = express();


app.get('/get_token', (req, res) => { // endpoint to retrieve JWT

// read private key
const privateKey = fs.readFileSync(__dirname + "/private_key.pem")

// Create payload and JWT
var token = jwt.sign({}, privateKey, {

algorithm: 'RS256', // algo used to create JWT, change to ES256 if necessary
expiresIn: "2d", // set a 2 day expiration
keyid: '0123456789' // arbitrary key ID for this JWT token, must match the one you configure on node endpoint security tab

});

return res.json({ token: token }); // return an object containing the signed JWT

})

app.listen(PORT, () => {
console.log(`Server listening on ${PORT}`); // listen to connections on the specified host and port
});

danger

If you previously used ES256 to generate a public and private key pair (instead of RS256), change the value above in the algorithm field to ES256.

Remember to save the file! Now, we are off to creating our frontend code.

Create the React Frontend

Open the App.js file located within the src directory and input the code below. Also, remember to replace the string - "YOUR_QUICKNODE_HTTP ENDPOINT" with your actual QuickNode Endpoint. If you don't have an endpoint already, you can sign up for a free QuickNode account here and easily set up an endpoint!

import React from "react";
import "./App.css";

function App() {
const [data, setData] = React.useState(null);

React.useEffect(() => {
fetch("/get_token")
.then((res) => res.json())
.then((token) => {

fetch("YOUR_QUICKNODE_HTTP_ENDPOINT", { // don't have one? go to quicknode.com and create one now!
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token.token}`
},
body: JSON.stringify({ method: "eth_blockNumber", params: [], id: 1, jsonrpc: "2.0" })
}).then(res => res.json()).then(content => {
console.log(content)
setData(parseInt(content.result))
});

});
})

return (
<div className="App">
<header className="App-header">
<p>{!data ? "Loading..." : data}</p>
</header>
</div>
);
}

export default App;

We're almost done! Before we can start our app, we’ll need to add our public key pair to our blockchain node. Let’s set up JWT authentication on QuickNode next.

Add Public Key to QuickNode Node Endpoint

First, create a QuickNode endpoint for Ethereum Mainnet. Then, navigate to your Node's Security tab and click the Disable JWTs toggle to enable the setting, then click the Add JWT button.

JWT Section - QuickNode Endpoints

Enter a name for your JWT and paste the public key previously generated in your public_key.pem file into the second field, titled "Public Key."

JWT Section - QuickNode Endpoints

Note that the format of the public key should match the image above.

Once added, the public key's Name, ID, and Fingerprint will be displayed in the JSON Web Token section. Important: the value in the ID field should match the keyid value in your script (i.e., index.js), or you will run into an unauthorized error.

JWT Added to Node Security

Starting the React App

Before starting the Express API and React app, let's summarize how they will work together.


  1. The Express.js API will serve our /get_token endpoint, which, once invoked, will read the local private key, create and sign a JWT payload, then return the signed JWT.
  2. The React app will call the /get_token endpoint and fetch the signed JWT (i.e., bearer token)
  3. The React app then makes a call to the QuickNode endpoint to fetch the latest block number using the eth_blockNumber RPC method and includes the signed JWT in the header
  4. The React app returns the latest block number if the call is successful and JWT is authorized

Now, we'll need to open two terminal windows so we can run the backend server and React app simultaneously.

To start the backend server, run the command node index.js in one of your terminal windows. If the server is running, you should see the following output: "Server listening on 3001"

Then, in the other terminal window, run the command npm start to start the React app. A browser window should automatically open to the port the app is running on, and you should see a result similar to the one below:

React App Displaying Latest Block number

If you want to dive deeper, check out this awesome GitHub repository that shows you how to implement Cloudflare workers with JWT authorization on QuickNode.

Below are some answers to common questions a user might have when using JWT on QuickNode. If you have any further questions regarding this feature or any others, please don't hesitate to reach out to us!

Questions You May Have

Q: Which chains are JWT supported on?
A: JWT is supported on all chains

Q: How do I discard a JWT before it expires?
A: If your JWT might have been exposed and you want to prevent it from being used, you can remove the public key from the Node's security tab.

Q: Can I add multiple JWTs to a blockchain node?
A: There are no limits to how many JWTs you can activate on a blockchain node at once. If multiple JWTs are active, ensure you are using the proper ID value in the keyid field, which corresponds to the public/private key you are using when signing the JWT. More information can be found here.

Q: Which cipher does QuickNode support?
A: RSA 256 (RS256) and ECDSA 256 (ES256), as specified in RFC7518 table 3.1, are only supported at this time.

Q: How do I resolve 401 errors?
A: You may have other forms of security methods enabled on your blockchain node. Check to ensure your requests meet all security checks.

Q: What expiration date should I choose?  A: You can set any expiration date in the future you'd like. Generally, the shorter the expiration time, the more secure your JWT is.

Conclusion

Congratulations on completing this guide! We've learned about JWTs and how to enable it on your blockchain node with QuickNode. Subscribe to our newsletter for more articles and guides on Ethereum. If you have any feedback, feel free to reach out to us via Twitter. You can always chat with us on our Discord community server, featuring some of the coolest developers you'll ever meet 😃

We ❤️ Feedback!

Let us know if you have any feedback or requests for new topics. We'd love to hear from you.

Share this guide