Connect a Node application
Check an existing server-side function and inspect its call and result decisions.
The Node SDK adds AuthRail checks around a function your application already uses. It sends the requested call and returned result to the local sidecar, then makes the decisions available to your application.
This guide connects one invoice-reading function in Observe. By the end, you can read both decisions and find the request in AuthRail. The invoice reader still runs even if a rule would deny it, so use a safe system first.
You need Node.js 20 or newer, an existing application, and a running sidecar. Complete the dashboard setup and connection details first. Keep the organisation ID, deployment ID, reviewed Operation Version ID, adapter-token file and private-key file available to the protected server application.
1. Install the SDK
From your application's directory, install the npm package:
npm install @authrail/sdk-node@0.1.1Keep the package version and your lockfile in source control for repeatable installs. Installing the SDK does not start your application or the sidecar.
Build from source when contributing
git clone https://github.com/AuthRail/authrail-sdk-node.git
cd authrail-sdk-node
npm ci
npm run buildThis compiles JavaScript and TypeScript declarations into dist/. To try your
changes in another application, run npm install /absolute/path/to/authrail-sdk-node
from that application's directory. Use its actual checkout path.
2. Connect to the sidecar
Create the client once in your server application. Here config is your own
configuration object: its IDs come from AuthRail, and its file paths point to
the private files you prepared in the connection guide.
import { readFileSync } from 'node:fs';
import { ObserveClient } from '@authrail/sdk-node';
const client = new ObserveClient({
sidecarUrl: 'http://127.0.0.1:7078',
organisationId: config.organisationId,
deploymentId: config.deploymentId,
adapterToken: readFileSync(config.adapterTokenFile, 'utf8').trim(),
executorPrivateKey: readFileSync(config.executorPrivateKeyFile, 'utf8'),
});The token file is the local adapter-token created during setup. The private key is executor-private.pem; the sidecar gets only the matching public PEM. Keep this code in the protected server application, outside the agent and browser bundle.
Use the native sidecar if this application runs on your host, or follow the Docker application placement if it runs in Docker. The local URL must reach the sidecar beside this application.
3. Check an invoice read
Suppose an authenticated staff member asks an assistant to read an invoice. The application resolves the invoice ID and uses an existing invoiceService.read function:
const { result, observation } = client.observe({
operationVersionId: config.invoiceReadOperationVersionId,
actionKey: request.stableBusinessKey,
principalId: session.staffId,
sessionId: session.id,
resourceId: invoice.id,
principalSource: 'application_session',
resourceSource: 'application_lookup',
}, { invoiceId: invoice.id }, () => invoiceService.read(invoice.id));
const invoiceResult = await result;
const checks = await observation;
console.log(checks.callDecision?.outcome, checks.resultDecision?.outcome);
console.log(checks.callError, checks.resultError);request, session, invoice and invoiceService are your application's objects. Resolve them through authenticated middleware and a protected lookup, rather than trusting IDs supplied by the model. The reviewed Operation must cover the arguments, returned JSON object and resource identity in this example. For an action without a target resource, omit resourceId and use resourceSource: 'not_applicable'.
result is the function's own result or error. observation has separate call/result decisions or errors. A failed function has no successful result to check. In Observe, a deny decision or unavailable sidecar does not stop the function. Use a safe system when testing actions with effects.
4. Read the decisions
With a healthy setup, the checks contain decisions for tool_call and tool_result. The outcome depends on your published Rails. recordingStatus: 'retained' means AuthRail stored that report; 'queued' means it is saved locally for later delivery. An error is not an allow decision.
Open the deployment's Actions & decisions in your workspace. Inspect the Action and both certificates. Keep actionKey stable across retries of the same business request; generate a different business key for a different request. Arguments and successful results must be bounded JSON objects.
Next: require permission before the function runs
Observe shows how the rules apply. Once you have checked the decisions and reviewed other access routes, use Enforce to stop the function unless permission is established. Read Observe and Enforce, human approvals and recovery before changing that boundary.
Switch this integration to Enforce
In the deployment's Overview → Review Enforce setup, resolve any missing
setup or call/result reports, confirm the protected boundary and select
Turn on Enforce. Replace the Observe client and wrapper with EnforceClient:
import { EnforceClient } from '@authrail/sdk-node';
const enforcingClient = new EnforceClient(protectedClientConfig);
const checked = await enforcingClient.enforce(operation, args,
async (checkedArgs, execution) => {
await privateLedger.saveRecovery(execution);
return protectedPayments.refund(checkedArgs, {
idempotencyKey: execution.providerIdempotencyKey,
});
});protectedClientConfig has the same connection and key fields as the earlier
client. This refund example uses your own operation, args, privateLedger
and protectedPayments; it does not supply a payment service.
The SDK requires a covered allow decision or valid approval permit, saved by AuthRail, and a saved execution-start report before calling this function. Use the checked arguments and provider idempotency key. Save recovery context before the provider call. A result check can withhold output after the effect; it cannot undo that effect.
Approvals, unknown outcomes and additional SDK features
A saved approval wait raises EnforceBlockedError with approvalContinuation.
Encrypt and save it with the original authenticated request before a restart.
resumeApprovalFrom claims an approved call. recoverApprovalFrom reads an
existing permit after a lost claim response. Neither permits replacement
model arguments or starts an already-started attempt.
EnforceOutcomeUnknownError includes recovery context. Check the provider using
the original idempotency key before reconcile. Do not rerun the function on
a generic network error. The recovery guide explains this flow.
The SDK README also covers
source facts, Guard handlers and discovery. Run npm test from the SDK checkout
to build and run its source checks. Those checks do not establish that every
route in your application is protected.
The Runtime walkthrough shows a connected application and the decisions it retained in AuthRail.