Skip to content

Setting up your environment

Follow the guide below to set up your environment to execute actions with wallets from your server.

Node SDK vs. REST API

To execute delegated actions with wallets, your server must make HTTP requests to Privy's REST API with information about your intended action and appropriate authorization details.

Privy also offers a NodeJS SDK (@privy-io/server-auth) that wraps requests to Privy's REST API in a simple TypeScript interface. If your app uses a TypeScript/JavaScript backend, we strongly recommend using @privy-io/server-auth for executing delegated actions.

Make sure to follow the instructions here to set up your @privy-io/server-auth client or to configure your HTTP requests to Privy's REST API with the required authorization headers.

Authorization signatures

If your app has an authorization keypair enabled for delegated actions, your server must sign any request payloads for executing actions with wallets with your app's authorization private key. This signature must be included as a privy-authorization-signature header on RPC requests.

Follow the instructions below to ensure authorization signatures are included on requests to Privy's API, if applicable for your app.

Using @privy-io/server-auth

When initializing your instance of the PrivyClient, pass your authorization private key from the dashboard to the client's constructor like so:

tsx
import { PrivyClient } from '@privy-io/server-auth';

...

const privy = new PrivyClient('insert-your-app-id', 'insert-your-app-secret', {
  walletApi: {
    authorizationPrivateKey: 'insert-your-authorization-private-key-from-the-dashboard'
  }
});

If an authorization private key is passed in the constructor, the Privy client will automatically sign requests with the private key and include the signature as the required privy-authorization-signature header to Privy's API.

Using the REST API

If requesting Privy's REST API directly, your app must manually sign request payloads with your authorization private key. This involves three steps at a high-level:

  1. Generate a JSON payload containing the following fields. All fields are required unless otherwise specified.
FieldTypeDescription
version1Authorization signature version. Currently, 1 is the only version.
method'POST'HTTP method for the request. Currently, only 'POST' requests are used.
urlstringThe full URL for the request. Should not include a trailing slash.
bodyJSONJSON body for the request.
headersJSONJSON object containing any Privy-specific headers, e.g. those that are prefixed with 'privy-'. This should not include any other headers, such as authentication headers, content-type, or trace headers.
headers['privy-app-id']stringPrivy app ID header (required).
  1. Canonicalize the payload per RFC8785 and serialize it to a string. This GitHub repository links to various libraries for JSON canonicalization in different languages.
  2. Sign the serialized JSON with ECDSA P-256 using your app's private key and serialize it to a base64-encoded string.

See the code snippets below to serialize and sign requests with your app's private key.

ts
import canonicalize from 'canonicalize'; // Support JSON canonicalization
import crypto from 'crypto'; // Support P-256 signing

// Replace this with your private key from the Dashboard
const PRIVY_AUTHORIZATION_KEY = 'wallet-auth:insert-your-private-key-here';
...

function getAuthorizationSignature({url, body}: {url: string; body: object}) {
  const payload = {
    version: 1,
    method: 'POST',
    url,
    body,
    headers: {
      'privy-app-id': 'insert-your-app-id'
    }
  };

  // JSON-canonicalize the payload and convert it to a buffer
  const serializedPayload = canonicalize(payload) as string;
  const serializedPayloadBuffer = Buffer.from(serializedPayload);

  // Replace this with your app's authorization key. We remove the 'wallet-auth:' prefix
  // from the key before using it to sign requests
  const privateKeyAsString = PRIVY_AUTHORIZATION_KEY.replace('wallet-auth:', '');

  // Convert your private key to PEM format, and instantiate a node crypto KeyObject for it
  const privateKeyAsPem = `-----BEGIN PRIVATE KEY-----\n${privateKeyAsString}\n-----END PRIVATE KEY-----`;
  const privateKey = crypto.createPrivateKey({
    key: privateKeyAsPem,
    format: 'pem',
  });

  // Sign the payload buffer with your private key and serialize the signature to a base64 string
  const signatureBuffer = crypto.sign('sha256', serializedPayloadBuffer, privateKey);
  const signature = signatureBuffer.toString('base64');
  return signature;
}

const authorizationSignature = getAuthorizationSignature({
  url: 'https://auth.privy.io/api/v1/wallets/rpc',
  // Replace with your desired body
  body: {
    address: '0xb8B849D7647937eB7331Dc7b6C445651A3EC55aE',
    chain_type: 'ethereum',
    method: 'personal_sign',
    params: {
      message: 'Hello, Ethereum',
      encoding: 'utf-8'
    }
  },
});

Setting the privy-authorization-signature header

Once you have signed your request with your authorization keypair, include the produced signature as the 'privy-authorization-signature' header for your request.