> For the complete documentation index, see [llms.txt](/llms.txt).

# Authenticate with JWT

This tutorial demonstrates how to create and apply a JSON Web Token (JWT) to authenticate an [eth_blockNumber](/services/reference/ethereum/json-rpc-methods/eth%5Fblocknumber/) API request with Node.js.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

- [Node](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) version 20+
- A text editor (for example, [VS Code](https://code.visualstudio.com/))
- An [Infura account](https://app.infura.io/register)

## Steps[​](#steps "Direct link to Steps")

### 1\. Initiate your project[​](#1-initiate-your-project "Direct link to 1. Initiate your project")

Create a new directory for your project:

```
mkdir infura-jwt-demo

```

Next, change into the `infura-jwt-demo` directory:

```
cd infura-jwt-demo

```

Initialize a new Node.js project:

```
npm init -y

```

Install the required dependencies:

```
npm install axios jsonwebtoken dotenv

```

### 2\. Create a key pair[​](#2-create-a-key-pair "Direct link to 2. Create a key pair")

#### 2.1. Generate your private key[​](#21-generate-your-private-key "Direct link to 2.1. Generate your private key")

Generate your private key using the RSA (PKCS #8) or ES256 algorithm:

- RSA
- ES256

```
openssl genpkey                 \
  -algorithm RSA                \
  -out private_key.pem          \
  -pkeyopt rsa_keygen_bits:2048 \
  -outform PEM

```

```
openssl ecparam    \
  -genkey          \
  -name prime256v1 \
  -noout           \
  -out private_key.pem

```

#### 2.2. Generate your public key[​](#22-generate-your-public-key "Direct link to 2.2. Generate your public key")

Generate your public key from your RSA or ES256 private key:

- RSA
- ES256

```
openssl rsa           \
  -in private_key.pem \
  -pubout             \
  -out public_key.pem

```

```
openssl ec            \
  -in private_key.pem \
  -pubout             \
  -out public_key.pem

```

### 3\. Set up your `.env` file[​](#3-set-up-your-env-file "Direct link to 3-set-up-your-env-file")

#### 3.1. Update the Infura dashboard[​](#31-update-the-infura-dashboard "Direct link to 3.1. Update the Infura dashboard")

In the [Infura dashboard](https://app.infura.io/login), under **API Keys**, select the key you want to use for authentication. Go to its **Settings** tab. Under **Requirements**, fill out these fields:

- **JWT PUBLIC KEY NAME** - Provide a unique name for your JWT public key, which can help you manage multiple keys.
- **JWT PUBLIC KEY** - Paste the entire contents of the `public_key.pem` file.

note

Optionally, you can check **REQUIRE JWT FOR ALL REQUESTS**. If this option is not checked, you can make calls using your key without a JWT in the request header, however, invalid or expired tokens will result in the call being rejected.

#### 3.2. Create your `.env` file[​](#32-create-your-env-file "Direct link to 32-create-your-env-file")

At the root of your Node.js project, create an environment file:

```
touch .env

```

Add the following details to `.env`:

- Syntax
- Example

.env

```
INFURA_API_KEY=<YOUR-API-KEY>
JWT_KEY_ID=<YOUR-JWT-KEY-ID>
INFURA_NETWORK_URL=<NETWORK-URL>

```

.env

```
INFURA_API_KEY=8c101...6b26c77d8
JWT_KEY_ID=777e2caf...826bc4303f
INFURA_NETWORK_URL=https://sepolia.infura.io/v3/

```

Replace the following values in the `.env` file:

- `<YOUR-API-KEY>` with your API key from the Infura dashboard.
- `<YOUR-JWT-KEY-ID>` with the JWT's key ID. This is generated by Infura, and you can find it in the Infura dashboard. The code in [Step 4](#4-create-and-apply-your-jwt) applies this ID to the JWT header to allow Infura to identify which key was used to sign the JWT.
- `<NETWORK-URL>` with the URL of an Infura network for which your key has access rights, and that supports the method [eth_blockNumber](/services/reference/ethereum/json-rpc-methods/eth%5Fblocknumber/).

Important

Before pushing code to a public repository, add `.env` to your `.gitignore` file. This reduces the likelihood that keys are exposed in public repositories.

Note that `.gitignore` ignores only untracked files. If your `.env` file was committed in the past, it's tracked by Git. Untrack the file by deleting it and running `git rm --cached .env`, then include it in `.gitignore`.

### 4\. Create and apply your JWT[​](#4-create-and-apply-your-jwt "Direct link to 4. Create and apply your JWT")

Create a new file named `call.js`:

```
touch call.js

```

Add the following to `call.js`:

call.js

```
require('dotenv').config()
const axios = require('axios')
const jwt = require('jsonwebtoken')
const fs = require('fs')

function getAlgorithm(privateKey) {
  if (privateKey.includes('BEGIN RSA PRIVATE KEY') || privateKey.includes('BEGIN PRIVATE KEY')) {
    return 'RS256'
  } else if (privateKey.includes('BEGIN EC PRIVATE KEY')) {
    return 'ES256'
  } else {
    throw new Error('Unsupported key type')
  }
}

// Function to generate the JWT
function generateJWT() {
  const privateKey = fs.readFileSync('private_key.pem', 'utf8')
  const algorithm = getAlgorithm(privateKey)
  const token = jwt.sign({}, privateKey, {
    algorithm: algorithm, // Dynamically set the algorithm based on the key type
    keyid: process.env.JWT_KEY_ID,
    audience: 'infura.io',
    expiresIn: '1h',
    header: {
      typ: 'JWT',
    },
  })

  return token
}

// Function to authenticate with Infura and get the latest block number
async function getBlockNumber() {
  const jwtToken = generateJWT()
  const url = `${process.env.INFURA_NETWORK_URL}${process.env.INFURA_API_KEY}`
  const data = {
    jsonrpc: '2.0',
    method: 'eth_blockNumber',
    params: [],
    id: 1,
  }

  try {
    const response = await axios.post(url, data, {
      headers: {
        Authorization: 'Bearer ' + jwtToken,
        'Content-Type': 'application/json',
      },
    })
    console.log('Block number:', response.data.result)
  } catch (error) {
    console.error(
      'Error fetching block number:',
      error.response ? error.response.data : error.message
    )
  }
}

// Call the function to get latest block
getBlockNumber()

```

Next, run the code:

```
node call.js

```

Your console outputs the response, for example:

```
Block number: 0x61fc48

```

tip

This script:

1. Generates a JWT with a 1-hour expiry that is only valid on `infura.io`.
2. Applies this JWT to form the header of a `getBlockNumber` call.
3. Submits the API call.

### (Optional) Examine the curl equivalent[​](#optional-examine-the-curl-equivalent "Direct link to (Optional) Examine the curl equivalent")

If you want to better understand the code applied in [Step 4](#4-create-and-apply-your-jwt), you can examine the equivalent curl request.

Create a new file named `curl.js`:

```
touch curl.js

```

Add the following to `curl.js`:

curl.js

```
require('dotenv').config()
const jwt = require('jsonwebtoken')
const fs = require('fs')

function getAlgorithm(privateKey) {
  if (privateKey.includes('BEGIN RSA PRIVATE KEY') || privateKey.includes('BEGIN PRIVATE KEY')) {
    return 'RS256'
  } else if (privateKey.includes('BEGIN EC PRIVATE KEY')) {
    return 'ES256'
  } else {
    throw new Error('Unsupported key type')
  }
}

// Function to generate the JWT
function generateJWT() {
  const privateKey = fs.readFileSync('private_key.pem', 'utf8')
  const algorithm = getAlgorithm(privateKey)
  const token = jwt.sign({}, privateKey, {
    algorithm: algorithm, // Dynamically set the algorithm based on the key type
    keyid: process.env.JWT_KEY_ID,
    audience: 'infura.io',
    expiresIn: '1h',
    header: {
      typ: 'JWT',
    },
  })
  return token
}

// Generate the JWT and print the curl command
async function printCurlRequest() {
  const jwtToken = generateJWT()
  console.log('Generated JWT:', jwtToken)
  const curlRequest = `
    curl -X POST ${process.env.INFURA_NETWORK_URL}${process.env.INFURA_API_KEY} \\
      -H "Authorization: Bearer ${jwtToken}" \\
      -H "Content-Type: application/json" \\
      -d '{
        "jsonrpc": "2.0",
        "method": "eth_blockNumber",
        "params": [],
        "id": 1
      }'
      `
  console.log('Equivalent curl request:')
  console.log(curlRequest)
}

// Call the function to print the curl request
printCurlRequest()

```

Next, run the code:

```
node curl.js

```

Your console outputs the curl request, for example:

```
curl -X POST https://sepolia.infura.io/v3/<YOUR-API-KEY> \
  -H "Authorization: Bearer pqJhbG**JWT-token**2Ud5o2Q" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_blockNumber",
    "params": [],
    "id": 1
  }'

```

You can run this request yourself to make the call. Your console outputs the response, for example:

```
{"jsonrpc":"2.0","id":1,"result":"0x61fc48"}

```

## Next steps[​](#next-steps "Direct link to Next steps")

Consider following these next steps:

- [Configure your JWT](/services/how-to/json-web-token-jwt/) to control its scope.
- Decode your JWT: Copy the JWT provided in the console by the [optional curl equivalent step](#optional-examine-the-curl-equivalent), and paste it into the **Encoded** field in [jwt.io](https://jwt.io/).
- Add a layer of verification to your call by applying the JWT's **FINGERPRINT** provided in the Infura dashboard.  
note  
The JWT's fingerprint is a hash of the public key, used to ensure the key's integrity and authenticity.
