> ## Documentation Index
> Fetch the complete documentation index at: https://hs-df36fa00.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Store Encrypted Agent Credentials as Auth Contexts

> Register encrypted auth contexts to store bearer tokens and API keys for agents. Reference them by ID at invocation time instead of passing raw tokens.

Auth contexts let you register encrypted credential references on ServiceNet. Instead of passing a raw bearer token or API key on every invocation, you store the credential once and reference it by `auth_context_id`. Tokens are encrypted at rest with ChaCha20-Poly1305 — only a masked preview is ever exposed in API responses, making auth contexts safe to log and inspect without leaking secrets.

## When to use auth contexts

Consider storing credentials as auth contexts when:

* You want to avoid embedding tokens in client code, request logs, or orchestration configs
* You invoke the same agent repeatedly from multiple callers that share a credential
* You want to manage and rotate credentials centrally without redeploying callers

## Register an auth context

Send a `POST` to `/v1/auth-contexts/register` with the credential details. The `provider_id` you supply must match the provider that owns the target agent — the gateway enforces this at invocation time.

```bash theme={null}
curl -X POST http://127.0.0.1:8042/v1/auth-contexts/register \
  -H 'content-type: application/json' \
  -d '{
    "subject_did": "did:key:z6MkhaXgBZDvotD1X9gRrYkM5Xq9jYQqK6d8r8bQdE1mV2Xa",
    "provider_id": "acme-labs",
    "auth_model": { "mode": "bearer_token" },
    "token": "my-secret-api-key"
  }'
```

ServiceNet encrypts the token, stores a `secret_ref` UUID pointing to the encrypted blob, and returns the new `AuthContextRecord`:

```json theme={null}
{
  "auth_context_id": "550e8400-e29b-41d4-a716-446655440000",
  "secret_ref": "b3a9f120-4c2d-4e8a-9f1b-7d3c5e6a8b2d",
  "subject_did": "did:key:z6MkhaXgBZDvotD1X9gRrYkM5Xq9jYQqK6d8r8bQdE1mV2Xa",
  "provider_id": "acme-labs",
  "auth_model": { "mode": "bearer_token" },
  "token_preview": "my-se***",
  "created_at": "2025-01-15T10:00:00Z"
}
```

<Note>
  `token_preview` shows only the first few characters of the original token followed by asterisks. The full token is never returned in any API response after registration.
</Note>

### Request fields

<ParamField body="subject_did" type="string" required>
  The DID of the credential owner — typically the agent caller or the identity asserting ownership of this credential.
</ParamField>

<ParamField body="provider_id" type="string" required>
  The provider this credential is scoped to. Must match the `provider_id` of any agent you intend to invoke using this auth context. The gateway rejects invocations where the auth context provider does not match the target agent's provider.
</ParamField>

<ParamField body="auth_model" type="object" required>
  Describes how the credential will be injected into downstream A2A calls. See [Auth model options](#auth-model-options) below.
</ParamField>

<ParamField body="token" type="string" required>
  The plaintext credential to encrypt and store. This value is encrypted immediately on write and is never stored or returned in plaintext.
</ParamField>

<ParamField body="expires_at" type="string">
  Optional ISO 8601 timestamp. If set, the gateway rejects invocations that reference this auth context after the expiry time, returning HTTP 403.
</ParamField>

## Auth model options

<Expandable title="Supported auth models">
  | Mode               | JSON                                                       | Description                                                                                                            |
  | ------------------ | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
  | `none`             | `{ "mode": "none" }`                                       | No credential is injected. Use this when the target agent is public.                                                   |
  | `bearer_token`     | `{ "mode": "bearer_token" }`                               | The token is sent as an HTTP `Authorization: Bearer <token>` header on the downstream A2A call.                        |
  | `api_key_header`   | `{ "mode": "api_key_header", "header_name": "X-API-Key" }` | The token is sent in the custom header you specify. Replace `X-API-Key` with your target agent's expected header name. |
  | `capability_token` | `{ "mode": "capability_token" }`                           | A capability-based token scoped to a specific permission or resource. Injected as a bearer token.                      |
</Expandable>

## Use an auth context in invocations

Pass `auth_context_id` in place of `auth_token` when calling `/v1/agents/:agent_id/invoke`. The gateway resolves the stored credential, decrypts it, and injects it into the downstream A2A call automatically.

```bash theme={null}
curl -X POST http://127.0.0.1:8042/v1/agents/stripe-agent/invoke \
  -H 'content-type: application/json' \
  -d '{
    "message": "Create a payment link",
    "auth_context_id": "550e8400-e29b-41d4-a716-446655440000",
    "region": "AU"
  }'
```

<Tip>
  If you supply both `auth_token` and `auth_context_id`, the auth context takes precedence. The gateway resolves the stored credential first and uses it as the effective token.
</Tip>

<Warning>
  The `provider_id` on the auth context must match the provider that owns the agent you are invoking. If they differ, the gateway returns HTTP 403 with `"auth context provider does not match target provider"`.
</Warning>

## List auth contexts

Retrieve all registered auth contexts, optionally filtered by `provider_id` or `subject_did`:

```bash theme={null}
# Filter by provider
curl 'http://127.0.0.1:8042/v1/auth-contexts?provider_id=acme-labs'

# Filter by subject DID
curl 'http://127.0.0.1:8042/v1/auth-contexts?subject_did=did:key:z6MkhaXgBZDvotD1X9gRrYkM5Xq9jYQqK6d8r8bQdE1mV2Xa'
```

The response wraps results in an `items` array. Each item is an `AuthContextRecord` with `token_preview` instead of the plaintext token.

## Node configuration

<Note>
  Auth contexts require `SERVICENET_SECRET_BROKER_KEY` to be set on the node. This must be a base64-encoded 32-byte key used to derive the ChaCha20-Poly1305 encryption key. Without it, any database-backed deployment will refuse to start, and auth context registration will fail.

  Generate a key with:

  ```bash theme={null}
  openssl rand -base64 32
  ```

  Then pass it as an environment variable when starting the node:

  ```bash theme={null}
  SERVICENET_SECRET_BROKER_KEY=<your-base64-key> cargo run -p watt-servicenet-node
  ```
</Note>
