Which OAuth Flow Should You Use?

Deciding which flow is best suited for your use case depends mostly on how your application is designed, however there are other parameters to weigh in, like the level of trust for the calling application, or the customer experience you envision for your users.

The following outlines various authentication and authorization scenarios, and which authentication method applications developers should use for each.

Authentication Flows

The OAuth 2.0 Authorization Framework supports several different flows (AKA, grant types). Flows user workflows (both interactive and non-interactive) that result in the creation of an access token, ID token, and/or refresh token that can be used by the application to create a local session.

Figure 1 below illustrates a key point: some applications are capable of protecting a client ID/secret pair, and some cannot; and that impacts how they request tokens on behalf of the user.

Figure 1: OAuth Flows

Here is some helpful guidance that you can use determine which authentication flow your application should use:

Is the Client the Resource Owner?

If the party that requires access to resources is a machine (i.e. machine-to-machine authorization) then the Client is also the Resource Owner, so no end-user authorization is needed.

Your application should use: Authorization Code Flow

Is the Client a web app executing on the server?

If the Client is a regular web app executing on a server, then the Authorization Code Flow should be used. This flow allows the Client to retrieve an ID Token, Access Token and, optionally, a Refresh Token interactively, on behalf of a user (i.e. the resource owner). The Access Token is then passed directly to the web server hosting the Client, without exposing the access token to the user’s web browser.

Your application should use: Authorization Code Flow

Is the Client a Single-Page App?

If the Client is a Single-Page App (SPA), (i.e. an application running in a browser using a scripting language like JavaScript) then the Authorization Code Flow with Proof Key for Code Exchange (PKCE) is recommended. this flow, the Access Token is not exposed on the client side, and this flow can return Refresh Tokens.

Your application should use: Authorization Code Flow w/ Proof Key Code Exchange (PKCE)

Is the Client a Native/Mobile App?

If the application is running on a native device wherein the entirety of the device operating system is under control of the end user, then PKCE should be used.

Your application should use: PKCE

Is the Client absolutely trusted with user credentials?

If the application is highly trusted (i.e. first party, device constrained and sender constrained) then Resource Owner Password Credentials Grant may be used. In this flow, the end-user provides credentials (username/password), typically using an interactive form. This information is then sent to the backend (i.e. server side) and from there to Auth0. It is therefore imperative that the Client is absolutely trusted with this information since the user (resource owner) does not have control over how and where those credentials are used and/or stored.

Your application may use: Resource Owner Password Grant (ROPG)

Authorization Code Flow

The Authorization Code Flow (‘auth code flow‘ for short) allows server-side applications to exchange an Authorization Code for a token (id token, access token or refresh token). Server-side apps are applications that do not publicly expose their source code, and therefore have the capability to protect client ID and secret pairs. Specifically this excludes client-side applications such as single page applications (SPAs) and native (mobile or desktop) applications.

Applications utilizing the auth code flow must be server-side (A.K.A. backend) because both the client ID and secret pair must be included in the resulting code-for-token exchange request.

Figure 2: Authorization Code Flow

Authorization Code Flow w/ Proof Key Code Exchange (PKCE)

Applications that have their client source code wholly exposed or are under the possession of an untrusted 3rd party (i.e. the user and their device) are considered non-confidential or public clients. Due to the exposure of the client’s operating code base, when non-confidential clients request ID tokens, access tokens or refresh tokens, some additional security vulnerabilities are exposed that are not mitigated by the Authorization Code Flow alone. In particular:

  • Native apps Cannot securely store a Client Secret. Decompiling the app will reveal the Client Secret, which is bound to the app and is the same for all users and devices.
  • Native apps may make use of a custom URL scheme to capture redirects (e.g., MyApp://) potentially allowing malicious applications to receive an Authorization Code from your Authorization Server.
  • Single-page apps Cannot securely store a Client Secret because their entire source is available to the browser.

Given these vulnerabilities, OAuth 2.0 provides a version of the Authorization Code Flow which makes use of a Proof Key for Code Exchange (PKCE) (defined in OAuth 2.0 RFC 7636). The PKCE-enhanced Authorization Code Flow introduces a secret created by the calling application that can be verified by the authorization server; this secret is called the Code Verifier. Additionally, the calling app creates a transform value of the Code Verifier called the Code Challenge and sends this value over HTTPS to retrieve an Authorization Code. This way, a malicious attacker can only intercept the Authorization Code, and they cannot exchange it for a token without the Code Verifier.

Figure 3: Authorization Code Flow w/ Proof Key Code Exchange (PKCE)

PKCE w/ backend applications

It has been widely postulated that using the Authorization Code Flow w/ PKCE eliminates the need to store a client secret on a backend application server, and therefore even backend applications should use PKCE instead.

While the sentiment may be correct, that you can’t lose a secret you never had in the first place, there’s a bit more to it than that.

PKCE was originally designed to protect the authorization code flow in mobile apps, and therefore its ability to prevent authorization code injection makes it useful for every type of OAuth client, even web apps that use a client secret.

As such, PKCE allows the authorization server to validate that the client application exchanging the authorization code is the same client application that requested it, and that the authorization code had not been stolen and injected into a different session. However (and this is the BIG however) PKCE does not provide a replacement for client authentication (since it can’t protect the client’s secret key).

In contrast, the auth code flow provides client authentication (e.g. validation of client ID and secret) which allows the authorization server to validate the client application’s identity, proving that it is allowed to exchange an authorization code for a token.

By authenticating the client application, you prove that the requester is the actual client application known to the authorization server and not a malicious actor trying to impersonate some other client. Without client authentication, you cannot fully verify the application’s identity. Therefore, since PKCE does not provide a replacement for client authentication, backend applications should continue to use client authentication (i.e. including client ID/secret pairs in auth requests) whenever possible, even if using PKCE with a backend application.

Resource Owner Password Grant (ROPG)

Though most identity providers do not recommend using this authentication flow (and it is slated for removal in OAuth 2.1), highly-trusted applications can use the Resource Owner Password Grant (ROPG) flow. This grant type is suitable for clients capable of 1.) protecting a client ID/secret pair and 2.) obtaining the resource owner’s credentials (username and password, typically using an interactive form). ROPG is often used to migrate existing users from one identity stack to another without requiring users to update their passwords.

Implementing this flow shifts much of the responsibility of securing the login page wholly to the application owner, since this method does not redirect the user to the identity provider’s centralized authentication endpoint.

Additionally, since credentials are collected and sent to the application backend there is an inherent risk that credentials can be errantly exfiltrated or insecurely stored prior being exchanged for an Access Token. Because of this, it is imperative that any application utilizing ROPG is absolutely trusted with this information. And even when this condition is met, the ROPG should only be used when redirect-based flows (like the Authorization Code Flow) cannot be used.

Additional considerations when using ROPG

  1. ROPG may cause brute-force protections provided by your identity provider or other edge protections to fail as attack behavior can be hidden within application API calls.
  2. ROPG Flow involves the application handling the user’s password, ROPG must not be used by third-party clients.

Client Credentials Flow

Applications, such as CLIs, daemons, or services running on your back-end require a method for the system authenticate and authorize a non-interactive application, rather than a human user. For this scenario, typical authentication schemes like username + password or social logins don’t make sense. Instead, M2M apps use the Client Credentials Flow (defined in OAuth 2.0 RFC 6749, section 4.4), in which they pass along their Client ID and Client Secret to authenticate themselves and get a token.

Matt Cooper Avatar

Written by

Written by

Matt Cooper Avatar

We Are

The Anti-Fraud Company

Nimble SA is on a mission to help SaaS providers and their customers prevent billions of dollars in fraud losses without compromising on customer experience.

Discover more from The Anti-Fraud Company

Subscribe now to keep reading and get access to the full archive.

Continue reading