OAuth 2.0 Implicit Flow

April 02, 2023

Note On Terminology

Client-side applications are generally considered less secure at storing sensitive information like client secrets.

In the case of SPAs, the source code is accessible, and if a device is shared between users, developer tools make it easy to find secrets stored in the browser. They can be vulnerable to XSS attacks, allowing malicious scripts access to browser storage.

Mobile apps, while often running on platforms that do offer some mechanisms for secure storage, are still vulnerable when faced with a determined attacker armed with reverse-engineering and debugging tools. Here’s a comprehensive explanation.

OAuth 2.0 has two flows designed specifically for client-side applications, Implicit Flow and Authorization Code Flow with PKCE. Implicit Flow is regarded as an insecure implementation, and has been largely superseded by the more secure Authorization Code Flow with PKCE.

However let’s briefly examine Implicit Flow’s implementation and it’s vulnerabilities, then show how Authorization Code Flow with PKCE improves on it.

1) App Registration

As with standard Authorization Code Flow, the app is registered with the Service Provider, including a unique client_id and a redirect_uri that the Authorization Server will direct the user to after authorization.

The Client App’s domain - implicitflow.demoapp.com

client_id - ImplicitFlow_DemoApp

redirect_uri - https://implicitflow.demoapp.com/callback

The Authorization Server’s authorization endpoint - https://auth.service.com/authorize

2) User Authorization Request

To authorize the Client App, the app constructs a URL pointing to the Authorization Server, along with the query parameters:

client_id - ImplicitFlow_DemoApp

scope - The list of permissions the Client App is asking the user to authorize. As before, “profile” is all our demo app requires

redirect_uri - The redirect URI setup in the app registration, https://implicitflow.demoapp.com/callback, encoded as a URL parameter

state - A random string value generated by the Client App specifically for the authorization request. As with the Authorization Code Flow, the state value is used to protect against CSRF attacks. To ensure uniqueness and be unguessable, it should be generated with a CSRNG

We’ll keep using ‘OurOAuth2StateString’ as our dummy state string.

response_type - Always set to ‘token’ (indicating the Client App wants to receive the Access Token directly)

When the user wishes to authorize the Client App, this URL is opened in a new tab sending the authorization request as a GET request to the Authorization Server:

https://auth.service.com/authorize?response_type=token&client_id=ImplicitFlow_DemoApp&scope=profile&state=OurOAuth2StateString&redirect_uri=https%3A%2F%2Fimplicitflow.demoapp.com%2Fcallback

In the new tab displaying the Authorization Server’s authentication screen, the user authenticates with their credentials and authorizes the app with its requested permissions (defined in the scope query parameter).

3) Access Token Returned

After the user has granted authorization, the user is redirected back to the Client App via the redirect_uri.

The Access Token, along with the standard OAuth token parameters such as expiry time, are included in the URL as part of the URL fragment:

https://implicitflow.demoapp.com/callback#access_token=Acc3ssT0ken&token_type=Bearer&expires_in=3600&state=OurOAuth2StateString

The Access Token and other parameters are sent as a URL fragment (everything after the #) because URL fragments aren’t sent to the server supporting the SPA. Even if our server does nothing except return SPA application code, it still may log or monitor requests, so the URL fragment prevents the sensitive data being recorded in these logs.

Since URL fragments aren’t sent to servers, they also avoid being cached by the browser. However they are still recorded in browser history, as discussed below.

4) Accessing Protected Resources

The SPA extracts the Access Token and other relevant parameters from the URL and stores them in the browser, whether in memory, sessionStorage or localStorage.

As with other flows, now the Access Token is granted, the SPA can make requests for protected resources from the Service Provider by including the header:

Authorization: Bearer Acc3ssT0ken 

Specific Implicit Flow vulnerabilities

1) URL exposure

With Access Tokens included in the URL, they will be visible in browser history, as well as accessible to any javascript running on the callback page, making them vulnerable to access through XSS attacks.

2) Lack of refresh mechanism

Implicit Flow does not implement any refresh mechanism and doesn’t provide refresh tokens.

To avoid frequent user re-authorization, the token must be long-lived and stored in browser localStorage. LocalStorage has benefit of being inaccessible to external processes. However as the data stored is persistent, there is a larger window of opportunity for malicious code - whether through an XSS attack or a device compromised by a malicious user - to access sensitive data such as the Access Token.

If tokens are short-lived, frequent user authorization requests are needed, and instead this could provide a greater opportunity for request interception (i.e. a man-in-the-middle attack).

Requiring users to frequently re-authenticate and re-authorize is also detrimental to user experience, especially when the authentication process involves MFA, for example.

3) Redirect URL Interception

With the Access Token fully exposed in the post-authorization redirection URL, it provides a significant attack vector independent from the underlying Implicit Flow process, making potential exploits difficult to predict and defend against.

For example, on older Android and iOS operating systems, a vulnerability existed where multiple apps could be registered to handle the same custom URL scheme e.g. mycustomapp://. A malicious app could in some circumstances intercept a redirection using a scheme intended for a legitimate app, accessing any data in the URL.

Deprecation

Due to its inherent vulnerabilities, OAuth 2.0 Implicit Flow has been deprecated, although it is still supported by many Service Providers, including Spotify and Microsoft Identity Platform.

Instead Authorization Code Flow with PKCE is now the recommended standard for applications that cannot securely store a client secret.

Applications implementing Authorization Code Flow with PKCE avoid or mitigate the inherent vulnerabilities of Implicit Flow.

Web Security series

1) Common Browser Security Concepts 2) Cookies - A guide for developers 3) HTTP Basic Access Authentication 4) Maintaining Authentication State with Session Cookies 5) JWT Essentials 6) OAuth 1.0 7) OAuth 2.0 Overview 8) OAuth 2.0 Authorization Code Flow 9) OAuth 2.0 Implicit Flow 10) OAuth 2.0 Authorization Code Flow with PKCE 11) OAuth 2.0 Device Authorization Flow 12) OpenID Connect - OAuth 2.0 with Authentication