> ## Documentation Index
> Fetch the complete documentation index at: https://developer.utgl.io/llms.txt
> Use this file to discover all available pages before exploring further.

# How to authenticate with the Issuing API using Node.js

## Overview

This tutorial shows you how to authenticate to the Issuing API using Node.js by generating signed JSON Web Tokens (JWTs).

## In This Recipe

1. Install Dependencies
2. Create signJWT function
3. Usage - GET Request
4. Usage - POST Request

## Prerequisites

* Node.js 16 or higher
* Your Issuing API credentials (Access Key and RSA key pair)

## Step 1: Install Dependencies

Install the required npm packages:

```bash theme={null}
npm install jsonwebtoken
```

## Step 2: Create signJWT Function

Create a utility function to handle JWT signing with SHA256 body hashing:

```javascript theme={null}
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
const fs = require('fs');

/**
 * Sign a JWT for Issuing API authentication
 * @param {string} privateKeyPath - Path to the private key file
 * @param {string} accessKey - Your Access Key (UUID)
 * @param {string} uri - The API endpoint URI (e.g., '/v1/ping')
 * @param {string} method - HTTP method (GET, POST, etc.)
 * @param {string} requestBody - The request body (empty string for GET requests)
 * @returns {string} Signed JWT token
 */
function signJWT(privateKeyPath, accessKey, uri, method, requestBody) {
  // Read private key
  const privateKey = fs.readFileSync(privateKeyPath, 'utf8');

  // Hash request body with SHA256
  const hashedBody = crypto
    .createHash('sha256')
    .update(requestBody)
    .digest('hex');

  const now = Math.floor(Date.now() / 1000);

  // Create JWT payload
  const payload = {
    sub: accessKey,
    iat: now,
    exp: now + 30, // 30 second expiration
    uri: uri,
    method: method,
    body: hashedBody,
  };

  // Sign the token
  const token = jwt.sign(payload, privateKey, {
    algorithm: 'RS256',
    header: {
      typ: 'JWT',
      alg: 'RS256',
    },
  });

  return token;
}

module.exports = { signJWT };
```

### Important Notes:

* **Request body is hashed** with SHA256 before signing
* **30 second expiration** for security
* **Private key format**: PEM-encoded RSA private key
* **Empty body**: Use empty string `""` for GET requests

## Step 3: Usage - GET Request

Make a simple GET request to test connectivity:

```javascript theme={null}
const { signJWT } = require('./auth'); // Assuming the signJWT function is in auth.js

const privateKeyPath = './utgl-access.private'; // Path to your private key
const accessKey = '6e33a078-99ed-4aa1-8e67-b0e19e9475fd'; // Replace with your access key

const uri = '/v1/ping';
const method = 'GET';
const requestBody = '';

async function makeGetRequest() {
  try {
    // Generate JWT
    const jwtToken = signJWT(privateKeyPath, accessKey, uri, method, requestBody);

    // Make HTTP request
    const response = await fetch(`https://sandbox.access.utgl.io${uri}`, {
      method: method,
      headers: {
        'Authorization': `Bearer ${jwtToken}`,
        'Content-Type': 'application/json',
      },
    });

    const data = await response.json();
    console.log(`${method} ${uri} ${response.status}`);
    console.log('Response:', data);
  } catch (error) {
    console.error('Error:', error.message);
  }
}

makeGetRequest();
```

## Step 4: Usage - POST Request

Make a POST request with a request body:

```javascript theme={null}
const { signJWT } = require('./auth'); // Assuming the signJWT function is in auth.js

const privateKeyPath = './utgl-access.private'; // Path to your private key
const accessKey = '6e33a078-99ed-4aa1-8e67-b0e19e9475fd'; // Replace with your access key

const uri = '/v1/ping';
const method = 'POST';
const requestBody = JSON.stringify({ message: 'Hello, world!' });

async function makePostRequest() {
  try {
    // Generate JWT
    const jwtToken = signJWT(privateKeyPath, accessKey, uri, method, requestBody);

    // Make HTTP request
    const response = await fetch(`https://sandbox.access.utgl.io${uri}`, {
      method: method,
      headers: {
        'Authorization': `Bearer ${jwtToken}`,
        'Content-Type': 'application/json',
      },
      body: requestBody,
    });

    const data = await response.json();
    console.log(`${method} ${uri} ${response.status}`);
    console.log('Response:', data);
  } catch (error) {
    console.error('Error:', error.message);
  }
}

makePostRequest();
```

## Using with Axios

If you prefer using Axios instead of fetch:

```javascript theme={null}
const axios = require('axios');
const { signJWT } = require('./auth');

const privateKeyPath = './utgl-access.private';
const accessKey = '6e33a078-99ed-4aa1-8e67-b0e19e9475fd';

async function makeRequest() {
  const uri = '/v1/accounts';
  const method = 'GET';
  const requestBody = '';

  const jwtToken = signJWT(privateKeyPath, accessKey, uri, method, requestBody);

  try {
    const response = await axios({
      method: method,
      url: `https://sandbox.access.utgl.io${uri}`,
      headers: {
        'Authorization': `Bearer ${jwtToken}`,
        'Content-Type': 'application/json',
      },
    });

    console.log(`${method} ${uri} ${response.status}`);
    console.log('Response:', response.data);
  } catch (error) {
    console.error('Error:', error.response?.data || error.message);
  }
}

makeRequest();
```

## TypeScript Version

For TypeScript projects:

```typescript theme={null}
import jwt from 'jsonwebtoken';
import crypto from 'crypto';
import fs from 'fs';

interface JWTPayload {
  sub: string;
  iat: number;
  exp: number;
  uri: string;
  method: string;
  body: string;
}

export function signJWT(
  privateKeyPath: string,
  accessKey: string,
  uri: string,
  method: string,
  requestBody: string
): string {
  const privateKey = fs.readFileSync(privateKeyPath, 'utf8');

  const hashedBody = crypto
    .createHash('sha256')
    .update(requestBody)
    .digest('hex');

  const now = Math.floor(Date.now() / 1000);

  const payload: JWTPayload = {
    sub: accessKey,
    iat: now,
    exp: now + 30,
    uri: uri,
    method: method,
    body: hashedBody,
  };

  return jwt.sign(payload, privateKey, {
    algorithm: 'RS256',
    header: {
      typ: 'JWT',
      alg: 'RS256',
    },
  });
}
```

## Common Pitfalls

<Warning>
  **Body Hashing is Critical!** The `signJWT` function automatically hashes the request body with SHA256 before including it in the JWT claims. Make sure you pass the **exact same request body** to both `signJWT()` and your HTTP request.
</Warning>

<Tip>
  **Token Expiration**: JWT tokens expire after 30 seconds. Generate a fresh token for each API request to avoid authentication errors.
</Tip>

<Warning>
  **JSON Stringify Consistency**: When sending JSON bodies, use `JSON.stringify()` consistently. The exact string representation must match between signing and sending.
</Warning>

## Next Steps

* See [Authentication](/issuing/getting-started/request-signing) for more details on JWT signing
* Explore [API Endpoints](/api-reference) to see what you can do
* Check out [Webhook Verification](/issuing/recipes/verify-webhook-nodejs) for handling webhooks
