How OAuth Evolved

This section documents OAuth 2.0 (RFC 6749) as amended by the OAuth 2.0 Security Best Current Practice (RFC 9700 / BCP 240), the OAuth 1.0 Protocol (RFC 5849) for historical context, and OpenID Connect Core 1.0, as published at the IETF Datatracker and the OpenID Foundation specifications — and, on the Spring pages, Spring Boot 4.1.x and Spring Security 7.1.x as published at the Spring Security reference documentation — which are the references these pages are written and verified against.

OAuth 2.1 is still an Internet-Draft (draft-ietf-oauth-v2-1-16, 3 September 2026) and is flagged as such everywhere it appears on these pages. It is a working-group consolidation in progress, not a published standard; nothing here should be read as saying otherwise.

This content was generated with the assistance of AI and should be verified against those official specifications before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

OAuth is not the product of a single design and a single release; it is nearly two decades of proprietary protocols, a standard, a rewrite, a walkout, and roughly twenty extension RFCs converging on a single in-progress consolidation. Understanding that history is not trivia — it explains why the protocol looks the way it does, why some of its parts (implicit grant, resource owner password credentials, bearer tokens with no proof of possession) are now considered mistakes, and why "OAuth 2.0" today means something considerably larger than RFC 6749 alone. This page walks the timeline in order; the figure below marks the same milestones visually.

Timeline of OAuth from 2006 to 2026

The pre-OAuth proprietary era

Before there was a standard, every large service that wanted to let third-party applications act on a user’s behalf invented its own answer, and every answer required the third-party application to see the user’s password at least once:

  • Google ClientLogin (introduced 2006) had the client application collect the user’s Google username and password directly and exchange them for a long-lived authentication token via a POST request. The password passed through the client’s own code, in full, every time.

  • Google AuthSub (introduced 2006, alongside ClientLogin) improved on this for web applications: the user was redirected to a Google-hosted page to authenticate, and the client received an opaque token afterwards — much closer to what OAuth would formalise, but Google’s own proprietary redirect and token format, with no applicability outside Google’s own services.

  • Yahoo! BBAuth ("Browser-Based Authentication", introduced 2006) followed the same redirect-and-token shape as AuthSub, again as a Yahoo!-only mechanism with its own parameter names and its own token semantics.

Each of these solved the same problem for one vendor. A developer integrating with Google, Yahoo! and a third provider needed three separate, incompatible integrations, each trusting its own proprietary redirect dance, with no shared vocabulary for "client", "scope", or "token" and no shared security review. That fragmentation — not a single dramatic breach — is what motivated an open standard: enough vendors had independently arrived at "redirect the user, get a token back" that formalising the pattern once, with a jointly reviewed security model, was obviously worth doing.

OAuth Core 1.0 (December 2007)

A group of developers from Twitter, Google, Ma.gnolia and others — including Blaine Cook, Chris Messina and Larry Halff — began drafting a shared specification in 2006, and OAuth Core 1.0 was published in December 2007. It formalised the three-legged dance already visible in AuthSub/BBAuth (request a token, get the user to authorize it, exchange it for an access token) but added something none of the proprietary schemes had: a cryptographic request-signing mechanism, so that an access token could be used over plain HTTP without a bearer-token eavesdropper being able to replay it verbatim. The full mechanics of that signing scheme are covered on OAuth 1.0a, which the reader is encouraged to read before this page’s later sections, since several of the changes below are direct reactions to specific properties of 1.0’s design.

Security Advisory 2009.1 and Revision A (June 2009)

In April 2009, a session-fixation vulnerability was found in OAuth Core 1.0’s request-token flow: because the request token was not bound to the specific authorization request that obtained it, an attacker could obtain a valid, unauthorized request token, trick a victim into authorizing that token (for example by starting the flow themselves and handing the victim the resulting authorization URL), and then redeem the now-authorized token as their own — gaining access to the victim’s account at the target service. The OAuth community published Security Advisory 2009.1 describing the attack and coordinated a fix across implementers before public disclosure.

The fix introduced a new parameter, oauth_verifier: the authorization server, after the resource owner approves the request token, generates a random verifier and returns it to the client alongside the now-approved request token; the client must present that verifier when exchanging the request token for an access token. Binding the approval to a verifier only the legitimate client receives closes the fixation window. This fix was published as OAuth Core 1.0 Revision A in June 2009 — the "a" that gives "OAuth 1.0a" its name, and the reason oauth_verifier appears in the three-legged flow described on OAuth 1.0a.

RFC 5849 (April 2010)

OAuth 1.0a itself was subsequently published by the IETF as RFC 5849 in April 2010, as an Informational RFC — documenting existing, already-implemented practice for the community record rather than defining a new IETF Standards Track protocol. RFC 5849 is, functionally, OAuth Core 1.0 Revision A with the IETF’s editorial conventions applied; there is no material protocol change between the two.

OAuth WRAP and the removal of signatures

In parallel with RFC 5849’s publication, a separate proposal — OAuth WRAP ("Web Resource Authorization Profiles"), authored primarily by engineers from Microsoft, Google and Yahoo! in 2009-2010 — took a very different approach to the same problem: it dropped OAuth 1.0’s per-request cryptographic signatures entirely in favour of a simple bearer token presented over mandatory TLS. The reasoning was pragmatic: 1.0’s signature base string (see OAuth 1.0a) required exact, byte-for-byte agreement between client and server on URL and parameter canonicalisation, which was a real and recurring source of interop bugs across languages, HTTP libraries and proxies that silently reordered or re-encoded parameters in flight. WRAP was never published as an independent standard; it was folded into the working group that became OAuth 2.0 and its bearer-token model became that protocol’s foundation.

RFC 6749 and RFC 6750 (October 2012)

The OAuth 2.0 working group’s output shipped in October 2012 as two RFCs: RFC 6749, The OAuth 2.0 Authorization Framework, and RFC 6750, The OAuth 2.0 Authorization Framework: Bearer Token Usage. Together they define almost everything covered elsewhere in this reference: the four roles, the grant types (authorization code, implicit, resource owner password credentials, client credentials), the token endpoint, and the bearer-token model WRAP had prototyped.

RFC 6749 is explicitly a framework, not a fully specified protocol: it defines extension points (new grant types, new token types, new client-authentication methods) rather than closing them off, which is both its greatest strength — the entire extension decade below builds on those extension points without needing a new major version — and, as covered on OAuth 1.0 vs. OAuth 2.0, one of its most-criticised properties: two fully RFC-6749-compliant implementations are not guaranteed to interoperate.

The signatures debate and "the road to hell"

The move from OAuth 1.0’s signed requests to OAuth 2.0’s bearer tokens was contentious at the time, and nobody argued the point more visibly than Eran Hammer-Lahav, who had edited both OAuth 1.0 and, for most of its life, the OAuth 2.0 draft. In a widely read 2010 post, "OAuth 2.0 (without Signatures) Is Bad for the Web", Hammer-Lahav argued that removing per-request signatures traded a real (if imperfect) cryptographic integrity guarantee for a bearer-token model that depended entirely on TLS being correctly deployed everywhere, all the time, with no defence in depth if it was not.

That disagreement, compounded by a broader shift in the working group away from a single interoperable protocol toward an extensible framework meant to be profiled differently by each deployment, led Hammer-Lahav to resign his editorship in mid-2012, shortly before RFC 6749’s publication, in a post titled "OAuth 2.0 and the Road to Hell". His central complaint was that OAuth 2.0, as it shipped, was "a framework for building authorization protocols" rather than an authorization protocol itself — exactly the "closed spec vs. extension framework" trade-off examined on OAuth 1.0 vs. OAuth 2.0. History has been mixed on the underlying bet: bearer tokens over mandatory TLS did become the industry default, but the very absence of proof of possession he warned about is exactly what DPoP and mTLS-bound tokens exist to fix, more than a decade later.

The extension decade

RFC 6749’s extension points meant that, unlike OAuth 1.0, OAuth 2.0 could absorb new capability as separate RFCs rather than a new major protocol version. The following table lists the extension RFCs referenced elsewhere in this reference, in RFC-number order, with what each one added:

RFC What it added

7009

Token revocation — a /revoke endpoint so a client or resource owner can explicitly invalidate a token before it expires. See Opaque tokens, introspection and revocation.

7519

JSON Web Token (JWT) — a compact, signed (and optionally encrypted) claims format that became the de facto structured access-token and ID-token representation. See JWT and JOSE.

7591 / 7592

Dynamic Client Registration and Registration Management — letting a client register itself with an authorization server via an API instead of an administrative form. See Discovery, metadata and client registration.

7636

PKCE (Proof Key for Code Exchange) — closes the authorization-code-interception attack against public clients by binding the code to a verifier only the original requester holds. See Authorization code and PKCE.

7662

Token introspection — lets a resource server ask the authorization server whether an opaque token is still valid and what it is good for. See Opaque tokens, introspection and revocation.

8252

OAuth 2.0 for Native Apps — mandates the system browser (or an in-app browser tab) over an embedded WebView for native and mobile clients. See Native and mobile apps.

8414

Authorization Server Metadata — the /.well-known/oauth-authorization-server discovery document. See Discovery, metadata and client registration.

8628

Device Authorization Grant — lets an input-constrained device (a TV, a CLI) delegate the interactive part of the flow to a second device. See Device authorization grant.

8693

Token Exchange — a /token grant for trading one security token for another, enabling delegation and identity chaining across services. See Token exchange and assertion grants.

8705

Mutual-TLS client authentication and certificate-bound access tokens — sender-constrains a token to the client’s TLS certificate. See Sender-constrained tokens: DPoP and mTLS.

9068

JWT Profile for OAuth 2.0 Access Tokens (at+jwt) — standardises the claims a JWT access token should carry, so resource servers do not each invent their own shape. See JWT and JOSE.

9101

JWT-Secured Authorization Request (JAR) — lets the entire authorization request be carried as a signed (and optionally encrypted) JWT instead of loose query parameters. See PAR, JAR and hardened profiles.

9126

Pushed Authorization Requests (PAR) — moves the authorization request to a back-channel POST, returning a short request_uri for the front-channel redirect. See PAR, JAR and hardened profiles.

9207

Authorization Server Issuer Identification — the iss parameter on the authorization response, closing mix-up attacks between multiple authorization servers. See Security best practices.

9396

Rich Authorization Requests (RAR) — structured, fine-grained authorization_details beyond a flat scope string. See Scopes, claims and permissions.

9449

DPoP (Demonstrating Proof of Possession) — sender-constrains a token to a client-held key using a signed proof JWT on each request, without requiring mTLS infrastructure. See Sender-constrained tokens: DPoP and mTLS.

9470

Step Up Authentication Challenge Protocol — lets a resource server demand a stronger authentication event mid-session via a structured WWW-Authenticate challenge. See Authentication methods: 2FA and passwordless.

9700

Best Current Practice for OAuth 2.0 Security (BCP 240) — consolidates over a decade of attack research into a single set of mandatory-to-implement mitigations; the specification baseline named in this section’s disclaimer. See Security best practices.

9728

Protected Resource Metadata — a discovery document for the resource server side, complementing RFC 8414’s authorization-server metadata. See Discovery, metadata and client registration.

10017

OAuth 2.0 for Browser-Based Applications (BCP 212) — the hardened profile for single-page applications, formalising the backend-for-frontend pattern. See Browser-based apps.

10027

Best Current Practice for Security of Cross-Device Flows — mitigations for the device-code phishing pattern uncovered after RFC 8628 shipped. See Device authorization grant.

Two grants that RFC 6749 shipped with — the implicit grant and the resource owner password credentials grant — are conspicuously absent from later hardening: instead of being fixed, both are covered on Legacy implicit and password grants as constructs the ecosystem moved away from rather than patched.

The OAuth 2.1 consolidation

By the mid-2020s, "OAuth 2.0" in practice meant RFC 6749 read together with RFC 9700’s Security BCP, PKCE, and a handful of the extension RFCs above — a correct but scattered picture that new implementers had to assemble from twenty-odd documents. The OAuth working group’s response is draft-ietf-oauth-v2-1 (at the time of writing, revision draft-ietf-oauth-v2-1-16, dated 3 September 2026): a consolidation, folding the accumulated best practice back into a single, self-contained document that reads like RFC 6749 but reflects what a compliant deployment should actually do in 2026.

draft-ietf-oauth-v2-1-16 is an IETF Internet-Draft — a working-group document undergoing active review, not a published standard. As of this page’s writing its working-group milestone is "submit to IESG" in December 2026; it has not been submitted for RFC publication, has no RFC number, and can still change before it does. Everywhere this reference mentions OAuth 2.1, it means this specific in-progress draft, never a finished specification — see the Datatracker page for its current status.

The draft’s three headline changes, each a direct response to lessons in the extension decade above:

  • PKCE becomes mandatory for every authorization-code client, including confidential ones. RFC 6749 and RFC 7636 originally treated PKCE as primarily a public-client defence; RFC 9700 already recommended it universally, and OAuth 2.1 makes that recommendation a requirement, because the interception attack PKCE closes does not actually care whether the client can also hold a secret.

  • The implicit grant is removed. Returning an access token directly in a URL fragment (RFC 6749 §4.2) is dropped entirely rather than merely discouraged — see Legacy implicit and password grants for exactly why it was never safe against a public JavaScript-hosted client.

  • Resource owner password credentials (ROPC) is removed. The grant that had the client collect the resource owner’s password directly is dropped — the very anti-pattern OAuth exists to avoid, formalised as a grant type in RFC 6749 §4.3 and now excised.

Beyond the headline three, the draft tightens refresh-token handling (rotation and sender-constraining are pushed from "recommended" to "expected" for public clients, closing the loop described on Access and refresh tokens) and redirect-URI validation (requiring exact string matching rather than the looser prefix-matching some early deployments allowed, reinforcing the point made on Security best practices).

None of this is new cryptography or a new wire format — it is the extension decade’s hard-won lessons written down as the default, rather than as an opt-in a careful implementer has to know to reach for.

Where to go next