> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nelieo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Authenticating API Requests to the NSP Axon Daemon

> Generate API keys with axon-daemon keygen, pass them via X-Substrate-Key, and configure the keys file and auth settings in axon.toml.

By default, the NSP daemon requires every API request to carry a valid API key in the `X-Substrate-Key` header. This prevents other processes on the same machine — or any local web page — from querying your application state or triggering actions without your authorization. Keys are stored as one-way hashes, so the plaintext secret never persists on disk anywhere other than your own secure storage. Authentication is enabled by default and should remain enabled in any environment beyond your local development machine.

## Generating an API Key

Run the following command to generate a new key and register it instantly:

```powershell theme={null}
axon-daemon.exe keygen
```

The daemon prints the key to stdout and appends its hashed form to `axon_keys.json`. The key is active immediately — no restart required.

```text theme={null}
✅ Generated new API key: sk_nsp_a1b2c3d4e5f6789...
   Added to: C:\ProgramData\Nelieo\axon_keys.json
   The daemon will accept this key immediately (no restart required).
```

<Warning>
  Copy the key from this output and store it in a secrets manager or environment variable. The daemon stores only the hash — it cannot reconstruct the plaintext key later.
</Warning>

## Using the API Key

Pass your key in the `X-Substrate-Key` header on every request.

<CodeGroup>
  ```bash curl theme={null}
  curl -H "X-Substrate-Key: sk_nsp_a1b2c3d4e5f6..." \
       http://localhost:7842/substrate/v1/apps
  ```

  ```python Python SDK theme={null}
  import nelieo_nsp as nsp

  # Pass the key directly
  async with nsp.NSPClient(api_key="sk_nsp_a1b2c3d4...") as client:
      apps = await client.list_apps()
  ```

  ```bash Environment variable (Python SDK) theme={null}
  # Set once in your shell or .env file
  export NSP_API_KEY=sk_nsp_a1b2c3d4...

  # The SDK reads it automatically when no api_key argument is given
  ```
</CodeGroup>

## Keys File Format

The daemon reads keys from the JSON file configured in `axon.toml` under `auth.keys_file` (default: `C:\ProgramData\Nelieo\axon_keys.json`). You can inspect this file to see all registered keys:

```json theme={null}
{
  "keys": [
    {
      "id": "key_01j5abc123",
      "key_hash": "hash:a3f8c9d2...",
      "label": "my-agent-prod",
      "created_at": "2026-07-20T13:00:00Z",
      "last_used_at": "2026-07-20T18:30:00Z",
      "enabled": true
    }
  ]
}
```

<ResponseField name="id" type="string">
  A unique identifier for this key entry, generated automatically by `keygen`.
</ResponseField>

<ResponseField name="key_hash" type="string">
  A one-way hash of the plaintext API key. The daemon verifies each incoming request against all entries with `enabled: true`. The plaintext key is never stored on disk.
</ResponseField>

<ResponseField name="label" type="string">
  A human-readable name for this key. Set it to something that identifies the agent or system using it — for example, `"ci-runner"` or `"production-agent-v2"`.
</ResponseField>

<ResponseField name="created_at" type="string">
  ISO 8601 timestamp of when the key was generated.
</ResponseField>

<ResponseField name="last_used_at" type="string">
  ISO 8601 timestamp of the most recent successful request using this key. Updated after each authenticated request.
</ResponseField>

<ResponseField name="enabled" type="boolean">
  Set to `false` to revoke a key without deleting it. The daemon rejects requests from disabled keys with a `401 disabled_key` response.
</ResponseField>

<Tip>
  To revoke a key immediately, open `axon_keys.json` and set `"enabled": false` on the relevant entry. The daemon picks up the change on the next request — no restart needed.
</Tip>

## Enabling Auth in axon.toml

Authentication is enabled by default. The relevant section of `axon.toml` is:

```toml theme={null}
[auth]
# Require a valid X-Substrate-Key header on all requests. Default: true
require_key = true

# Path to the JSON file containing hashed API keys
keys_file = "C:\\ProgramData\\Nelieo\\axon_keys.json"
```

To point the daemon at a different keys file — for example, a per-user file at `%APPDATA%\Nelieo\keys.json` — update `keys_file` and restart the daemon.

## Authentication Errors

When a request fails authentication, the daemon returns `HTTP 401` with a JSON body that identifies the specific failure reason.

| Status | Error code     | Cause                                                           |
| ------ | -------------- | --------------------------------------------------------------- |
| `401`  | `missing_key`  | No `X-Substrate-Key` header was present on the request          |
| `401`  | `invalid_key`  | A key was provided but does not match any hash in the keys file |
| `401`  | `disabled_key` | The key matches an entry but that entry has `"enabled": false`  |

A `missing_key` response looks like this:

```bash theme={null}
curl http://localhost:7842/substrate/v1/apps
```

```json theme={null}
{
  "error": "missing_key",
  "message": "This endpoint requires an X-Substrate-Key header.",
  "status": 401
}
```

An `invalid_key` response:

```bash theme={null}
curl -H "X-Substrate-Key: sk_nsp_wrongkey" \
     http://localhost:7842/substrate/v1/apps
```

```json theme={null}
{
  "error": "invalid_key",
  "message": "The provided API key is not recognized.",
  "status": 401
}
```

## Disabling Auth for Development

To run without key validation during local development, set `require_key = false` in your config or pass the environment variable:

<Tabs>
  <Tab title="axon.toml">
    ```toml theme={null}
    # axon.toml — DEVELOPMENT ONLY
    [auth]
    require_key = false
    ```
  </Tab>

  <Tab title="Environment variable">
    ```powershell theme={null}
    $env:AXON_AUTH__REQUIRE_KEY = "false"
    axon-daemon.exe run
    ```
  </Tab>
</Tabs>

The daemon prints the following warning at startup and repeats it every 60 seconds while auth is disabled:

```text theme={null}
⚠️  NSP DAEMON RUNNING WITHOUT AUTHENTICATION — All API requests pass without
    a key. Set AXON_AUTH__REQUIRE_KEY=true before any production use.
```

For a full treatment of production security practices — network binding, key rotation, and least-privilege service accounts — see the [API Keys security guide](/security/api-keys).
