OAuth 2.0 Flow for APIs — Complete Authorization Guide
In this tutorial, you will learn about OAuth 2.0 Flow for APIs. We cover key concepts, practical examples, and best practices to help you master this topic.
OAuth 2.0 is an authorization framework that allows third-party applications to obtain limited access to a user's resources without exposing their credentials. It uses access tokens issued by an authorization server.
What You'll Learn
You'll learn the OAuth 2.0 grant types, authorization code flow, client credentials flow, and how to implement OAuth for your API.
Why It Matters
OAuth 2.0 is the industry standard for API authorization, used by Google, Facebook, GitHub, and most major platforms. Building your own authorization scheme is risky and non-interoperable.
Real-World Use
A mobile note-taking app uses OAuth 2.0 to access a user's Google Drive files. The user grants permission once, and the app receives a token to read specific files without ever seeing the user's Google password.
sequenceDiagram
participant User
participant App as Client App
participant Auth as Authorization Server
participant API as Resource Server
User->>App: Click "Login with Provider"
App->>Auth: Authorization Request (client_id, redirect_uri, scope)
Auth->>User: Authenticate & Consent
User->>Auth: Grant Permission
Auth->>App: Authorization Code (redirect_uri)
App->>Auth: Exchange Code (code, client_secret)
Auth->>App: Access Token + Refresh Token
App->>API: API Request (Bearer token)
API->>Auth: Validate Token
Auth-->>API: Token Valid
API->>App: Response Data
App->>User: Display Data
Teacher's Mindset
OAuth 2.0 is like a hotel key card system. You check in at the front desk (authorization server), get a key card (token) that opens only your room for a limited time, without giving the staff your house keys.
Authorization Code Flow Implementation
from flask import Flask, request, jsonify
import requests
import secrets
app = Flask(__name__)
CLIENT_ID = "your-client-id"
CLIENT_SECRET = "your-client-secret"
REDIRECT_URI = "https://app.example.com/callback"
@app.route("/auth/login")
def login():
state = secrets.token_urlsafe(32)
auth_url = (
f"https://auth.example.com/authorize?"
f"response_type=code&client_id={CLIENT_ID}"
f"&redirect_uri={REDIRECT_URI}&scope=openid%20profile"
f"&state={state}"
)
return jsonify({"auth_url": auth_url, "state": state})
@app.route("/auth/callback")
def callback():
code = request.args.get("code")
state = request.args.get("state")
token_response = requests.post(
"https://auth.example.com/token",
data={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
},
headers={"Content-Type": "application/x-www-form-urlencoded"}
)
return jsonify(token_response.json())
# Client credentials flow (server-to-server)
def get_client_credentials_token():
response = requests.post(
"https://auth.example.com/token",
data={
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"scope": "api:read api:write"
},
headers={"Content-Type": "application/x-www-form-urlencoded"}
)
return response.json()["access_token"]
def call_protected_api(token):
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(
"https://api.example.com/data",
headers=headers
)
return response.json()
# Resource server token validation
import jwt
import requests
JWKS_URL = "https://auth.example.com/.well-known/jwks.json"
def get_public_key(kid):
jwks = requests.get(JWKS_URL).json()
for key in jwks["keys"]:
if key["kid"] == kid:
from jwt import PyJWK
return PyJWK(key).key
raise ValueError("Key not found")
def validate_bearer_token(token):
header = jwt.get_unverified_header(token)
public_key = get_public_key(header["kid"])
payload = jwt.decode(
token,
public_key,
algorithms=["RS256"],
audience="https://api.example.com"
)
return payload
Common Mistakes
| Mistake | Why It's Wrong | Fix |
|---|---|---|
| Missing state parameter | Vulnerable to CSRF on the callback | Generate and validate a random state value |
| Exposing client_secret in mobile apps | Reverse engineering reveals the secret | Use PKCE (Proof Key for Code Exchange) |
| Not validating redirect_uri | Open redirect vulnerability | Whitelist exact redirect URIs |
| Using implicit grant (deprecated) | Token in URL fragment, less secure | Use authorization code flow with PKCE |
| Storing tokens insecurely | Token theft leads to account access | Store in secure HTTP-only cookies or secure storage |
Practice Questions
- What is the difference between authorization code and implicit grant?
- Why is the state parameter important?
- What is the client credentials grant used for?
- How does PKCE improve OAuth security?
- What is a bearer token?
Challenge
Implement the authorization code flow with PKCE. Create a simple client that initiates login, receives the callback, exchanges the code for a token, and calls a protected API endpoint.
FAQ
Mini Project
Set up a complete OAuth 2.0 system with an authorization server (using Flask) and a resource server. Support authorization code and client credentials grants. Include token introspection.
What's Next
Learn about Openid Connect to understand how OAuth 2.0 is extended for authentication.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro