<?xml version="1.0" encoding="utf-8"?>
<!-- name="GENERATOR" content="github.com/mmarkdown/mmark Mmark Markdown Processor - mmark.miek.nl" -->
<rfc version="3" ipr="trust200902" docName="draft-patwhite-aauth-00" submissionType="IETF" category="info" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude" indexInclude="true">

<front>
<title abbrev="AAuth">AAuth - Agentic Authorization OAuth 2.1 Extension</title><seriesInfo value="draft-patwhite-aauth-00" stream="IETF" status="informational" name="Internet-Draft"></seriesInfo>
<author initials="P" surname="White" fullname="Pat White"><organization></organization><address><postal><street></street>
</postal><email>pat.white@gmail.com</email>
</address></author><date/>
<area>Authorization</area>
<workgroup></workgroup>

<abstract>
<t>This document defines the <strong>Agent Authorization Grant</strong>, an OAuth 2.1 extension for <strong>confidential agent clients</strong>—software or AI agents with long-lived identities—to request end-user consent and obtain access tokens via HTTP polling, Server-Sent Events (SSE), or WebSocket. It is heavily inspired by the core dance of the OAuth 2.0 Device Authorization Grant (RFC 8628) but is tailored for agents either long lived identities, and introduces scoped, natural-language descriptions and a <tt>reason</tt> parameter provided by the agent.</t>
</abstract>

</front>

<middle>

<section anchor="introduction"><name>Introduction</name>
<t>OAuth 2.1 provides a framework for delegated access via bearer tokens. In modern AI architectures, <strong>agents</strong>—autonomous software processes—act on behalf of users or other agents. This extension defines the <strong>Agent Authorization Grant</strong>, enabling agents with long lived identities to request a delegated token with human-in-the-loop consent, and to receive tokens asynchronously via polling, SSE, or WebSocket, while leveraging natural-language scope descriptions published by resource servers.</t>
</section>

<section anchor="conventions-and-requirements-language"><name>Conventions and Requirements Language</name>
<t>The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” are to be interpreted as described in [RFC2119].</t>
</section>

<section anchor="terminology"><name>Terminology</name>

<ul spacing="compact">
<li><strong>Agent</strong>: A confidential client (software or AI) with a stable, long-lived identity (<tt>client_id</tt>).</li>
<li><strong>Authorization Server (AS)</strong>: Issues <tt>request_code</tt> handles, manages user consent, and issues access tokens.</li>
<li><strong>Resource Server (RS)</strong>: API server that protects resources via OAuth tokens and publishes human-readable scope descriptions at <tt>/.well-known/aauth.json</tt>.</li>
<li><strong>request_code</strong>: Opaque handle returned by the AS to correlate an agent’s request with subsequent token retrieval.</li>
<li><strong>reason</strong>: Human-readable explanation provided by the agent, shown to the user during consent.</li>
<li><strong>scope_descriptions</strong>: Natural-language text for each requested scope, fetched from the RS’s discovery document.</li>
</ul>
</section>

<section anchor="agent-authorization-grant"><name>Agent Authorization Grant</name>
<blockquote><t>This flow is modeled on the OAuth 2.0 Device Authorization Grant (RFC 8628) but is tailored for <strong>confidential agent clients</strong> with long-lived identities, and optimized for performant delivery of tokens to the agent.</t>
</blockquote>
<section anchor="agent-authorization-request"><name>Agent Authorization Request</name>
<t>An agent requests user approval by authenticating and POSTing to <tt>/agent_authorization</tt>:</t>

<sourcecode type="http"><![CDATA[POST /agent_authorization HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <base64(client_id:client_secret)>

grant_type=urn:ietf:params:oauth:grant-type:agent_authorization&
scope=urn:example:resource.read urn:example:resource.write&
reason="<human-readable reason>"
]]></sourcecode>

<ul spacing="compact">
<li><strong>grant_type</strong>: MUST be <tt>urn:ietf:params:oauth:grant-type:agent_authorization</tt>.</li>
<li><strong>scope</strong>: Space-delimited list of scope URIs.</li>
<li><strong>reason</strong>: Concise, human-readable explanation provided by the agent; MUST be echoed verbatim by the AS.</li>
</ul>
<t>Upon receipt, the AS:</t>

<ol spacing="compact">
<li><strong>Validates</strong> client credentials.</li>
<li><strong>Fetches</strong> each scope’s description from the target RS’s <tt>https://{rs}/.well-known/aauth.json#scope_descriptions</tt>.</li>
<li><strong>Returns:</strong></li>
</ol>

<sourcecode type="json"><![CDATA[{
  "request_code": "GhiJkl-QRstuVwxyz",
  "token_endpoint": "https://auth.example.com/token",
  "poll_interval": 5,
  "expires_in": 600,
  "poll_sse_endpoint": "https://auth.example.com/agent_authorization/sse",
  "poll_ws_endpoint": "wss://auth.example.com/agent_authorization/ws"
}
]]></sourcecode>
</section>

<section anchor="user-approval-user-approval"><name>User Approval User Approval</name>
<t>The AS is fully responsible for user interaction:</t>

<ol spacing="compact">
<li><strong>Initiate</strong> the consent review flow with the user. This spec does not specify how this occurs, it could be through an app, a chat client, or some other mechanism.</li>
<li><strong>Display</strong> the <tt>reason</tt> and each <tt>scope_descriptions</tt> entry to ensure the user has all the information necessary to assess the consent request.</li>
<li><strong>Authenticate</strong> the user (including MFA) and, upon consent, bind approval to <tt>request_code</tt>.</li>
</ol>
<blockquote><t><em>Note:</em> The agent does <strong>not</strong> handle redirects or UI rendering—it passively awaits token availability.</t>
</blockquote></section>

<section anchor="token-retrieval"><name>Token Retrieval</name>
<t>After user approval, the agent obtains its access token via one of:</t>

<ol spacing="compact">
<li><strong>HTTP Polling</strong></li>
</ol>

<sourcecode type="http"><![CDATA[   POST /token HTTP/1.1
   Host: auth.example.com
   Content-Type: application/x-www-form-urlencoded
   Authorization: Basic <base64(client_id:client_secret)>

   grant_type=urn:ietf:params:oauth:grant-type:device_code&
   device_code=GhiJkl-QRstuVwxyz
]]></sourcecode>
<t><em>Pending</em>: <tt>{&quot;error&quot;:&quot;authorization_pending&quot;}</tt>
   <em>Success</em>: Standard OAuth 2.x token response.</t>

<ol spacing="compact" start="2">
<li><strong>Server-Sent Events (SSE)</strong></li>
</ol>

<sourcecode type="http"><![CDATA[   GET /agent_authorization/sse?request_code=GhiJkl-QRstuVwxyz HTTP/1.1
   Host: auth.example.com
   Authorization: Bearer <agent_jwt>
   Accept: text/event-stream
]]></sourcecode>
<t>On approval:</t>

<artwork><![CDATA[   event: token_response
   data: {"access_token":"<JWT>","expires_in":900,"issued_token_type":"urn:ietf:params:oauth:token-type:jwt"}
]]></artwork>

<ol spacing="compact" start="3">
<li><strong>WebSocket</strong></li>
</ol>

<sourcecode type="http"><![CDATA[   GET /agent_authorization/ws?request_code=GhiJkl-QRstuVwxyz HTTP/1.1
   Host: auth.example.com
   Upgrade: websocket
   Connection: Upgrade
   Sec-WebSocket-Protocol: aauth.agent-flow
   Authorization: Bearer <agent_jwt>
]]></sourcecode>
<t>On open:</t>

<sourcecode type="json"><![CDATA[   {
     "type": "token_response",
     "access_token": "<JWT>",
     "issued_token_type": "urn:ietf:params:oauth:token-type:jwt",
     "expires_in": 900
   }
]]></sourcecode>
</section>

<section anchor="error-handling-back-off"><name>Error Handling &amp; Back-Off</name>

<ul>
<li><t><strong>HTTP Polling</strong>: MUST honor <tt>error=&quot;slow_down&quot;</tt> with <tt>Retry-After</tt> headers; return standard OAuth error codes such as <tt>authorization_pending</tt>, <tt>access_denied</tt>, or <tt>expired_token</tt>.</t>
</li>
<li><t><strong>Server-Sent Events (SSE)</strong>:</t>

<ul spacing="compact">
<li>On token response:</li>
</ul>

<artwork><![CDATA[event: token_response
data: {"access_token":"<JWT>","expires_in":900,"issued_token_type":"urn:ietf:params:oauth:token-type:jwt"}
]]></artwork>

<ul spacing="compact">
<li>On user rejection:</li>
</ul>

<artwork><![CDATA[event: error
data: {"error":"access_denied","error_description":"The user denied the request."}
]]></artwork>

<ul spacing="compact">
<li>On request expiration:</li>
</ul>

<artwork><![CDATA[event: error
data: {"error":"expired_token","error_description":"The request_code has expired."}
]]></artwork>
</li>
<li><t><strong>WebSocket</strong>:</t>

<ul spacing="compact">
<li>On token response:</li>
</ul>

<sourcecode type="json"><![CDATA[{"type":"token_response","access_token":"<JWT>","issued_token_type":"urn:ietf:params:oauth:token-type:jwt","expires_in":900}
]]></sourcecode>

<ul spacing="compact">
<li>On user rejection or expiration:</li>
</ul>

<sourcecode type="json"><![CDATA[{"type":"error","error":"access_denied","error_description":"The user denied the request."}
]]></sourcecode>

<sourcecode type="json"><![CDATA[{"type":"error","error":"expired_token","error_description":"The request_code has expired."}
]]></sourcecode>
</li>
<li><t><strong>Security</strong>: All endpoints SHOULD enforce TLS and require client authentication.</t>
</li>
</ul>
</section>
</section>

<section anchor="security-considerations-security-considerations"><name>Security Considerations. Security Considerations</name>

<ul spacing="compact">
<li>Agents MUST protect their long-lived credentials.</li>
<li>Short-lived <tt>request_code</tt> and tokens limit replay risk.</li>
<li>RS scope descriptions should not expose sensitive system details.</li>
<li>Implement rate-limiting on polling and push channels to prevent abuse.</li>
</ul>
</section>

<section anchor="iana-considerations"><name>IANA Considerations</name>
<t>This document registers the following new OAuth grant type:</t>

<artwork><![CDATA[urn:ietf:params:oauth:grant-type:agent_authorization
]]></artwork>
</section>

<section anchor="references"><name>References</name>

<section anchor="normative-references"><name>Normative References</name>

<ul spacing="compact">
<li>[RFC2119] Bradner, &quot;Key words for use in RFCs to Indicate Requirement Levels&quot;, BCP 14, RFC 2119.</li>
<li>[RFC8628] Wahl, &quot;OAuth 2.0 Device Authorization Grant&quot;, RFC 8628.</li>
<li>[RFC8693] Jones &amp; Campbell, &quot;OAuth 2.0 Token Exchange&quot;, RFC 8693.</li>
</ul>
</section>
</section>

</middle>

</rfc>
