ADR-0005: Authentication Gates as a Capability Skill¶
- Date: 2026-05-06
- Authors: Matteo Rizzo
- Status: Accepted
- Approval State: Approved (Approved by: Matteo Rizzo on 2026-05-06)
- Implementation State: Completed
1. Context and Problem Statement¶
Many shared skills make outbound HTTP calls — AgentBrowserSkill, WeatherSkill, the BrowserWebSearchProvider for RAG, plus the long tail of future enterprise skills (Jira, Salesforce, etc.). Each call can fail with HTTP 401 (missing or expired credential) or 403 (credential lacks the required scope). When that happens, the agent has two unattractive options: bubble the error to the user (verbose, fails the turn), or silently retry without a credential (futile).
The right behavior is neither. The agent should pause the autonomous flow, hand off to a human (or to the calling system) with a structured request for the missing credential, and resume after the credential lands. This pattern is the same regardless of which skill encountered the 401 — the policy is "any skill, on auth failure, asks for help" — so the implementation should not be re-invented per skill.
mirai-agent-core already has a HITL primitive (agent-core ADR-0001) that suspends a workflow until a signal arrives. We need a way to bind the HTTP-auth-failure pattern to that primitive in a way that's reusable across every HTTP-using skill.
2. Decision Drivers (Forces)¶
- Reuse: The credential-handoff payload, the 401/403 detection logic, and the resume contract should be authored once.
- Discoverability: Agents should see "authentication-gates" in the skill catalog and know to route auth-failure events through it.
- Composability: Other HTTP-using skills should not have to know about the gate's internals — they should call it as a tool.
- Type safety: The handoff payload is a structured object (which credential, which scope, which provider), not free-text.
- No runtime coupling between skills: Skills don't import each other; they all import
mirai-agent-coretypes. Any cross-skill plumbing has to flow through the agent (via tool calls) or through agent-core types.
3. Considered Options¶
- Option 1: HTTP middleware injected into every skill. A shared
httpxevent hook that detects 401/403 and pauses. - Option 2: A capability skill (
AuthenticationGatesSkill) with explicit tools (chosen). - Option 3: Per-skill catch blocks that each call a helper.
- Option 4: Bake auth-handoff into
mirai-agent-coreas a first-class primitive.
4. Decision Outcome¶
Chosen option: Option 2 (a capability skill with explicit tools), because it makes the auth-handoff pattern a first-class, agent-visible capability without coupling skills to each other. The pattern lives in the catalog as a peer of every other skill, and any skill that hits a 401 can route through it as a normal tool call.
AuthenticationGatesSkill exposes two tools:
inspect_status_code(status_code: int, response_body: str)— a pure function the agent calls when any HTTP-using skill returns a non-2xx status. Returns a structured classification:{auth_failure: bool, scope_required: str | None, hint: str}.request_credential_handoff(provider: str, scope: str | None, context: dict)— emits aCredentialHandoffPydantic model that the calling system (Chainlit, a custom UI, a Slack bot) receives via the AG-UI stream. The skill itself doesn't suspend; it relies on the downstreamSecureSkillwrapper (withREQUIRES_HITLforrequest_credential_handoff) to do the suspending via agent-core's HITL primitive.
This composes cleanly with SecureSkill:
from mirai_core.core.types import SecureSkill, SecurityLevel
from mirai_shared_skills import AuthenticationGatesSkill
gated = SecureSkill(
AuthenticationGatesSkill(),
policy={
"inspect_status_code": SecurityLevel.SAFE, # pure function, autonomous
"request_credential_handoff": SecurityLevel.REQUIRES_HITL, # pauses turn
},
)
The agent prompt (the skill's instructional payload) tells the LLM: "if you receive an HTTP error from another skill, call inspect_status_code; if it returns auth_failure: true, call request_credential_handoff with the provider and scope". The reasoning happens in the LLM, the gating happens in SecureSkill, the credential delivery happens in the calling system.
4.1. Validation / Compliance¶
- The
CredentialHandoffPydantic model has unit tests asserting required fields. inspect_status_codehas table-driven tests for 401, 403, 5xx, and 2xx.- End-to-end test: an
httpx401 →inspect_status_code→request_credential_handoff→ simulated HITL signal → resume.
5. Pros and Cons of the Options¶
Option 1: HTTP middleware in every skill¶
- Pros: Automatic — skills don't have to opt in.
- Cons: Couples every skill to the gate's implementation. Cross-cuts vendor SDKs that don't use shared
httpxclients. The agent can't reason about "should I retry?" because the middleware fired before the LLM saw the failure.
Option 2 (chosen): Capability skill¶
- Pros:
- One catalog entry; one set of tests; one set of docs.
- The LLM is in the loop: it can decide whether to escalate or to try a different skill first.
- Composable with
SecureSkillfor HITL gating. - Other skills don't know
AuthenticationGatesSkillexists — coupling is via the agent, not the code. - Cons:
- Requires the agent's system prompt to mention the gate (handled by the gate's instructional payload — see ADR-0008).
Option 3: Per-skill catch blocks¶
- Pros: Localized.
- Cons: Re-invented per skill; drift risk; no shared discoverability.
Option 4: Bake into agent-core¶
- Pros: Available everywhere by default.
- Cons: agent-core is provider-agnostic — auth handoff is an enterprise pattern, not a core agent runtime concern. Bloats agent-core's surface.
6. Consequences¶
- Positive Consequences:
- The pattern is auditable: anyone reading
mirai_shared_skills/auth_gates/skill.pysees the entire auth-failure surface. - New HTTP-using skills inherit the pattern by being deployed alongside
AuthenticationGatesSkillin the agent's skill list — no code coupling. - The
CredentialHandoffPydantic model is the contract between the skill and any UI; UIs can render it however they like. - Negative Consequences / Trade-offs:
- Requires the LLM to actively call
inspect_status_codeafter HTTP failures. If the LLM doesn't, the failure surfaces as a normal tool error. The agent's system prompt must reinforce this expectation. - Risks & Mitigations:
- Risk: A new HTTP-using skill ships before its prompt mentions the auth-gates pattern. Mitigation: the "Adding New Skills" guide enumerates this as a checklist item; integration tests for HTTP-using skills include a 401 case that the gate must handle.
7. Implementation Plan & Status Updates¶
- Target Milestone/Release: v0.1.0 (current).
- Implementation Notes:
- 2026-05-06: ADR formalizes the existing skill in
mirai_shared_skills/auth_gates/. No code changes.
8. References / Related Documents¶
mirai_shared_skills/auth_gates/skill.py—AuthenticationGatesSkill,CredentialHandoff.- agent-core ADR-0001: Hybrid Durable HITL — the suspension primitive this composes against.
- agent-core ADR-0012: Declarative Security Policies —
SecureSkilland theREQUIRES_HITLpolicy.