Skip to main content
The Nmbr Component is designed so that your API secret is never exposed to the browser. Every API call made by the component is authenticated using a JWT signature produced by your server, ensuring that only authorized requests reach the Nmbr API.

How Request Signing Works

When the Nmbr Component needs to interact with the Nmbr API (for example, to load payroll data or submit changes), it does not call the API directly. Instead, it follows a three-step signing flow:

1. The Component Intercepts the Request

Before any API call leaves the browser, the Nmbr Component intercepts it and extracts the request body. This body contains the data that will be sent to the Nmbr API.

2. Your Server Signs the Request

The component sends the request body to the signing endpoint you configured during initialization (via signingUrl or a custom sign function). Your server:
  1. Receives the JSON request body
  2. Signs the body as a JWT using the SHA-256 hash of your API Secret and the HS256 algorithm
  3. Returns the signed JWT token to the component
Because this step happens on your server, your API Secret is never sent to or accessible from the browser.

3. The Component Calls the Nmbr API

The component takes the signed JWT returned by your server and includes it with the API request to the Nmbr API. The Nmbr API validates the signature to confirm the request was authorized by your server before processing it. Diagram showing the request signing flow between the browser, your server, and the Nmbr API

Why This Architecture?

API Secret Never Leaves Your Server

The signing flow ensures that your API Secret is only ever used server-side. The browser never has access to it, which eliminates the risk of credential exposure through client-side code, browser extensions, or network inspection.

You Control Authorization

Your signing endpoint is a server-side route in your application. This means you can enforce your own authentication and authorization logic before signing any request. For example, you can verify that the current user is logged in and has permission to administer payroll before returning a signature.

Every Request is Verified

The Nmbr API validates the JWT signature on every incoming request. If a request has been tampered with or was not signed by your server, it will be rejected.

Signing Endpoint Requirements

Your signing endpoint must:
  • Accept POST requests with a JSON body
  • Sign the body as a JWT using the HS256 algorithm
  • Use the SHA-256 hash of your API Secret as the signing key (hex-encoded or base64-encoded)
  • Return the signed JWT as plain text with a 201 status code
  • Be protected by your own authentication and authorization. See Authenticating the Signing Request below
For implementation examples in Ruby, Node.js, PHP, and .NET, see the Getting Started guide.

The Signed Payload

The Component builds the JWT payload for each API request. Your signingUrl or sign function should sign the JSON it receives as-is. You do not need to create or change the JWT claims. If you inspect or build the payload yourself, set the uri claim to the API request path, including the query string when one is present. Exclude the scheme, host, and /services/payroll base path. For example:
  • GET https://sandbox.nmbr.co/services/payroll/employees?per_page=5uri: "/employees?per_page=5"
  • GET https://sandbox.nmbr.co/services/payroll/employeesuri: "/employees"

Authenticating the Signing Request

Note: cookies are not sent to your signing endpoint by default. The following approaches are supported:

Bearer Authentication

Send a token in an HTTP header on every signing request and validate it server-side. The token can be an API key, signed token, or bearer JWT from your own auth system. Use the custom sign function below to attach the header. signingUrl does not support custom headers. If your architecture specifically requires cookie-based auth, the custom sign function below lets you write your own fetch call with credentials: 'include'.

Custom Signing Function

If your application architecture requires more control over the signing process (for example, if you need to add custom headers or use a different transport), you can provide a sign function instead of a signingUrl when initializing the component:
window.components = nmbr.initialize({
  companyId,
  partnerId,
  sign: async (json: string): Promise<string> => {
    const response = await fetch('/your-custom-endpoint', {
      method: 'POST',
      headers: {
        Accept: 'text/plain',
        'Content-Type': 'application/json',
        Authorization: `Bearer ${yourSessionToken}`,
      },
      body: json,
    });

    return response.text();
  },
});
This gives you full control over how the signing request is made while maintaining the same security guarantees.

Best Practices

  • Protect your signing endpoint — Ensure it is behind authentication so that only logged-in users with the appropriate permissions can request signatures.
  • Store your API Secret securely — Use environment variables or a secrets manager. Never hard-code it in source files or commit it to version control.
  • Use HTTPS — All communication between the browser, your server, and the Nmbr API should be over HTTPS to prevent interception.
  • Limit access — Only users who need to administer payroll should be able to reach the signing endpoint.