Back to blog

OAuth 2.1 vs 2.0: What developers need to know

Auth & identity

Apr 2, 2025

Author: Stytch Team

OAuth 2.1 vs 2.0: What developers need to know

Modern app development requires solid authentication and authorization strategies to keep user data safe and APIs secure. If you’ve worked with OAuth 2.0, you’ve probably experienced both its flexibility and its security pitfalls.

Enter OAuth 2.1, an update that consolidates a decade of best practices and lessons learned from the soon-to-be outdated OAuth 2.0 protocol.

While it's still in draft form as of April 2025, its core specifications are already being adopted by leading organizations like Anthropic, who have made OAuth 2.1 a foundational part of the Model Context Protocol (MCP) authorization spec.

In this guide, we’ll break down what OAuth 2.1 changes, why it matters, and what you need to implement in order to improve your own authentication and authorization flows.

What is OAuth 2.1 and why does it matter?

OAuth 2.1 is not a brand new standard; it's an incremental update that incorporates the security lessons learned since OAuth 2.0 was released in 2012. Believe it or not—iIt’s been over a decade since RFC 6749 and RFC 6750, the foundations of the OAuth 2.0 protocol, were published in 2012.

Rather than introducing new features, OAuth 2.1 removes insecure patterns and mandates security best practices that were previously optional. Think of OAuth 2.1 as a refinement or an improvement rather than a total rewrite.

Over the years, OAuth 2.0 became a patchwork of extensions and competing recommended implementations. This made it difficult for developers to know what “secure” actually looked like. Instead of forcing developers to cross-reference multiple RFCs (PKCE, JWT access tokens, DPoP ,etc.), OAuth 2.1 gives a single, unified source of truth for secure implementation.

OAuth 2.1 sequence diagram

Just like the jump from OAuth 1.0 to 2.0, the community felt like there was a need to address issues by consolidating years of best practices into a more secure, streamlined specification. That’s what OAuth 2.1 aims to deliver.

TL;DR What’s actually changing

If you take away anything from this article, it should be this quick side-by-side comparison of OAuth 2.0 and OAuth 2.1 so you can see what’s changed.

OAuth 2.0

OAuth 2.1

Proof Key for Code Exchange (PKCE)

Proof Key for Code Exchange (PKCE)

Optional; primarily recommended for public clients like mobile apps.

Mandatory for all clients using the authorization code flow to enhance security.

Implicit Grant Flow

Implicit Grant Flow

Supported; allows clients (especially SPAs) to receive access tokens directly without an authorization code.

Removed due to security concerns; SPAs should utilize the authorization code flow with PKCE.

Resource Owner Password Credentials Grant

Resource Owner Password Credentials Grant

Supported; enables clients to obtain tokens by directly using the resource owner's credentials.

Removed to discourage practices that involve sharing user credentials with clients.

Redirect URI Matching

Redirect URI Matching

Allows flexible matching, including wildcard patterns, which can introduce security risks.

Requires exact string matching for redirect URIs to prevent open redirect attacks.

Bearer Token Transmission

Bearer Token Transmission

Permits inclusion of bearer tokens in URI query strings, posing potential security vulnerabilities.

Prohibits sending bearer tokens in query strings; mandates using headers or message bodies instead.

Refresh Token Handling

Refresh Token Handling

No specific guidance on rotation; long-lived refresh tokens can be a security risk if compromised.

Recommends refresh token rotation, issuing a new token with each use and invalidating the previous one to mitigate risks.

In the next few sections, we’ll walk through each change in more detail and how to implement them in practice.

Key differences between OAuth 2.0 and 2.1

1. PKCE is now required for all clients

In OAuth 2.0, PKCE (Proof Key for Code Exchange) was optional and only recommended for public clients like mobile apps.

In OAuth 2.1, PKCE is required for all clients. Why? It protects against authorization code interception attacks, especially in cases where the code could be intercepted during redirect handling or in misconfigured environments.

What this looks like in practice:

PKCE flow

If the authorization server can't validate that the code_verifier matches the original code_challenge, the request is rejected. This prevents attackers from exchanging intercepted codes for tokens—even if they’ve tricked the user into logging in.

2. Implicit flow is removed

In OAuth 2.1, the implicit flow (response_type=token) has been officially removed.

This flow was originally designed for Single-Page Applications (SPAs) that couldn’t securely store client secrets or perform backend token exchanges. It allowed these apps to receive access tokens directly in the browser—without going through the authorization code exchange. While convenient at the time, it introduced serious security concerns like the following:

  • Token Exposure in URLs: Access tokens returned in the URL fragment can be inadvertently exposed through browser history, referrer headers, or logs, increasing the risk of leakage.​
  • Lack of Client Authentication: The Implicit Flow does not authenticate the client, making it easier for malicious applications to obtain tokens on behalf of users.​
  • Advancements in Browser Capabilities: Modern browsers now support Cross-Origin Resource Sharing (CORS), allowing SPAs to securely perform backchannel communication, which was a limitation when the Implicit Flow was introduced.

With the implicit flow, after user authentication and consent, the authorization server would redirect to something like:

https://spa.example.com/callback#
access_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
&token_type=Bearer
&expires_in=3600
&state=ae13d489fb21

Note how the access token is directly included in the URL fragment (after the #). This is the key security risk that led to the removal of this flow in OAuth 2.1.

OAuth 2.1 mandates SPAs use the authorization code flow with PKCE instead.

3. Resource Owner Password Credentials grant is removed

In OAuth 2.0, the Resource Owner Password Credentials (ROPC) grant allowed applications to collect a user's username and password directly and exchange them for tokens. In OAuth 2.1, this grant has been formally removed.

Why? Because ROPC breaks the core design philosophy of OAuth: delegated authorization without exposing credentials. Handing raw user credentials to an application—especially a third-party one—introduces major security risks, including phishing, keylogging, and insecure credential storage.

ROPC grant was susceptible to vulnerabilities like:

  • Direct Exposure of Credentials: Applications handling raw user credentials increase the risk of credential leakage and misuse.​
  • Bypassing Secure Delegation: The ROPC grant contradicts OAuth's core principle of delegated access, where applications should obtain tokens without directly accessing user credentials.​
  • Enhanced Security Practices: Modern security standards advocate for flows that minimize credential exposure, such as the Authorization Code Flow with PKCE.
// DEPRECATED - Resource Owner Password Credentials Grant (OAuth 2.0)
fetch('https://auth-server.com/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'password',
    username: 'user@example.com',  // User's credentials collected directly by the app
    password: 'userPassword123',   // Security risk: client has direct access to credentials
    client_id: 'client123',
    scope: 'read write'
  })
})

The client application has full access to the user’s login credentials—introducing countless opportunities for abuse or compromise. This is especially important for confidential clients, which are expected to authenticate securely with the authorization server and avoid exposing user credentials directly.

In this scenario, OAuth 2.1 also mandates the use of Authorization Code flow with PKCE instead.

4. Exact redirect URI matching

OAuth 2.1 requires strict, exact redirect URI matching. This change closes a common security gap in OAuth 2.0, where fuzzy or wildcard matching made it easier for attackers to exploit misconfigured apps and intercept tokens.

In OAuth 2.0, developers often registered redirect URIs with loose patterns to support different environments—like development, staging, or production. For example:

  • https://website.com/callback​
  • https://*.website.com/callback (to match multiple subdomains)

While convenient, this flexibility introduced security risks. Attackers could exploit poorly validated redirect URIs to perform open redirect attacks, leading users to malicious sites that could capture sensitive information or tokens.​

OAuth 2.1 eliminates this risk by requiring that the redirect URI included in the authorization request exactly matches one of the pre-registered URIs. No wildcards. No partial matches. If it doesn’t match exactly, the request must be rejected.

5. No tokens in query parameters

In OAuth 2.1, access tokens must never be passed via query parameters. Instead, they should be sent using the Authorization header as a bearer token or, in some cases, the request body for POST requests.

const axios = require('axios');

const config = {
headers: { Authorization: `Bearer YOUR_ACCESS_TOKEN` }
};

axios.get('https://api.example.com/data', config)
.then((response) => {
  console.log(response.data);
})
.catch((error) => {
  console.error(error);
});

On the other hand, query strings are easily exposed in server logs, browser history, analytics tools, and referrer headers—creating unnecessary risk of token leakage. OAuth 2.1 formalizes this as a prohibited pattern to reduce the attack surface and protect user data.

https://api.example.com/resource?access_token=YOUR_ACCESS_TOKEN HTTP

// DEPRECATED

6. Sender-constrained or rotating refresh tokens

OAuth 2.1 introduces stronger requirements around refresh token usage, especially for public clients. These updates are designed to limit the damage that can be done if a refresh token is stolen or leaked.

To comply, your implementation must either:

  • Rotate refresh tokens on every use (invalidate the previous one),
  • Constrain tokens to the original sender, using cryptographic binding (e.g., DPoP or mTLS).

With rotation, every time a refresh token is used to obtain a new access token, the authorization server returns a new refresh token and invalidates the old one. This ensures that:

  • A stolen refresh token becomes useless after it's been used once.
  • The lifetime of any individual token is minimized.
  • Replay attacks using an old token are prevented.

This is the preferred approach for mobile apps, SPAs, and other public clients that can’t securely store long-lived secrets.

Refresh token flow

Sender-constrained tokens go a step further by cryptographically binding the token to the client that requested it. Even if the token is intercepted, it can’t be used by anyone else.

This can be implemented with:

  • DPoP (Demonstrating Proof-of-Possession): The client signs each request with a key it controls. The token is bound to this key, and every API call must include a signed DPoP proof.
  • Mutual TLS (mTLS): The client presents a certificate during the TLS handshake, and the token is bound to that certificate. The token is only valid when used over a TLS connection authenticated with the same cert.

For confidential clients, which can securely store secrets, OAuth 2.1 expects compliance with these refresh token protections, especially when used in server-to-server scenarios like the client credentials grant.

Whether you choose rotation or sender-constrained tokens, the goal is the same: make refresh tokens single-use or client-bound, so they’re useless to attackers if compromised. OAuth 2.1 turns this from an optional best practice into an expectation for secure systems.

A final implementation checklist for developers

If you're building an auth system, whether you're modernizing an existing OAuth 2.0 setup or starting with OAuth 2.1, these are the key implementation priorities to focus on:

  1. Use authorization code + PKCE everywhere: Make PKCE the default for all clients—including web, mobile, and SPAs. It’s now required in OAuth 2.1 and significantly reduces the risk of authorization code interception.
  2. Remove deprecated flows: Eliminate use of the Implicit and Resource Owner Password Credentials grants. Redirect users through the authorization code flow instead, which supports modern security features like MFA and consent screens.
  3. Audit and lock down redirect URIs: Ensure every redirect URI is exact, HTTPS-only, and pre-registered with your authorization server. Wildcard or loosely matched URIs are no longer acceptable. URIs must be matched exactly.
  4. Secure Token Transmission: Always transmit bearer tokens via headers or message bodies, avoiding query strings to reduce exposure. Make sure each access token expires within a short, predictable window to limit the risk if it’s ever leaked.
  5. Rotate refresh tokens: If your app uses refresh tokens, implement rotation. Each token should be single-use, with the previous one invalidated after a new one is issued. This is especially important for public clients like SPAs and mobile apps.

How Stytch can help

Just like OAuth 2.0, implementing a secure OAuth 2.1-compliant flow from scratch is a steep technical challenge and investment to ensure secure authentication and authorization systems.

Stytch’s Connected Apps feature can offload that engineering work. It gives you:

  • A fully compliant OAuth and OIDC identity provider
  • The ability to create and authenticate third-party applications with issued access tokens
  • A unified management system for permissions, scopes, and consent flows
  • Built-in PKCE, token rotation, scope enforcement, and secure defaults
  • And more

If you're building an app that needs to integrate with AI agents or third-party apps, Stytch makes it easy. You configure a fully compliant OAuth server with your application in just a few steps.

Final thoughts

It’s time to upgrade. Embracing OAuth 2.1 now means fewer vulnerabilities, less complexity, and a more secure foundation for your authentication and authorization systems.

Implementing auth can be a heavy lift, but you don’t have to build it from scratch. Stytch offers a suite of APIs and SDKs for authentication, authorization, and fraud prevention, so you can implement OAuth quickly without compromising on security.

Sign up today and build OAuth.

Implement OAuth

Stytch Connected Apps makes AI agent workflows, cross-app logins, secure data-sharing workflows possible with OAuth.

Learn more

Share this article

OAuth 2.1 vs 2.0: What developers need to know