> For a complete page index, fetch https://docs.conduit.xyz/llms.txt

# Make authenticated RPC requests

> Send a Conduit Nodes API key and JSON Web Token to an RPC endpoint with TypeScript or Go.

After you bind a public key to a Nodes API key, each RPC request must include both credentials:

* The Nodes API key in the endpoint URL path.
* The signed JSON Web Token (JWT) in the `Authorization: Bearer <JWT>` header.

Copy the HTTP endpoint URL from the **Endpoints** tab for your Nodes API key. The copied URL includes the API key path. Set the URL and a freshly generated token as environment variables:

```bash
export CONDUIT_RPC_URL='https://[YOUR_RPC_URL]/[YOUR_API_KEY]'
export JWT='[YOUR_SIGNED_JWT]'
```

If you need a token, [generate a JWT](/rpc-nodes/guides/jwt-authentication/generate-jwts) first.

## Send a request

These examples call `eth_blockNumber` and print the JSON-RPC response.

Save the example as `request.ts` or `request.go`.

**`TypeScript`**

```typescript TypeScript
const rpcURL = process.env.CONDUIT_RPC_URL
const token = process.env.JWT

if (!rpcURL || !token) {
  throw new Error('Set CONDUIT_RPC_URL and JWT')
}

const response = await fetch(rpcURL, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${token}`,
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'eth_blockNumber',
    params: [],
  }),
})

if (!response.ok) {
  throw new Error(`RPC request failed: ${response.status} ${await response.text()}`)
}

console.log(await response.json())
```

**`Go`**

```go Go
package main

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

func main() {
	rpcURL := os.Getenv("CONDUIT_RPC_URL")
	token := os.Getenv("JWT")
	if rpcURL == "" || token == "" {
		log.Fatal("set CONDUIT_RPC_URL and JWT")
	}

	body := []byte(`{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}`)
	request, err := http.NewRequest(http.MethodPost, rpcURL, bytes.NewReader(body))
	if err != nil {
		log.Fatal(err)
	}
	request.Header.Set("Content-Type", "application/json")
	request.Header.Set("Authorization", "Bearer "+token)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		log.Fatal(err)
	}
	defer response.Body.Close()

	responseBody, err := io.ReadAll(response.Body)
	if err != nil {
		log.Fatal(err)
	}
	if response.StatusCode < 200 || response.StatusCode >= 300 {
		log.Fatalf("RPC request failed: %s: %s", response.Status, responseBody)
	}

	fmt.Println(string(responseBody))
}
```

Run the example:

**`TypeScript`**

```bash TypeScript
npm install --save-dev tsx @types/node
npx tsx request.ts
```

**`Go`**

```bash Go
go run request.go
```

A successful response contains the latest block number in the `result` field.

## Refresh tokens before they expire

Issue short-lived tokens from your backend and replace them before `exp`. Never embed the private key or token-generation code in a browser app. If several clients share a token, refresh it early enough that active requests don't cross the expiration time.

## Troubleshoot authentication errors

If Conduit rejects a request, check that:

* The endpoint URL contains the correct Nodes API key.
* The `Authorization` header uses the `Bearer <JWT>` format.
* The JWT hasn't expired.
* The JWT header's `kid` matches the Key ID shown in Conduit.
* The JWT algorithm matches the algorithm selected for the public key.
* The public key is enabled and bound to the API key in the endpoint URL.

For other HTTP and JSON-RPC failures, use the [RPC error reference](/rpc-nodes/guides/rpc-errors).