Web Authorization Protocol D. Hardt Internet-Draft Hellō Intended status: Standards Track S. Goto Expires: 5 January 2027 Google 4 July 2026 OAuth Protected Authorization draft-hardt-oauth-protected-authorization-00 Abstract This document defines browser support for protecting OAuth 2.0 authorization requests and authorization responses during redirect- based authorization flows. A single Structured Field header field, OAuth-Authorization, is set by the OAuth client in the redirect response that sends the browser to the authorization server, and by the authorization server in the redirect response that returns the browser to the OAuth client. In both cases the browser augments the header with the attested origin of the redirecting party and delivers it to the redirect destination. The mechanism provides security for the authorization request: the authorization server receives a browser-attested, tamper-evident statement of which origin initiated the request. The mechanism provides security and privacy for the authorization response: the authorization code is delivered in the browser-protected header instead of the redirect URI, and never appears in a URL, eliminating its exposure through browser history, server logs, Referer headers, analytics systems, and URL sharing. The header is generated, validated, and delivered by the browser, and is inaccessible to scripts, service workers, and browser extensions. Existing OAuth deployments continue to function unchanged; the protections activate only when the OAuth client, browser, and authorization server all support them. Discussion Venues _Note: This section is to be removed before publishing as an RFC._ Source for this draft and an issue tracker can be found at https://github.com/dickhardt/oauth-protected-authorization (https://github.com/dickhardt/oauth-protected-authorization). Status of This Memo This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79. Hardt & Goto Expires 5 January 2027 [Page 1] Internet-Draft Protected Authorization July 2026 Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet- Drafts is at https://datatracker.ietf.org/drafts/current/. Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress." This Internet-Draft will expire on 5 January 2027. Copyright Notice Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved. This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/ license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License. Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 1.1. Goals . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.2. Non-Goals . . . . . . . . . . . . . . . . . . . . . . . . 5 1.3. Browser Enforcement Precondition . . . . . . . . . . . . 6 2. Conventions and Terminology . . . . . . . . . . . . . . . . . 6 3. Protocol Overview . . . . . . . . . . . . . . . . . . . . . . 7 4. The OAuth-Authorization Header Field . . . . . . . . . . . . 7 4.1. query . . . . . . . . . . . . . . . . . . . . . . . . . . 8 4.2. origin . . . . . . . . . . . . . . . . . . . . . . . . . 8 4.3. path . . . . . . . . . . . . . . . . . . . . . . . . . . 8 5. Authorization Request . . . . . . . . . . . . . . . . . . . . 8 5.1. Client Behavior . . . . . . . . . . . . . . . . . . . . . 9 5.2. Authorization Server Behavior . . . . . . . . . . . . . . 9 6. Authorization Response . . . . . . . . . . . . . . . . . . . 10 6.1. Authorization Server Behavior . . . . . . . . . . . . . . 10 6.2. Client Behavior . . . . . . . . . . . . . . . . . . . . . 11 7. Path Validation . . . . . . . . . . . . . . . . . . . . . . . 12 8. Browser Processing Model . . . . . . . . . . . . . . . . . . 12 9. Deployment Considerations . . . . . . . . . . . . . . . . . . 14 9.1. Incremental Adoption . . . . . . . . . . . . . . . . . . 14 Hardt & Goto Expires 5 January 2027 [Page 2] Internet-Draft Protected Authorization July 2026 9.2. Dual Transmission of Request Parameters . . . . . . . . . 14 9.3. Single-Page Applications . . . . . . . . . . . . . . . . 14 9.4. Header Sizes . . . . . . . . . . . . . . . . . . . . . . 15 10. Security Considerations . . . . . . . . . . . . . . . . . . . 15 10.1. Dependence on Browser Enforcement . . . . . . . . . . . 15 10.2. Downgrade . . . . . . . . . . . . . . . . . . . . . . . 15 10.3. Cross-Context Delivery . . . . . . . . . . . . . . . . . 15 10.4. What Is and Is Not Protected . . . . . . . . . . . . . . 16 10.5. Server-Side Handling . . . . . . . . . . . . . . . . . . 16 10.6. Relationship to Existing Mechanisms . . . . . . . . . . 17 11. Privacy Considerations . . . . . . . . . . . . . . . . . . . 17 11.1. Authorization Request Privacy . . . . . . . . . . . . . 17 11.2. Authorization Response Privacy . . . . . . . . . . . . . 17 11.3. No New Cross-Site Information Flow . . . . . . . . . . . 17 11.4. Origin and Path Disclosure . . . . . . . . . . . . . . . 18 11.5. User Transparency . . . . . . . . . . . . . . . . . . . 18 12. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 18 12.1. OAuth-Authorization Header Field . . . . . . . . . . . . 18 13. Implementation Status . . . . . . . . . . . . . . . . . . . . 18 14. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 19 15. References . . . . . . . . . . . . . . . . . . . . . . . . . 19 15.1. Normative References . . . . . . . . . . . . . . . . . . 19 15.2. Informative References . . . . . . . . . . . . . . . . . 19 Appendix A. Example: Authorization Code Flow Before and After . 20 A.1. Without This Mechanism (Current OAuth) . . . . . . . . . 20 A.2. With This Mechanism . . . . . . . . . . . . . . . . . . . 21 Appendix B. Design Rationale . . . . . . . . . . . . . . . . . . 22 B.1. Why OAuth-Specific Rather Than Generic Redirect Headers . . . . . . . . . . . . . . . . . . . . . . . . 22 B.2. Why a Single Header Field . . . . . . . . . . . . . . . . 22 B.3. Why Not Cryptographic Protection of Parameters . . . . . 22 B.4. Why Not Move to the Back Channel . . . . . . . . . . . . 23 B.5. Why the Authorization Request Parameters Stay in the URL . . . . . . . . . . . . . . . . . . . . . . . . . . 23 B.6. Why a Structured Field Dictionary Wrapping a Query String . . . . . . . . . . . . . . . . . . . . . . . . . 23 B.7. Why Redirect Responses Only (Why Not form_post) . . . . . 23 B.8. Why the AS Rejects on Query Mismatch, Rather Than the Browser Dropping the Header . . . . . . . . . . . . . . 24 B.9. Why Not a Sec-Prefixed Name . . . . . . . . . . . . . . . 24 B.10. Why Not a response_mode Value . . . . . . . . . . . . . . 24 B.11. Why the Authorization Response Is Not Readable by JavaScript . . . . . . . . . . . . . . . . . . . . . . . 24 B.12. Why Native Application Flows Are Out of Scope . . . . . . 24 B.13. Why Browser-Attested Origin When iss Exists . . . . . . . 25 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 25 Hardt & Goto Expires 5 January 2027 [Page 3] Internet-Draft Protected Authorization July 2026 1. Introduction OAuth 2.0 [RFC6749] redirect-based authorization flows carry protocol parameters in URLs. The critical parameter is the *authorization code*: it is a credential, exchangeable for tokens. When the authorization server redirects back to the OAuth client with ?code=...&state=... in the redirect URI, that credential is written into browser history, web server access logs, proxy and load balancer logs, and analytics systems; it leaks through Referer headers to third-party resources loaded by the callback page; and it can be disclosed through URL sharing, screenshots, and copy/paste. The OAuth 2.0 Security Best Current Practice [RFC9700] documents these leakage vectors and prescribes mitigations that limit the damage of a leaked code (PKCE [RFC7636], one-time use, short lifetimes), but the code is still exposed. A second, related weakness is that the authorization server has no reliable way to know which web origin sent the user. The Referer header may be trimmed, stripped, or rewritten, and everything else in the authorization request is claimed by the requester rather than attested by anyone. This document defines browser behavior and a single Structured Field [RFC9651] header field, OAuth-Authorization, used on both legs of the flow: * For the *authorization request*, the OAuth client sets the header in the redirect response that sends the browser to the authorization server. The browser delivers it with the navigation, adding a browser-attested origin (and optionally a browser-validated path) identifying where the navigation actually came from. Its presence also signals to the authorization server that the browser and OAuth client support protected authorization responses. * For the *authorization response*, the authorization server sets the header in the redirect response that returns the browser to the OAuth client, placing the authorization response parameters in the header instead of the redirect URI. The browser delivers it, exactly once, to the redirect URI, adding a browser-attested origin identifying the authorization server. The browser performs the same processing in both cases (Section 8); which OAuth message the header carries is determined by the endpoint that receives it. The mechanism provides *security for the authorization request, and security and privacy for the authorization response*: Hardt & Goto Expires 5 January 2027 [Page 4] Internet-Draft Protected Authorization July 2026 * The authorization request parameters remain in the request URI, unchanged, so existing authorization servers continue to work. The header adds origin attestation, tamper evidence, and a capability signal. This is security without privacy: the OAuth client cannot know whether a given user's browser supports this mechanism, so the parameters never leave the URL. * The authorization response parameters, above all the authorization code, exist only in the protected header and never appear in any URL. The authorization server sends them this way only after the header's arrival with the authorization request has proven that the browser and OAuth client support it. Existing deployments continue to function unchanged, and adoption is deliberately inexpensive: for most clients, support arrives as an update to the OAuth library they already use, with no new endpoints, no keys, and no change to how authorization parameters are constructed or parsed (Section 9). 1.1. Goals 1. Provide an explicit browser signal that a navigation is an OAuth authorization request. 2. Provide a protected, browser-mediated delivery mechanism for OAuth authorization responses. 3. Preserve complete compatibility with existing OAuth deployments and parameter processing. This mechanism complements PKCE [RFC7636], PAR [RFC9126], iss identification [RFC9207], and JARM [JARM]. It does not replace any of them. 1.2. Non-Goals * This is not a back-channel protocol. Protocols that move the authorization exchange out of the front channel entirely (such as PAR [RFC9126] for the request, or the AAuth protocol [I-D.hardt-oauth-aauth-protocol] for the full authorization exchange) provide stronger confidentiality with different deployment costs. See Appendix B.4. * This is not a generic HTTP redirect mechanism. It is intentionally specific to OAuth authorization flows. See Appendix B.1. * This mechanism does not protect against a compromised or non- conforming browser, a malicious authorization server, or a malicious OAuth client. * Native application flows [RFC8252] are out of scope. See Appendix B.12. Hardt & Goto Expires 5 January 2027 [Page 5] Internet-Draft Protected Authorization July 2026 1.3. Browser Enforcement Precondition The security properties defined in this document are provided by browser behavior, not by the header name or value. The header MUST be inaccessible to page JavaScript, to fetch() and XMLHttpRequest, to service workers, and to browser extensions (Section 8). *A browser that cannot enforce all of the protections in Section 8 (for example, because its extension APIs expose all request headers) MUST NOT implement this mechanism.* In that case the flow degrades safely to standard OAuth: no header is generated, and the authorization server responds with parameters in the redirect URI as it does today. 2. Conventions and Terminology The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. This document uses the terms "authorization request", "authorization response", "authorization server" (AS), "client", and "redirect URI" as defined by OAuth 2.0 [RFC6749], and "origin" as defined by [RFC6454]. *Client*: in this document, "client" always means the OAuth client as defined by [RFC6749], the application requesting authorization. The HTTP client performing navigations is always referred to as "the browser". *Browser*: a user agent performing top-level navigations on behalf of a user. *Redirecting server / redirecting URL*: the server, and the URL, from which a redirect response was received. The browser attests the origin (and optionally a path prefix) of the redirecting URL, which is well defined even when the redirect is the first response in a navigation (e.g., a login URL that immediately returns a redirect). *Authorization request and response* always refer to the OAuth messages [RFC6749], never to HTTP requests and responses. At each redirect hop, the OAuth-Authorization header field appears in two HTTP messages: the redirecting server sets it in the redirect _response_, and the browser delivers it as a header field of the subsequent HTTP _request_ to the redirect destination. This document always states which HTTP message is meant. Hardt & Goto Expires 5 January 2027 [Page 6] Internet-Draft Protected Authorization July 2026 3. Protocol Overview The flow is standard OAuth; the additions introduced by this specification are marked *(new)*: 1. The client constructs a normal authorization request URI and returns a redirect response (302 or 303) to the browser. *(new)* The redirect response also carries an OAuth-Authorization header whose query member is the same serialized query string that appears in the authorization request URI. 2. *(new)* The browser recognizes the header, adds the browser- attested origin member (and path if claimed and valid), and delivers it as a header field of the HTTP request to the authorization server. The request URI is unchanged. 3. The AS processes the authorization request from the URI as it does today. *(new)* If the OAuth-Authorization header is present, the AS verifies the query member matches the request URI query, and now knows (a) the browser-attested origin of the client and (b) that the browser and client support protected authorization responses. 4. The AS authenticates the user and obtains authorization, using any number of internal redirects or pages; the header plays no role in these intermediate steps. 5. The AS returns a redirect response to the registered redirect URI. *(new)* Instead of placing the authorization response parameters in the redirect URI query, the AS places them in the query member of an OAuth-Authorization header. The redirect URI carries no response parameters. 6. *(new)* The browser adds the browser-attested origin of the AS and delivers the header, exactly once, as a header field of the HTTP request to the redirect URI. 7. *(new)* The client reads the authorization response parameters from the header's query member, using the same parsing it uses for URL query strings today, and verifies the browser-attested origin is the expected AS. If any party does not support the mechanism, the header is simply absent and the flow proceeds as standard OAuth. 4. The OAuth-Authorization Header Field OAuth-Authorization is a Structured Field Dictionary [RFC9651] with three members, all Strings: query, origin, and path. The redirecting server sets the header in a redirect response; the browser validates and augments it, and delivers it as a header field of the subsequent HTTP request to the redirect destination (Section 8). Hardt & Goto Expires 5 January 2027 [Page 7] Internet-Draft Protected Authorization July 2026 A recipient determines which OAuth message the header carries from its own role: an authorization endpoint receives authorization requests; a redirect URI receives authorization responses. Delivery to the wrong context fails closed (Section 10.3). 4.1. query Set by the redirecting server; relayed by the browser without inspection or modification. The query member carries the OAuth parameters, using the same serialization as a URL query string, so recipients parse it with the code they already use for URLs today: * In an *authorization request* (Section 5), the client sets query to the query component of the authorization request URI, byte- identical to it. * In an *authorization response* (Section 6), the AS sets query to the serialized authorization response parameters that would otherwise appear in the redirect URI query. 4.2. origin Set only by the browser: the ASCII serialization [RFC6454] of the redirecting URL's origin. Servers MUST NOT set origin; the browser removes any server-set value before setting its own. A receiving party can therefore rely on origin unconditionally: it cannot be set, suppressed, or modified by web content or by any server. 4.3. path Claimed by the redirecting server; validated, and set or removed, by the browser. The redirecting server MAY include a path member as a claim about the path prefix of the redirecting URL; the value MUST begin and end with /. The browser delivers the member only if the redirecting URL's path begins with the claimed value, and removes it otherwise (Section 7). A receiving party can therefore rely on a delivered path unconditionally: the browser only delivers claims it has verified. 5. Authorization Request Hardt & Goto Expires 5 January 2027 [Page 8] Internet-Draft Protected Authorization July 2026 5.1. Client Behavior The client constructs the authorization request URI exactly as it does today; all authorization request parameters remain in the URI query for compatibility. In the redirect response (302 or 303) that sends the browser to the authorization server, the client additionally sets the header: HTTP/1.1 303 See Other Location: https://as.example/authorize?client_id=abc&response_type=code &redirect_uri=https%3A%2F%2Fapp.example%2Fportal%2Fcb&state=123 &code_challenge=E9Melhoa...&code_challenge_method=S256 OAuth-Authorization: query="client_id=abc&response_type=code &redirect_uri=https%3A%2F%2Fapp.example%2Fportal%2Fcb&state=123 &code_challenge=E9Melhoa...&code_challenge_method=S256", path="/portal/" (Line breaks in the examples are for readability only.) The query member MUST be byte-identical to the query component of the Location URI. The client MAY include a path claim (Section 7). The browser processes the header per Section 8 and delivers it with the navigation: GET /authorize?client_id=abc&response_type=code&redirect_uri=... &state=123&code_challenge=...&code_challenge_method=S256 HTTP/1.1 Host: as.example OAuth-Authorization: query="client_id=abc&response_type=code &redirect_uri=...&state=123&code_challenge=... &code_challenge_method=S256", origin="https://app.example", path="/portal/" Note that the browser does NOT compare the query member with the Location URI query. Dropping the header on a mismatch would allow an attacker able to tamper with the URI to silently downgrade the flow to unprotected behavior; instead the header is always delivered and the authorization server detects tampering (Section 5.2). 5.2. Authorization Server Behavior The AS processes the authorization request from the request URI query exactly as it does today. Deployments that do not implement this specification require no changes. An AS that implements this specification and receives an OAuth- Authorization header with an authorization request: Hardt & Goto Expires 5 January 2027 [Page 9] Internet-Draft Protected Authorization July 2026 1. MUST verify that the query member is byte-identical to the query component of the request URI, and reject the authorization request with an error if they differ. A mismatch indicates tampering or a defective client and MUST NOT be silently ignored. 2. SHOULD verify that the origin member is consistent with the client's registered redirect_uri values (e.g., that the registered redirect URIs for the presented client_id belong to the attested origin), and reject the request otherwise. Unlike the Referer header, origin is browser-attested: it cannot be set, suppressed, or modified by web content. 3. MAY use a validated path member to discriminate between multiple clients registered on the same origin under different path prefixes. 4. MUST return the authorization response using the OAuth- Authorization header as defined in Section 6. The header's arrival with the authorization request is the capability signal: it can only have arrived via a supporting browser from a supporting client. On this leg the header provides origin attestation and tamper evidence; it does not provide confidentiality. The authorization request parameters remain visible in the URL, as they are today. 6. Authorization Response 6.1. Authorization Server Behavior An AS whose authorization request arrived bearing the OAuth- Authorization header MUST deliver the authorization response in the header, and MUST NOT include response parameters in the redirect URI: HTTP/1.1 303 See Other Location: https://app.example/portal/cb OAuth-Authorization: query="code=SplxlOBeZQQYbYS6WxSbIA &state=123&iss=https%3A%2F%2Fas.example" The AS delivers error responses through the same header, for consistency: once support is established, every authorization response, success or error, arrives through the same channel, giving the client a single processing path. (Keeping error details out of URLs and logs is a secondary benefit.) HTTP/1.1 303 See Other Location: https://app.example/portal/cb OAuth-Authorization: query="error=access_denied&state=123 &iss=https%3A%2F%2Fas.example" The AS MAY include a path claim (Section 7). Hardt & Goto Expires 5 January 2027 [Page 10] Internet-Draft Protected Authorization July 2026 An AS MUST NOT include an OAuth-Authorization header in its response redirect unless the corresponding authorization request arrived bearing the header: without that signal there is no evidence the browser will deliver the header or that the client will read it. The browser processes the header per Section 8 and delivers it with the navigation, exactly once, to the redirect URI only: GET /portal/cb HTTP/1.1 Host: app.example OAuth-Authorization: query="code=SplxlOBeZQQYbYS6WxSbIA &state=123&iss=https%3A%2F%2Fas.example", origin="https://as.example" 6.2. Client Behavior A client that receives an OAuth-Authorization header at its redirect URI: 1. MUST obtain the authorization response parameters by parsing the query member as a URL query string, and MUST ignore any query parameters present in the request URI. 2. MUST verify that the origin member matches the origin of the authorization server it sent the corresponding authorization request to, and reject the response otherwise. This browser- attested check complements the iss parameter [RFC9207] and is stronger: iss is asserted by whichever server sent the response. 3. Processes the parameters (including state verification and the token request with PKCE) exactly as it does for URL-delivered responses today. A client that receives authorization response parameters in the URL (because the user's browser, or the AS, does not support this mechanism) processes them as it does today. A client can never require the header: URL delivery may simply mean an unsupporting browser (see Section 10.2). Because the header is delivered only once, clients MUST complete processing (or persist what they need) on first delivery; a reload of the redirect URI carries neither the header nor any parameters. Note that this also means an authorization code can no longer be replayed out of browser history: there is nothing in the URL or the history entry to replay. Hardt & Goto Expires 5 January 2027 [Page 11] Internet-Draft Protected Authorization July 2026 7. Path Validation Multiple clients may share an origin, separated by path prefix (e.g., https://host.example/app1/ and https://host.example/app2/). The origin alone cannot discriminate between them. The path member allows the receiving party to know which path prefix within the origin the redirect actually came from. The path member is a claim made by the redirecting server and validated by the browser: 1. The redirecting server includes path in its header with a value that MUST begin and end with / (e.g., path="/app1/"). 2. The browser checks whether the path component of the redirecting URL begins with the claimed value. 3. If it does, the browser includes the path member in the delivered header. 4. If it does not, the browser removes the path member and delivers the header without it. The trailing / requirement ensures prefix matching occurs on path- segment boundaries (/app1/ does not match /app1evil/x). The redirecting server cannot lie about its path: the browser only delivers a path claim it has verified. A receiving party that requires path discrimination treats an absent path member accordingly (e.g., an AS that registered a client with a path-scoped redirect URI SHOULD reject a request whose validated path is absent or inconsistent with the registration). 8. Browser Processing Model This is fundamentally a browser behavior specification: the security properties of the OAuth-Authorization header field are created entirely by the browser processing rules in this section. The browser acts as a trusted protocol participant, a role it already plays for every OAuth flow today by enforcing TLS, cookie isolation, redirect handling, and origin boundaries. This section makes that role explicit. *Recognition.* The browser processes the header when, and only when, it appears in a 302 or 303 response to a top-level navigation. No URL heuristics are used. The header is ignored (and stripped) in all other contexts: subresource requests, fetch/XHR responses, embedded frames, and non-redirect responses. Hardt & Goto Expires 5 January 2027 [Page 12] Internet-Draft Protected Authorization July 2026 *Identical processing on both legs.* The browser applies the same rules whether the redirecting server is a client sending an authorization request or an AS returning an authorization response. The browser does not parse or interpret the query member; in particular, it does not compare it with the Location URI (Appendix B.8). *Single hop, stateless.* The header is relayed exactly one hop: from the redirect response in which the redirecting server set it, to the HTTP request for the Location URI, and no further. The browser keeps no state about an OAuth flow across hops; if an intermediate destination redirects again, that response must itself set the header for the browser to relay it. Any transient state used to relay the header is destroyed after delivery. *Browser-generated members.* The browser removes any origin member set by a server and sets it itself; the browser validates any server- claimed path member and delivers it only if valid. Receiving parties can therefore rely on origin and path unconditionally. *Protection requirements.* The browser MUST ensure that: * Web content cannot set this header field on any request: it MUST be treated as a forbidden header name in the sense of Fetch [FETCH]. * JavaScript cannot read this header field from any request or response, including via fetch(), XMLHttpRequest, performance and reporting APIs, or any other API. * Service workers cannot observe or modify this header field, on either the redirect responses that carry it or the requests that deliver it, including via navigation preload. * Browser extensions cannot read, modify, inject, suppress, or replay this header field, regardless of the permissions the extension holds. * The header field is processed only for top-level navigations, delivered only to the Location destination of the redirect that carried it, delivered at most once, and never persisted. These protections are intentionally stronger than those of Sec-- prefixed header fields, which today remain readable by extensions and service workers. A browser that cannot enforce every requirement in this list MUST NOT implement this mechanism (see Section 10.1). Hardt & Goto Expires 5 January 2027 [Page 13] Internet-Draft Protected Authorization July 2026 *Standards coordination.* The processing model in this section (the forbidden header name, service worker opacity, and navigation integration) requires a normative change to the WHATWG Fetch standard [FETCH]. A Fetch pull request defining this processing model is a deliverable of this work; this document defines the OAuth protocol semantics that rely on it. 9. Deployment Considerations 9.1. Incremental Adoption No coordination between parties is required. Each party adds support independently, in any order: * *Clients* add the OAuth-Authorization header to the redirect responses they already send, keeping all parameters in the URL, and read authorization responses from the header when present, falling back to URL parameters when it is not. This is a library update. * *Browsers* implement the processing model in Section 8. * *Authorization servers* verify and use the header when it arrives with an authorization request, and switch the authorization response to the header, whose arrival proves the whole path supports it. Until all three parties support the mechanism, every flow proceeds exactly as standard OAuth. There is no flag day and no breakage for any non-supporting party. 9.2. Dual Transmission of Request Parameters Clients send the authorization request parameters in both the URL and the header on every request, indefinitely: a client cannot know whether any given user's browser supports this mechanism, and this specification deliberately defines no discovery mechanism. This is why the authorization request gains security but not privacy (Section 11.1), and why the authorization response, which is sent in the header only when support is proven, gains both. 9.3. Single-Page Applications The authorization response is delivered to the server at the redirect URI; it is, by design, not readable by JavaScript (Appendix B.11). SPAs that process authorization codes in front-end code continue to work exactly as they do today (they will not receive the header because they do not send it from a server-issued redirect response). SPAs that adopt a backend-for-frontend gain the protections of this specification. Hardt & Goto Expires 5 January 2027 [Page 14] Internet-Draft Protected Authorization July 2026 9.4. Header Sizes Authorization code responses are small (typically well under 1 KB). Deployments that layer large response payloads into the query member, such as JARM [JARM] response JWTs, should be aware of intermediary header size limits, commonly 8 to 16 KB. 10. Security Considerations 10.1. Dependence on Browser Enforcement Everything in this specification depends on the browser protections in Section 8. If extensions, service workers, or page script can observe or forge the header, the mechanism provides no security benefit over URL parameters and MUST NOT be implemented. This is the central deployment requirement of this specification and is intentionally stated bluntly: the security properties are defined by browser behavior, and exist only where the browser provides them. This specification assumes an honest, conforming browser. It cannot protect against a compromised or malicious browser, browser bugs that fail to enforce the processing model, or debugging tools operating with the user's authority. Servers SHOULD treat anomalous origin values as potential indicators of a non-conforming implementation. 10.2. Downgrade An attacker who prevents the mechanism from operating (for example, by interfering with a non-protected portion of the flow) obtains at most today's OAuth: parameters in URLs, with all [RFC9700] mitigations (PKCE, state, one-time short-lived codes, exact redirect URI matching) still in force. A client cannot distinguish "the user's browser does not support this" from "support was stripped", and therefore can never hard-require the header; this residual downgrade is accepted and is exactly the status quo. The browser is stateless across the flow (Section 8), so it cannot mark a callback as "should have been protected"; a future extension could revisit this if browsers ever maintain per-flow state. Query tampering, by contrast, is not a downgrade vector: the browser always delivers the header with the authorization request, and the AS rejects on mismatch (Section 5.2). 10.3. Cross-Context Delivery A single header field name means a header could in principle reach a party expecting the other OAuth message. Both directions fail closed: Hardt & Goto Expires 5 January 2027 [Page 15] Internet-Draft Protected Authorization July 2026 * An authorization endpoint that receives a header whose query member is not byte-identical to the request URI query rejects the request (Section 5.2); a header carrying authorization response parameters never matches an authorization request URI. * A client that receives a header at its redirect URI verifies the browser-attested origin is its expected AS (Section 6). A header minted by any other party, including an attacker's site issuing a redirect to the client's redirect URI, carries the attacker's origin and is rejected. Web content and extensions cannot forge the header at all (Section 8). 10.4. What Is and Is Not Protected Protected: the authorization code, and the other authorization response parameters, never appear in URLs, eliminating exposure via browser history, web server and proxy logs, Referer headers, analytics and crash reporting, URL sharing, screenshots, and copy/ paste; and both parties receive a browser-attested origin for the other side of each redirect. Not protected: parameters in transit (TLS remains REQUIRED for every HTTP request and response carrying the header); the authorization request parameters, which remain in the URL by design; the parties themselves (a malicious AS or client is out of scope); and injection of an attacker's _legitimate_ authorization response at a client (authorization code injection), for which PKCE remains REQUIRED. 10.5. Server-Side Handling When carrying an authorization response, the query member contains the authorization code and MUST be treated with the confidentiality of an Authorization header: excluded or redacted in access logs, application logs, and telemetry. Because the same field name is used on both legs, the simple deployment rule is to treat OAuth- Authorization as sensitive everywhere. Moving parameters out of URLs removes them from _default_ URL logging; header logging is a configuration choice that servers MUST make deliberately. Receiving parties MUST parse the header as a Structured Field [RFC9651] and reject malformed values. An HTTP request or response carrying more than one instance of the header field is invalid; recipients MUST ignore the header field entirely in that case, and browsers MUST NOT relay duplicated instances. Hardt & Goto Expires 5 January 2027 [Page 16] Internet-Draft Protected Authorization July 2026 10.6. Relationship to Existing Mechanisms This mechanism supplements and does not relax any existing requirement: redirect URI registration and exact matching, state (or equivalent CSRF protection), PKCE [RFC7636], and the mitigations of [RFC9700] all continue to apply. The origin member provides a browser-attested complement to iss [RFC9207] for mix-up defense, and browser-attested client origin strengthens the AS's ability to detect requests initiated from unexpected origins, supplementing rather than replacing redirect URI validation. 11. Privacy Considerations 11.1. Authorization Request Privacy Authorization request parameters remain in the URL indefinitely (Section 9) and remain exposed exactly as they are today. This is explicitly a non-goal: authorization request parameters (client_id, redirect_uri, state, code_challenge) are not secrets. Deployments that need request confidentiality should use PAR [RFC9126]. 11.2. Authorization Response Privacy Authorization response parameters never appear in URLs, browser history, Referer headers, or default logs, and the header is invisible to page JavaScript, embedded third parties, service workers, and extensions. The header is delivered once and never persisted. 11.3. No New Cross-Site Information Flow This mechanism activates only on OAuth authorization navigations: flows that by design already convey the client's identity to the AS (client_id, redirect_uri) in the URL. The browser-attested origin gives the AS nothing it does not already receive; it makes an existing claim reliable rather than adding a new one. On the return leg, the AS origin delivered to the client identifies a party the client chose and already knows. The header is invisible to all third parties, so it cannot be used as a side channel between origins. What remains true, and is unchanged by this specification, is that front-channel OAuth inherently reveals to the AS that a user is authorizing a given client; only back-channel protocols such as [I-D.hardt-oauth-aauth-protocol] change that. Hardt & Goto Expires 5 January 2027 [Page 17] Internet-Draft Protected Authorization July 2026 11.4. Origin and Path Disclosure The origin member is a reliable equivalent of a scheme-plus-host Referer, and a validated path member discloses a path prefix, but only to the party the redirect was addressed to, which in OAuth already knows the counterparty. Unlike Referer, these members cannot be stripped by the user without the flow degrading to URL parameters (which disclose strictly more). This trade-off, favoring reliable counterparty verification over origin hiding, is appropriate only where mutual knowledge of the parties is expected, as it is in OAuth; it is one of the reasons this mechanism is OAuth-specific rather than generic (Appendix B.1). 11.5. User Transparency Users cannot inspect or modify the header in-page (unlike URL parameters). Browsers SHOULD surface it in developer tools, read- only, while maintaining all protections in Section 8. 12. IANA Considerations This document registers one header field in the "Hypertext Transfer Protocol (HTTP) Field Name Registry" defined in [RFC9110]. 12.1. OAuth-Authorization Header Field Field name: OAuth-Authorization Status: permanent Structured Type: Dictionary Reference: [this document] 13. Implementation Status *Note to RFC Editor: Please remove this section before publication.* Specification status: Exploratory draft. This document replaces draft-hardt-httpbis-redirect-headers, refocused on the OAuth use case following IETF 125 feedback. Browser support: not yet implemented; requires the Fetch processing model in Section 8. Server and client support: reference implementations needed; adoption is a library update for both. Hardt & Goto Expires 5 January 2027 [Page 18] Internet-Draft Protected Authorization July 2026 14. Acknowledgments The authors would like to thank early reviewers for their valuable feedback and insights that helped shape this proposal: Jonas Primbs, Warren Parad. This document was refocused on the OAuth use case in response to feedback from the HTTPBIS working group at IETF 125, in particular from Martin Thomson, Justin Richer, David Waite, Mike Bishop, Li Ruochen, and Yaroslav Rosomakho. 15. References 15.1. Normative References [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, . [RFC6454] Barth, A., "The Web Origin Concept", RFC 6454, DOI 10.17487/RFC6454, December 2011, . [RFC6749] Hardt, D., Ed., "The OAuth 2.0 Authorization Framework", RFC 6749, DOI 10.17487/RFC6749, October 2012, . [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, . [RFC9110] Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., "HTTP Semantics", STD 97, RFC 9110, DOI 10.17487/RFC9110, June 2022, . [RFC9651] Nottingham, M. and P. Kamp, "Structured Field Values for HTTP", RFC 9651, DOI 10.17487/RFC9651, September 2024, . [RFC9700] Lodderstedt, T., Bradley, J., Labunets, A., and D. Fett, "Best Current Practice for OAuth 2.0 Security", BCP 240, RFC 9700, DOI 10.17487/RFC9700, January 2025, . 15.2. Informative References [FETCH] WHATWG, "Fetch Living Standard", 2026, . Hardt & Goto Expires 5 January 2027 [Page 19] Internet-Draft Protected Authorization July 2026 [I-D.hardt-oauth-aauth-protocol] Hardt, D., "AAuth Protocol", Work in Progress, Internet- Draft, draft-hardt-oauth-aauth-protocol-08, 24 June 2026, . [JARM] Lodderstedt, T. and B. Campbell, "JWT Secured Authorization Response Mode for OAuth 2.0 (JARM)", November 2022, . [RFC7636] Sakimura, N., Ed., Bradley, J., and N. Agarwal, "Proof Key for Code Exchange by OAuth Public Clients", RFC 7636, DOI 10.17487/RFC7636, September 2015, . [RFC8252] Denniss, W. and J. Bradley, "OAuth 2.0 for Native Apps", BCP 212, RFC 8252, DOI 10.17487/RFC8252, October 2017, . [RFC9126] Lodderstedt, T., Campbell, B., Sakimura, N., Tonge, D., and F. Skokan, "OAuth 2.0 Pushed Authorization Requests", RFC 9126, DOI 10.17487/RFC9126, September 2021, . [RFC9207] Meyer zu Selhausen, K. and D. Fett, "OAuth 2.0 Authorization Server Issuer Identification", RFC 9207, DOI 10.17487/RFC9207, March 2022, . Appendix A. Example: Authorization Code Flow Before and After A.1. Without This Mechanism (Current OAuth) Client redirects to the AS: HTTP/1.1 303 See Other Location: https://as.example/authorize?client_id=abc&response_type=code &redirect_uri=https%3A%2F%2Fapp.example%2Fportal%2Fcb&state=123 &code_challenge=E9Melhoa...&code_challenge_method=S256 The AS has only the unreliable Referer header to know where the user came from. After authorization, the AS redirects back: HTTP/1.1 303 See Other Location: https://app.example/portal/cb?code=SplxlOBeZQQYbYS6WxSbIA &state=123&iss=https%3A%2F%2Fas.example Hardt & Goto Expires 5 January 2027 [Page 20] Internet-Draft Protected Authorization July 2026 The authorization code is now in the URL: recorded in browser history, in the client's access logs and any intermediary's logs, sent in the Referer header to any third-party resource the callback page loads, and available to be shared, screenshotted, or pasted. A.2. With This Mechanism Client redirects to the AS; the URL is identical to today, plus the header: HTTP/1.1 303 See Other Location: https://as.example/authorize?client_id=abc&response_type=code &redirect_uri=https%3A%2F%2Fapp.example%2Fportal%2Fcb&state=123 &code_challenge=E9Melhoa...&code_challenge_method=S256 OAuth-Authorization: query="client_id=abc&response_type=code &redirect_uri=https%3A%2F%2Fapp.example%2Fportal%2Fcb&state=123 &code_challenge=E9Melhoa...&code_challenge_method=S256", path="/portal/" The redirecting URL is https://app.example/portal/login, so the browser validates the /portal/ path claim, attests the origin, and delivers: GET /authorize?client_id=abc&response_type=code&redirect_uri=... &state=123&code_challenge=...&code_challenge_method=S256 HTTP/1.1 Host: as.example OAuth-Authorization: query="client_id=abc&response_type=code &redirect_uri=...&state=123&code_challenge=... &code_challenge_method=S256", origin="https://app.example", path="/portal/" The AS verifies the query member matches the URL, verifies https://app.example is consistent with the registered redirect URI for client_id=abc, and, knowing the browser and client support protected authorization responses, returns the response in the header with a clean redirect URI: HTTP/1.1 303 See Other Location: https://app.example/portal/cb OAuth-Authorization: query="code=SplxlOBeZQQYbYS6WxSbIA &state=123&iss=https%3A%2F%2Fas.example" The browser attests the AS origin and delivers, once: Hardt & Goto Expires 5 January 2027 [Page 21] Internet-Draft Protected Authorization July 2026 GET /portal/cb HTTP/1.1 Host: app.example OAuth-Authorization: query="code=SplxlOBeZQQYbYS6WxSbIA &state=123&iss=https%3A%2F%2Fas.example", origin="https://as.example" The client verifies origin is its expected AS, parses the query member with its existing query-string parser, verifies state, and exchanges the code (with its PKCE verifier). The authorization code never appeared in any URL: nothing in browser history, nothing in URL-based logs, nothing in Referer headers, nothing to share or replay. Appendix B. Design Rationale B.1. Why OAuth-Specific Rather Than Generic Redirect Headers A generic redirect-header mechanism gives the browser no way to know when protections apply, no defined trust model, and a broad new surface for navigation tracking. Scoping to OAuth lets the browser recognize exactly one flow shape, attach exactly the metadata that flow needs, and constrain the mechanism to navigations that already carry cross-site identifiers by design. B.2. Why a Single Header Field The browser's processing is identical on both legs of the flow, so one header field name means one processing rule, one forbidden header name in Fetch, and one IANA registration. Separate "request" and "response" names would also invite conflating the OAuth message direction with the HTTP message direction: the header appears in an HTTP response and then an HTTP request on _each_ leg. The receiving endpoint's role already determines which OAuth message the header carries, and delivery to the wrong context fails closed (Section 10.3). B.3. Why Not Cryptographic Protection of Parameters The exposure this document addresses is at the endpoints, not on the channel: TLS already protects parameters in transit. An encrypted or signed response (JARM [JARM]) placed in a URL is still a URL: still written to history, still in access logs, still sent in Referer headers, still shareable. Cryptographic protection also requires key distribution between every client and AS pair, and no cryptographic scheme can attest a client's _web origin_: only the user agent knows which origin actually initiated a navigation. The mechanisms compose: a JARM response can be carried in the header's query member, gaining URL-freedom on top of its integrity properties. Hardt & Goto Expires 5 January 2027 [Page 22] Internet-Draft Protected Authorization July 2026 B.4. Why Not Move to the Back Channel Not putting sensitive parameters in the front channel at all is the strongest protection, and it is a different protocol. PAR [RFC9126] moves the authorization request to the back channel; the AAuth protocol [I-D.hardt-oauth-aauth-protocol] moves the entire authorization exchange to authenticated back-channel HTTP. Those approaches carry different deployment costs: new endpoints, client authentication, and protocol changes on both sides. This specification exists for the enormous installed base of redirect- based OAuth deployments, which can adopt it as a library update with no new endpoints, no keys, and no change to how authorization parameters are constructed or parsed. B.5. Why the Authorization Request Parameters Stay in the URL Compatibility, permanently. The authorization request URI is processed by every existing AS with no changes, and the client can never know whether the user's browser supports this mechanism, so it always sends both (Section 9). The query member on this leg is not for confidentiality (authorization request parameters are not secrets) but provides a canonical copy bound to browser-attested origin metadata, a tamper check (Section 5.2), and the capability signal that unlocks the protected authorization response. B.6. Why a Structured Field Dictionary Wrapping a Query String The outer Structured Field [RFC9651] layer gives the browser a well- defined, extensible place for the members it owns (origin, path) without colliding with the OAuth parameter namespace. The OAuth parameters themselves stay query-string encoded inside the query member, so every implementation parses them with the same code path it uses for URLs today: no new parameter encoding, and no dual-parser inconsistency bugs. B.7. Why Redirect Responses Only (Why Not form_post) This mechanism applies exclusively to redirect responses. The form_post response mode places parameters in the document as form fields, where they are visible to page JavaScript and extensions no matter what the browser does with headers; there is nothing there for the browser to protect. Redirects are also what the overwhelming majority of deployments use, and extending them is a library change rather than an infrastructure change. Hardt & Goto Expires 5 January 2027 [Page 23] Internet-Draft Protected Authorization July 2026 B.8. Why the AS Rejects on Query Mismatch, Rather Than the Browser Dropping the Header If the browser dropped the header when the query member disagreed with the URL, an attacker able to modify the URL query could make the header vanish, silently downgrading the flow to unprotected URL parameters. Instead the browser always delivers the header, and the AS treats a mismatch as an error (Section 5.2). Tampering becomes a visible failure rather than a silent downgrade. B.9. Why Not a Sec-Prefixed Name The Sec- prefix means only that web content cannot _set_ a header; extensions and service workers can still read Sec- request headers today. The protections required here are strictly stronger (Section 8) and are defined by normative browser behavior plus forbidden-header-name registration in Fetch. A Sec- prefix would understate the guarantee being made, and would break the symmetry of the same header field flowing from a redirect response into the browser's subsequent HTTP request. B.10. Why Not a response_mode Value The protected authorization response is functionally a new response mode, but it is negotiated by demonstrated browser capability (the header's arrival with the authorization request) rather than requested by the client. A response_mode parameter would allow a client to request behavior the user's browser may not support, which cannot work. In-band capability signaling is the only reliable negotiation. B.11. Why the Authorization Response Is Not Readable by JavaScript Deliberate. [RFC9700] and current browser-based-app guidance steer authorization codes away from script-accessible surfaces, where they are exposed to XSS, injected third-party code, and extensions. Delivering the authorization response only to the server at the redirect URI enforces that guidance structurally. B.12. Why Native Application Flows Are Out of Scope The header cannot survive the custom-scheme or app-link handoff from the system browser back to a native app: the operating system delivers a URL, not headers. The threat model also differs: dedicated system authentication sessions do not run page JavaScript or extensions in the same way. Native flows continue to use their existing mechanisms (with PKCE, per [RFC8252]). Hardt & Goto Expires 5 January 2027 [Page 24] Internet-Draft Protected Authorization July 2026 B.13. Why Browser-Attested Origin When iss Exists The iss parameter [RFC9207] is asserted by whichever server sends the response; in the mix-up scenarios it targets, the client must trust the asserter. The origin member is attested by the browser and cannot be set or influenced by any server. The two compose: iss travels unchanged inside the query member, and the client additionally gets an unforgeable statement of which origin the response actually came from. Authors' Addresses Dick Hardt Hellō Email: dick.hardt@gmail.com Sam Goto Google Email: goto@google.com Hardt & Goto Expires 5 January 2027 [Page 25]