> Source: https://nexusatlas.dev/guides/auth — Nexus Atlas developer documentation (Guides). Converted from the HTML page; the page is canonical.

# Peer authentication

Ten nodes tolerate hand-edited peer lists. A hundred don't. The `[auth]` section answers exactly one question — *what happens when a handshake arrives from a public key that is not in the config?* — and it answers it with three providers of increasing dynamism, every one of which fails closed. Peers you configured explicitly are always accepted; a provider only ever *extends* trust, never revokes what you wrote.

## Provider static — the default

Unknown keys are rejected. Identical to having no `[auth]` table at all. This is the right answer for fixed fleets: the config file is the complete trust statement, and nothing can widen it.

## Provider keyfile — an allowlist that updates without restarts

```
[auth]
provider = "keyfile"
keyfile = "/etc/atlas/authorized_peers.toml"
```

The keyfile is a TOML list of `[[peer]]` entries — `public_key` plus `allowed_ips` — re-read whenever its modification time changes. Granting a new node is appending an entry; revoking is deleting one; neither touches the daemon. Two properties to plan around:

- **Revocation stops *new* sessions.** An established session lives until its next rekey — with the default rekey interval, minutes, not days. Rotate the interval down if your threat model needs faster eviction.

- **An unreadable keyfile authorizes nobody.** Fail closed means a botched deploy of the allowlist quietly reverts you to `static` behavior rather than open doors.

## Provider command — your control plane decides

```
[auth]
provider = "command"
command = "/usr/local/lib/atlas/authorize-peer"
command_timeout_ms = 5000
deny_cache_secs = 30
```

For every unknown key, the daemon executes your hook as `command <base64-pubkey> <source-addr>`. Exit 0 authorizes, and each stdout line becomes an allowed-IPs CIDR for the new peer; any other exit denies. This is the integration point for an enrolment database, LDAP, an inventory system — whatever owns identity in your world. The contract is small enough to implement in a shell script and strict enough to trust:

- The hook runs *off* the packet path, under a hard time budget (`command_timeout_ms`) — a hung hook drops that handshake, never stalls the daemon.

- Denied keys are cached (`deny_cache_secs`) so a handshake flood from an unauthorized key cannot hammer your backend.

- A missing or non-executable hook refuses to start the daemon. Misconfiguration is loud, at startup, on purpose.

```
#!/bin/sh
# authorize-peer <base64-pubkey> <source-addr>
# Example: ask an internal inventory service; print the peer's tunnel /32.
KEY="$1"
RESP=$(curl -fsS --max-time 3 "https://inventory.example.internal/atlas/authorize?key=${KEY}") || exit 1
echo "$RESP"      # e.g. "10.0.100.57/32"
exit 0
```

## Choosing, honestly

| Fleet shape | Provider | Why |
|-------------|----------|-----|
| Fixed, small, security-reviewed configs | static | The config is the audit artifact. |
| Growing fleet, human-approved joins | keyfile | Grant/revoke is a file edit — scriptable, diffable, no restarts. |
| Enrolment owned by an external system | command | Atlas asks; your system answers; the contract is two arguments and an exit code. |

Library embedders have a fourth option: inject a custom authenticator implementation directly into the engine, bypassing the providers entirely.

> **Scope check:** `[auth]` governs *data-plane peers* — who may join the tunnel. Dashboard users, API tokens and mesh read tokens are a separate, independently documented surface: see the [REST API auth model](https://nexusatlas.dev/docs/api#auth-model).
