Why We Implemented RFC 8628 for Agent Registration
AID started with a single registration path: the admin holds a JWT, registers the agent directly, the agent gets tokens. Simple. But what happens when the agent boots on a headless server at 3am with no admin present? We needed a second path — and instead of inventing one, we adopted a proven standard.
Contents
The Problem: No Admin at Startup
AID's original registration flow is clean and direct. The admin authenticates, gets a JWT, and passes it to the aid-register script:
This works perfectly when the admin has direct access at the moment of registration. Most local dev and controlled deployment scenarios fit that description.
But a significant class of deployments does not fit that description:
- •Headless servers: an agent image boots in a container orchestration system. No admin is logged in. The agent needs credentials to do its job, and there is no human on-site to hand them over.
- •CI/CD pipelines: a new agent is provisioned as part of an automated deployment. The pipeline has no JWT to pass. Requiring one breaks the automation.
- •Edge devices: an agent running on embedded hardware with no keyboard, no browser, and no way for a human to type credentials at startup.
- •Async onboarding workflows: a new agent is deployed by an engineering team, but approval must come from a separate security team. The agent can't just sit idle waiting for a person to show up with a JWT.
In all of these scenarios, the agent exists and is ready to work, but it cannot receive a JWT from an admin. It needs a way to say "I exist, please approve me" without already having credentials. That is a circular problem if you only have one registration path.
Why RFC 8628
RFC 8628 is the OAuth 2.0 Device Authorization Grant, published in 2019. It was designed for exactly the scenario described above — devices with limited input capabilities that need user authorization on a separate device.
The canonical example from the RFC is a smart TV logging into a streaming service. The TV cannot type a username and password (or at least, no one wants to do that). Instead:
- The TV displays a short code and a URL.
- The user visits the URL on their phone or laptop.
- The user logs in and approves the TV.
- The TV polls until it gets tokens.
The mapping to AI agents is precise:
| RFC 8628 concept | AID equivalent |
|---|---|
| Device (limited input) | Agent (headless server, edge device) |
| User (authorizing on browser) | Admin (approves via authorization URL) |
| User code displayed on TV | User code shown in agent logs (XXXX-XXXX format) |
| Device polls authorization server | Agent polls /agent_registrations/status |
| Device receives access token | Agent receives AID access token + refresh token |
We did not invent a new flow. We did not design a custom protocol. We took a proven IETF standard and applied it to a new domain. That matters: every engineer who knows OAuth already understands the shape of this flow. The security properties are well-understood. The edge cases are documented.
Why not CIBA? Client-Initiated Backchannel Authentication (CIBA) is another option for out-of-band authorization. It is push-based — the server sends a notification to the admin rather than the admin polling. CIBA is more suitable for enterprise environments with existing push notification infrastructure. RFC 8628 is simpler to implement and deploy without that infrastructure, which is why we chose it first. CIBA remains on the roadmap.
Two Paths, One Protocol
Adding RFC 8628 did not replace admin-initiated registration. Both paths exist in AID v0.3.0, and the resulting agent identity is identical regardless of which path was used.
Admin has a JWT. Registers the agent directly. Agent gets tokens immediately with no polling required.
Best for: local dev, controlled deployments, scripted environments where an admin token is available.
Agent requests registration with its public key. Server returns an authorization URL and user code. Agent polls. Admin approves. Agent gets tokens.
Best for: headless servers, CI/CD, edge devices, async approval workflows.
The agent-initiated flow looks like this from the agent's perspective:
Design Decisions We Made
RFC 8628 defines the flow. It does not define every implementation detail. Here are the specific choices we made and why.
Opaque authorization codes, not permanent identifiers
The authorization URL uses a temporary opaque code (/agents/authorize?code=kX9mP2vR), not the agent's permanent unique_id. If someone intercepts or sees the URL, they cannot derive the agent's persistent identity. The authorization code expires and is single-use. The agent's actual identity — its Ed25519 public key and assigned unique_id — is only revealed to the admin after they authenticate at the authorization URL.
User codes exclude ambiguous characters
User codes use the format XXXX-XXXX with uppercase alphanumeric characters, but the character set explicitly excludes 0, O, 1, I, and L. When an admin reads a user code from a log file or a terminal screen and types it into a browser, there is zero ambiguity between the letter O and the digit 0, or between the letter I and the digit 1. This is a small detail that prevents real support tickets.
24-hour TTL on authorization codes
Authorization codes expire after 24 hours. That is long enough to accommodate asynchronous approval workflows — an engineering team deploys an agent on Monday, the security team reviews and approves on Tuesday. It is short enough that an unreviewed registration request does not remain open indefinitely. After expiration, the agent must request a new code. There is no way to extend an existing code.
Human always in control
The agent can request registration. It cannot approve itself. An admin must visit the authorization URL, authenticate, review the agent's public key fingerprint, explicitly assign a role, and click approve. There is no configuration option that allows auto-approval. No agent can grant itself permissions, regardless of what it claims in the registration request. The human approval step is not optional and cannot be bypassed.
Polling interval enforced server-side
The server returns an interval field (default: 5 seconds) and enforces it. If an agent polls faster than the specified interval, the server returns a slow_down error per RFC 8628 section 3.5. This prevents a thundering herd of impatient agents from hammering the auth server while waiting for approval.
The Three-Protocol Stack
AID is the identity layer. It answers one question: who is this agent? It does not orchestrate tools. It does not route messages between agents. Those concerns belong to other protocols.
MCP connections require knowing who the agent is before granting access to tools. A2A message routing requires trusting the sender before processing requests. Both protocols need to verify agent identity. AID provides that identity — and it does so regardless of which registration path the agent used.
An agent registered by an admin with a JWT and an agent registered via RFC 8628 device authorization produce identical identity artifacts: an Ed25519 keypair, a unique_id, an assigned role, and a set of RS256 JWTs. MCP and A2A do not know or care how the agent was registered. They validate the token, check the role, and proceed.
This is the value of building on standards. RFC 8628 is a well-understood registration path. RS256 JWT is a well-understood token format. Any protocol that can validate a JWT can work with AID agents, regardless of registration path.
What's Next
With both registration paths shipped and validated against a working reference implementation (the 23blocks Auth API), AID v0.3.0 covers the complete agent lifecycle:
The next two areas of work are key rotation and federation.
Key rotation: agents need to rotate their Ed25519 keypairs without losing their identity or requiring re-approval. The rotation flow must preserve the agent's unique_id and role assignment while replacing the underlying cryptographic material. The auth server needs to track both the current and previous public key during a transition window.
Federation: an agent registered with one AID-compatible auth server should be able to present its identity to a different server. This requires a trust model between AID providers. We are watching how OIDC federation evolves before committing to an approach. That is a separate post.
Try It Today
Agent-initiated registration via RFC 8628 is available in the AID CLI and the 23blocks Auth API reference implementation. The CLI handles polling automatically — you run one command, it prints the authorization URL and user code, and waits for admin approval.
AID is open source under MIT at github.com/agentmessaging/agent-identity. RFC 8628 specification is at datatracker.ietf.org/doc/html/rfc8628.