OAuth 2.0 Implicit Flow Is Deprecated – Switch to Authorization Code
The OAuth 2.0 Implicit Flow is deprecated because it exposes tokens in URLs and lacks robust revocation. Use the Authorization Code Flow with PKCE for secure, production‑ready authentication.
Focus: OAuth 2.0 implicit flow
OAuth 2.0 Implicit Flow: What It Was, Why It’s Deprecated, and What to Use Instead
Overview of OAuth 2.0 Implicit Flow
The OAuth 2.0 Implicit Flow was designed for client‑side applications that cannot securely store a client secret, such as single‑page web apps (SPAs) or mobile apps. Instead of exchanging a short‑lived authorization code for an access token, the flow returns an access token (and optionally a refresh token) directly from the authorization server in the same HTTP request that delivers the user to the client. The token is placed in the URL fragment (the part after #) so that it never appears in the web server logs, but it is still exposed to any script that can read the fragment.
Typical sequence:
- The client redirects the user’s browser to the authorization endpoint with required scopes and a
redirect_uri. - The user authenticates and consents.
- The authorization server redirects back to the
redirect_uriwith the access token embedded in the fragment. - The client reads the fragment, extracts the token, and uses it to call protected resources.
Because the token is delivered via the URL fragment, the client can obtain it without a separate token endpoint, making the flow simple for pure JavaScript environments.
How the Implicit Flow Works (Step‑by‑step)
1. Initiate Authorization Request
GET /authorize?response_type=token&client_id=APP_ID&redirect_uri=https%3A%2F%/myapp.com%2Fcallback&scope=read+write&state=xyz
Host: auth.example.comresponse_type=tokentells the server to return an access token directly.stateis a random value used to mitigate CSRF attacks.
2. User Authorization
The user sees a login screen, logs in, and grants consent.
3. Redirect with Token
The server redirects to the redirect_uri with the token in the fragment:
GET /myapp.com/callback
#access_token=ABC123&token_type=bearer&expires_in=3600&state=xyzThe fragment is not sent to the server, so the token stays client‑side.
4. Token Consumption
The SPA reads the fragment, parses the token, and stores it (e.g., in memory or localStorage). It then includes the token as a Bearer token in the Authorization header when calling APIs.
Real‑World Example (Python Simulation)
Below is a minimal Python script that demonstrates the flow using the popular requests library and the authlib OAuth 2.0 client helper. This example assumes you have a test authorization server that supports the implicit flow (e.g., https://demo.identityserver.io/). Replace placeholders with real values for a hands‑on test.
import requests
from authlib.integrations.requests_client import OAuth2Client
import urllib.parse
# Configuration – replace with your own values
AUTH_URL = "https://demo.identityserver.io/connect/authorize"
TOKEN_URL = "https://demo.identityserver.io/connect/token"
CLIENT_ID = "client_id_1"
REDIRECT_URI = "http://localhost:8080/callback"
SCOPES = ["api1.read", "api1.write"]
STATE = "random_state_123"
# 1. Build the authorization request URL
params = {
"response_type": "token",
"client_id": CLIENT_ID,
"redirect_uri": REDIRECT_URI,
"scope": " ".join(SCOPES),
"state": STATE,
}
auth_url = f"{AUTH_URL}?{urllib.parse.urlencode(params)}"
print("Visit this URL and log in:")
print(auth_url)
# In a real app the user would open a browser, grant consent, and be redirected.
# For demonstration, we simulate the redirect by parsing a mock fragment.
mock_fragment = "#access_token=abcd1234&token_type=bearer&expires_in=3600&state=xyz"
fragment_data = urllib.parse.parse_qs(urllib.parse.urlparse(mock_fragment).fragment)
access_token = fragment_data["access_token"][0]
print(f"\nExtracted access token: {access_token}")
# 2. Use the token to call a protected resource
api_endpoint = "https://demo.identityserver.io/connect/resource"
headers = {"Authorization": f"Bearer {access_token}"}
api_response = requests.get(api_endpoint, headers=headers)
print(f"\nAPI response status: {api_response.status_code}")
print(api_response.text)What this script shows
- How to construct the authorization URL with
response_type=token. - How a client would parse the fragment after the redirect.
- How to use the obtained token to call a protected API.
The code is intentionally simple; in production you would handle errors, token expiration, and secure storage.
Why It Is Deprecated
1. Token Exposure in URL Fragment
Even though the fragment is not sent to the server, any script running on the page can read it. Malicious extensions, compromised browsers, or leaked screenshots can capture the token, leading to token theft. Modern browsers also limit the ability to read fragments from cross‑origin iframes, making the flow fragile.
2. Lack of Token Revocation
Because the token is issued directly and often lives for a relatively long time, revoking it becomes difficult. The client cannot ask the server to invalidate a token that it already holds in memory.
3. Poor Support for Refresh Tokens
The implicit flow historically returns only a short‑lived access token. Refreshing the token requires a separate request that may expose the token again, defeating the purpose of a secure refresh mechanism.
4. Better Alternatives Exist
The industry has converged on the Authorization Code Flow with PKCE (Proof Key for Code Exchange). This flow works for native mobile apps, SPA back‑ends, and even server‑less environments, while keeping the token out of URLs and providing a robust refresh mechanism.
Modern Alternatives
Authorization Code Flow with PKCE
PKCE adds a cryptographic verifier that the client generates and sends in the authorization request. The server returns a code, which the client exchanges for tokens using the same verifier. This eliminates the need for a client secret and mitigates authorization code interception attacks.
Key advantages
- Tokens are never placed in the URL fragment; they are returned via a secure POST to a token endpoint.
- Refresh tokens can be issued, allowing long‑term sessions without re‑authenticating.
- The flow works equally well for SPAs (via a backend that handles the code exchange) and native mobile apps.
Hybrid Flow (Code + Implicit)
Some providers still support a hybrid where the authorization code is exchanged for an ID token and an access token in the same request. While this reduces the number of round‑trips, it still inherits the security drawbacks of the implicit flow and is generally discouraged.
Device Authorization Grant (Device Code Flow)
For devices without a browser (IoT, CLI tools), the device code flow is the recommended path. It separates user interaction from the device, keeping tokens out of any UI‑exposed location.
Practical Implementation Guide (Migrating from Implicit to Authorization Code + PKCE)
Below is a step‑by‑step guide for a typical SPA that wants to move away from the implicit flow.
1. Register the SPA
- Add the SPA’s
redirect_uri(e.g.,http://localhost:8080/callback) to the client registration. - Choose the scopes you need.
- No client secret is required for pure SPAs.
2. Generate PKCE Values (Python Example)
import secrets
import base64
import hashlib
def generate_pkce_codes():
code_verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).decode('utf-8')
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode('utf-8')).digest()
).decode('utf-8').rstrip('=')
return code_verifier, code_challenge
code_verifier, code_challenge = generate_pkce_codes()
print("PKCE code verifier:", code_verifier)
print("PKCE code challenge:", code_challenge)3. Build the Authorization Request
GET /authorize?response_type=code&client_id=APP_ID&redirect_uri=https%3A%2F%/myapp.com%2Fcallback&scope=api1.read+api1.write&state=xyz&code_challenge=XYZ&code_challenge_method=S256response_type=codetells the server to return an authorization code, not a token.code_challengeandcode_challenge_method=S256convey the PKCE data.
4. Handle the Redirect and Exchange the Code
After the user authorizes, the server redirects to http://localhost:8080/callback?code=AUTH_CODE&state=xyz. The SPA (or a lightweight backend) then makes a POST request to the token endpoint:
import requests
import urllib.parse
def exchange_code_for_tokens(code, redirect_uri, code_verifier):
token_url = "https://auth.example.com/connect/token"
data = {
"grant_type": "authorization_code",
"code": code,
"redirect_uri": redirect_uri,
"client_id": CLIENT_ID,
"code_verifier": code_verifier,
}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(token_url, data=data, headers=headers)
response.raise_for_status()
return response.json() # contains access_token, id_token, refresh_token, expires_in
tokens = exchange_code_for_tokens(
code="AUTH_CODE_FROM_REDIRECT",
redirect_uri="http://localhost:8080/callback",
code_verifier=code_verifier,
)
print(tokens)5. Store Tokens Securely
- Store
access_tokenandrefresh_tokenin memory or in a secure HTTP‑only cookie. - Use the
refresh_tokento request a new access token when the current one expires, without user interaction.
6. Refresh Tokens (Optional)
When the access token expires, make a request:
def refresh_access_token(refresh_token, client_id):
token_url = "https://auth.example.com/connect/token"
data = {
"grant_type": "refresh_token",
"refresh_token": refresh_token,
"client_id": client_id,
}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
resp = requests.post(token_url, data=data, headers=headers)
resp.raise_for_status()
return resp.json()Summary
The OAuth 2.0 Implicit Flow was a convenient way for client‑side apps to obtain an access token directly from the authorization server. However, its reliance on URL fragments, weak token revocation, and limited refresh capabilities make it insecure for modern applications. The industry now recommends the Authorization Code Flow with PKCE for SPAs and native apps, and the Device Authorization Grant for devices without a browser. Migrating is straightforward: generate PKCE values, request a code instead of a token, exchange the code securely, and use refresh tokens for long‑term sessions. By adopting these newer patterns, developers gain stronger security, better token management, and full compatibility with current OAuth 2.0 best practices.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.