OAuth 2.1 is Here: What You Need to Know
Tags: webdev, security, identity, opensource
Published: 2024-06-21 02:45:09

Since the initial release of OAuth 2.0, the internet has evolved significantly. Security threats have become more sophisticated. In response to these changes, the OAuth 2.1 specification has been planned. Let's explore the key differences between OAuth 2.0 and OAuth 2.1 and how they were adopted in Logto.

---
# Introduction

Since OAuth 2.0 (RFC 6749) came out in 2012, the world of web and mobile apps has changed a lot. People are moving from desktops to mobile devices, and Single Page Applications (SPAs) are now all the rage. We've also seen tons of new frameworks and web technologies pop up. With all these changes, the security challenges have stepped up too. To keep up with the latest web techs, new RFCs like Proof Key for Code Exchange (PKCE) have been continuously released to enhance OAuth 2.0. It's become crucial to group all the best practices for today’s security requirements, and that’s why OAuth 2.1 is coming.

In the upcoming OAuth 2.1, the OAuth Working Group aims to consolidate all the best practices and security recommendations into a single document. At Logto, we keep embrace with the latest standards and best practices of OAuth. In this article, we'll explore the key differences between OAuth 2.0 and OAuth 2.1 and how they were adopted in Logto.

# PKCE is now required for all OAuth clients using the Authorization Code flow

One of the most significant changes in OAuth 2.1 is that Proof Key for Code Exchange (PKCE) is now required for all OAuth clients using the Authorization Code flow. PKCE is a security extension that prevents authorization code interception attacks. It's especially useful for mobile and Single Page Applications (SPAs) where the client secret can't be securely stored.

OAuth clients can be categorized into two different types based on their ability to store secrets securely:

1. Confidential clients: These clients can store secrets securely, such as server-rendered web applications and web servers. All the authorization-related requests are made from the server side, and the risk of exposing the client secret is low.
3. Public clients: These clients can't store secrets securely, such as mobile apps and SPAs. The client secret can be easily extracted from the client-side code, and it's hard to protect it from attackers.

For public clients, PKCE is a must-have security measure. It ensures that the authorization code can only be exchanged by the client that initiated the authorization request.

PKCE works by generating a random code verifier and a code challenge based on the code verifier. The code verifier is sent to the authorization server, and the code challenge is used to verify the code verifier when exchanging the authorization code for an access token.

> 💡 Check the [How PKCE protects the authorization code flow for native apps](https://blog.logto.io/how-pkce-protects-the-authorization-code-flow-for-native-apps/) to learn more about PKCE and how it works for mobile apps.

In OAuth 2.1, PKCE becomes mandatory for all OAuth clients employing the Authorization Code flow, irrespective of their confidentiality status—whether confidential or public. This pivotal adjustment ensures universal protection against potential authorization code interception attacks.

In Logto, the PKCE validation flow is automatically activated for both public and confidential clients.

For SPAs and mobile apps, PKCE is a must-have security measure to protect the authorization code flow in Logto. Any authorization request lacking a code challenge will be promptly declined by Logto's authorization server.

Regarding confidential clients (traditional web apps), for enhanced legacy compatibility, Logto still permits the omission of the code challenge in the authorization request. However, we strongly advocate for confidential clients to adopt PKCE by incorporating the code challenge in the authorization request, following the practices of public clients.

# Redirect URIs exact matching

A Redirect URI(Uniform Resource Identifier) is a specific endpoint or URL that the authorization server redirects the user back to after the authentication and authorization process.

During the OAuth flow, the client application includes a Redirect URI as part of the initial authorization request. Once the user completes the authentication process, the authorization server generates a response that includes an Authorization Code, and redirects the user back to the specified Redirect URI. Any deviation from the original Redirect URI will lead to an code or token leakage.

The exact string matching of Redirect URIs was first introduced in [OAuth 2.0 Security Best Current Practices](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics) section 4.1. This practice ensures that the Redirect URI must match exactly with the one registered with the authorization server. Any deviation from the registered Redirect URI will result in an error response.

we've received numerous community requests regarding the implementation of wildcard matching for Redirect URIs. While wildcard matching can offer convenience for developers managing multiple subdomains or paths, particularly with a large number of random subdomains, it also introduces security risks such as open redirect attacks. For a practical illustration of the dangers posed by missing Redirect URI validation, please refer to our [A brief OAuth security recap](https://blog.logto.io/oauth-security-recap/#redirect-uri) blog post.

In line with the stringent security standards of OAuth 2.1, Logto uses the exact string matching of Redirect URIs. This decision prioritizes the security of the OAuth flow. Rather than utilizing wildcard matching, we encourage developers to register all potential Redirect URIs with the Logto authorization server. This ensures thorough validation of Redirect URIs and helps mitigate potential security vulnerabilities.


# The Implicit Flow is deprecated
The implicit grant flow in OAuth 2.0 was designed for SPAs where the access token is returned directly in the URL fragment after the user authenticates. This method was convenient because it avoided an additional token exchange step, allowing the client to receive the token directly.

However, this convenience has its downsides. The access token can be exposed to unauthorized parties through browser history, referrer headers, or other means, making it easier for security breaches to occur—especially when access tokens remain valid for extended periods. For example, if the authorization request is intercepted by a malicious party, they can easily extract the access token from the URL fragment and impersonate the user.

In the [OAuth 2.0 Security Best Current Practices](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics), it clearly states that:

> Clients SHOULD NOT use the implicit grant (response type "token") or other response types issuing access tokens in the authorization response.

Thus, the Implicit Flow has been officially removed from the OAuth 2.1 specification.

In Logto, authorization code flow with PKCE is the only supported flow for SPAs and mobile Apps . The authorization code flow provides a more secure way to obtain access tokens by exchanging the authorization code.

# The Resource Owner Password Credentials (ROPC) grant is deprecated
The resource owner password credentials (ROPC) grant allows the client to exchange the user's username and password for an access token. It was first introduced in the OAuth 2.0 specification as a way to support legacy applications such as HTTP basic authentication or legacy native applications that could not use the more secure OAuth tokenized flows.

The ROPC grant type has been marked as not recommended in the OAuth 2.0 specification due to its security risks. The user's credentials are exposed to the client application, which can lead to potential security breaches. The client application can store the user's credentials, and if the client is compromised, the user's credentials can be exposed to attackers.

Later on, in the [OAuth 2.0 Security Best Current Practices](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics) section 2.4, the ROPC grant type's prohibition was further emphasized as MUST NOT be used. As a result, the ROPC grant type has been removed from the OAuth 2.1 specification.

Due to the high security risks associated with the ROPC grant type, Logto has never supported it. If you are still using the direct user credentials flow in your legacy applications, we strongly recommend migrating to a more secure method, such as the authorization code flow or the client credentials grant. Logto offers various SDKs and tutorials to help you integrate these secure OAuth flows into your applications effortlessly.

We understand that developers may want to design or self-host their own user sign-in interface for the best product experience. At Logto, we offer a range of sign-in experience (SIE) customization options, including branding settings and custom CSS. Additionally, we have several ongoing projects, such as bring-your-own UI, and direct sign-in, to provide more flexibility for developers to bring their own sign-in interface while maintaining the security of the OAuth flow.

> 💡 To learn more about the security risks of the ROPC grant type, check out our blog post [Why you should deprecate the ROPC grant type](https://blog.logto.io/deprecated-ropc-grant-type/)

# Conclusion

OAuth 2.1 is the latest upgrade to the OAuth protocol, geared towards tackling today's security challenges while embracing modern web and mobile app needs. The OAuth working group is actively updating and refining OAuth 2.1 to ensure it meets the latest security standards and best practices. The latest draft, OAuth 2.1 11, was released in May 2024, marking significant progress toward its finalization. With the wide range adoption on the horizon, we highly recommend that everyone follow the best practices outlined in OAuth 2.1 to enhance security and improve user experience.

{% cta https://logto.io/?ref=dev %} Try Logto Cloud for free {% endcta %}