Skip to content

OAuth 2.0 Flow for APIs — Complete Authorization Guide

DodaTech Updated 2026-06-28 4 min read

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

  1. What is the difference between authorization code and implicit grant?
  2. Why is the state parameter important?
  3. What is the client credentials grant used for?
  4. How does PKCE improve OAuth security?
  5. 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

Is OAuth 2.0 an authentication protocol?

No. OAuth 2.0 is for authorization. For authentication on top of OAuth, use OpenID Connect which adds an ID token.

What is the difference between OAuth 1.0 and 2.0?

OAuth 1.0 used cryptographic signatures on every request. OAuth 2.0 uses bearer tokens over TLS, which is simpler but requires HTTPS.

Can I use OAuth without a browser?

Yes. Use device authorization grant for devices without browsers (smart TVs, CLI tools, IoT devices).

What is a refresh token?

A long-lived token used to obtain new access tokens without user interaction. Store securely and rotate on use.

How do I handle token expiration in OAuth?

Use refresh tokens to silently obtain new access tokens. If the refresh token expires, redirect the user to re-authenticate.

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