What
BearerTokenAuthMiddleware (`src/adcp/server/auth.py`) authenticates requests, sets the framework-private `current_principal` ContextVar with the validated principal id, and short-circuits on auth failure. What it does not do: construct an `AuthInfo` object and thread it into the request context.
Net effect for bearer adopters reading `RequestContext`:
- `ctx.auth_info` is `None` (or default-stub) — adopters can't read `auth_info.kind`, `auth_info.key_id`, `auth_info.credential`, etc.
- Adopters who want to branch on "is this a bearer or signed-request flow?" have no typed read.
- After #574, `ctx.auth_principal` is correctly populated for bearer flows — but the surrounding typed auth surface (`auth_info.*`) is still unusable.
Why it matters
The triage security-reviewer flagged this as a structural gap during the issue #571 review. PR #574 addressed the immediate `auth_principal is None` papercut; this issue tracks the deeper fix so it doesn't only live in PR-body prose.
For adopters writing transport-agnostic handlers, `ctx.auth_info` is meant to be the typed identity surface. Today bearer adopters either (a) read `ctx.auth_principal` (post-#574) and ignore everything else, or (b) reach into framework-private contextvars to reconstruct what they need.
Possible direction
Have `BearerTokenAuthMiddleware` construct an `AuthInfo` after `validate_token` succeeds, populate `AuthInfo.kind = "bearer"` (or similar), `AuthInfo.principal = principal.caller_identity`, and thread it into the request context alongside the ContextVar. Then `_build_request_context` already does the right thing for both flows, and adopters can read `ctx.auth_info.kind` to discriminate.
Open questions:
- What goes into `AuthInfo.credential` for a bearer flow? Per CLAUDE.md, the typed credential classes (`ApiKeyCredential`, `OAuthCredential`, `HttpSigCredential`) are for upstream propagation. Bearer adopters typically don't propagate the inbound bearer token outward — what's the right shape?
- `AuthInfo.kind` enum: does "bearer" exist today, or do we extend it?
- Backward compatibility: any consumer that assumes `auth_info` is `None` for bearer flows will break. Worth auditing before shipping.
Surfaced by
PR #574 (closes #571). Security-reviewer notes captured in the issue #571 triage comment.
What
BearerTokenAuthMiddleware(`src/adcp/server/auth.py`) authenticates requests, sets the framework-private `current_principal` ContextVar with the validated principal id, and short-circuits on auth failure. What it does not do: construct an `AuthInfo` object and thread it into the request context.Net effect for bearer adopters reading `RequestContext`:
Why it matters
The triage security-reviewer flagged this as a structural gap during the issue #571 review. PR #574 addressed the immediate `auth_principal is None` papercut; this issue tracks the deeper fix so it doesn't only live in PR-body prose.
For adopters writing transport-agnostic handlers, `ctx.auth_info` is meant to be the typed identity surface. Today bearer adopters either (a) read `ctx.auth_principal` (post-#574) and ignore everything else, or (b) reach into framework-private contextvars to reconstruct what they need.
Possible direction
Have `BearerTokenAuthMiddleware` construct an `AuthInfo` after `validate_token` succeeds, populate `AuthInfo.kind = "bearer"` (or similar), `AuthInfo.principal = principal.caller_identity`, and thread it into the request context alongside the ContextVar. Then `_build_request_context` already does the right thing for both flows, and adopters can read `ctx.auth_info.kind` to discriminate.
Open questions:
Surfaced by
PR #574 (closes #571). Security-reviewer notes captured in the issue #571 triage comment.