
`import api_context` carries the typed request metadata that handler
bindings declare as `parameter` types. The compiler decodes route
metadata, the request ID, the idempotency key, and the verified identity
once at the boundary; handlers see a single `RequestContext` value.

## Mental model

The boundary fills `RequestContext` once per request, before the handler
runs. The Vary HTTP runtime owns parsing, session validation, CSRF, and
API token verification, so handler code never re-parses headers or
re-validates tokens. A handler that needs to branch on the caller reads
fields and helper results from the context.

```text
import api_context

def handle_request(request: ListIssuesQuery, ctx: RequestContext) -> Str {
    if ctx.auth_kind == RequestAuthKind.OPTIONAL and ctx.auth_verified {
        return list_for_authenticated(ctx, request)
    }
    return list_for_anonymous(request)
}
```

## Route metadata

Every context carries a `RequestRouteMetadata` describing the route the
boundary matched:

| Field | Meaning |
|---|---|
| `operation_id` | Stable id in OpenAPI and the route manifest. |
| `method` | HTTP verb. |
| `path` | Route path template (e.g. `/api/v1/issues/{id}`). |
| `auth_kind` | `DEFAULT`, `NONE`, `OPTIONAL`, `SESSION`, or `CAPABILITY`. |
| `cache` | `RequestCachePolicy` with public/private cache hints. |
| `field_policy` | Projection name from `fields public ...`, if any. |

`request_route_metadata(...)` and the cache helpers (`request_cache_public`,
`request_cache_private_no_store`, `request_cache_default`) construct these
values in tests and in code that needs to build a context manually.

## Request identity

| Field | When set |
|---|---|
| `request_id: RequestId` | Always; falls back to `"req_unavailable"`. |
| `idempotency_key: Str?` | Present for `idempotent` routes with the header. |
| `remote_address: Str?`, `user_agent: Str?` | When the runtime exposes transport metadata. |

`required_idempotency_key(ctx)` returns `Result[IdempotencyKey, ApiBoundaryError]`
for mutation handlers that must refuse replays missing the header.

## Verified authentication

For `auth optional`, `auth session`, and `auth capability` routes, the
runtime fills the verified identity fields after passing the boundary's
auth gates:

| Field | Meaning |
|---|---|
| `auth_verified: Bool` | Session, JWT, or API token was verified. |
| `csrf_verified: Bool` | The configured CSRF policy was satisfied. |
| `principal_id: Str?` | Stable internal user id. |
| `subject: Str?` | OIDC/JWT `sub`. |
| `issuer: Str?` | OIDC/JWT `iss`. |
| `session_id: Str?` | Session row id (set when using a session cookie). |
| `api_token_id: Str?` | Hashed token id, when the request used a bearer token. |
| `roles: List[Str]` | Roles attached to the verified identity. |
| `capabilities: CapabilitySet` | Capabilities from the JWT/OIDC claim path. |

## Helpers

```text
import api_context

let actor = api_context.authenticated_user(ctx)?
api_context.require_csrf(ctx)?
api_context.required_capability(ctx, "issues.write")?
let viewer = api_context.optional_user(ctx)
let read_only = api_context.has_capability(ctx, "issues.read")
```

| Helper | Return type | Notes |
|---|---|---|
| `optional_user(ctx)` | `RequestUserId?` | `None` for anonymous `auth optional` calls. |
| `authenticated_user(ctx)` | `Result[RequestUserId, ApiBoundaryError]` | `auth_failure` if session missing or unverified. |
| `authenticated_user_id(ctx)` | `Result[Str, ApiBoundaryError]` | Same gate; returns the bare id for log fields. |
| `has_capability(ctx, name)` | `Bool` | Also requires `auth_verified`. |
| `required_capability(ctx, name)` | `Result[None, ApiBoundaryError]` | Fails with `capability_required`. |
| `request_capabilities(ctx)` | `List[Str]` | Full verified capability list for policies or audit. |
| `require_csrf(ctx)` | `Result[None, ApiBoundaryError]` | `csrf_required` when `csrf_verified` is false. |

## See also

| Topic | Where |
|-------|-------|
| Production auth configuration | [Public API security][api-sec] |
| Handler context | [Public JSON APIs][json-api] |
| Route auth clauses | [HTTP services](/docs/http/) |

[api-sec]: /docs/public-api-security/#production-auth-configuration
[json-api]: /docs/public-json-api/#handler-context
