Understanding OAuth 2 Authentication in HTTP Requests and Implementation in FastAPI

This article will briefly introduce what OAuth 2 authentication in HTTP requests is and how to use OAuth 2 in FastAPI.

Welcome to follow my public account NLP Journey of Wonders, where original technical articles are pushed at the first time.

Welcome to follow my knowledge planet Journey of Natural Language Processing, where I am working hard to build my own technical community.

Understanding OAuth 2 Authentication in HTTP Requests and Implementation in FastAPI

Introduction

In our daily lives, we often need to log in to a website or app, and in such scenarios, the website or app may also support logging in with third-party application accounts, such as WeChat, Google, GitHub, etc.

So, how does the website or app implement login using third-party application accounts? This commonly used authorization method is OAuth 2 in HTTP requests.

How should we understand OAuth 2 authentication?

What is OAuth 2?

In the internet, there are often situations like this:

👉 You are in A application (like a third-party app) wanting to access data from B service (like WeChat, GitHub, Google).

However, the data from B service requires login permissions. Should you give your account password to A application? (Very unsafe ❌)

Thus, the OAuth2 protocol was created, which allows:

  • • Users do not have to tell their passwords to third-party applications
  • • Still allows third-party applications to access some protected data (with limited scope)

Core Roles

There are four main roles in OAuth2:

  1. 1. Resource Owner → User (you)
  2. 2. Client → Third-party application (like the app you are using)
  3. 3. Authorization Server → The server that issues “tokens” (like Google’s authorization system)
  4. 4. Resource Server → The actual place where data is stored (like Google Drive API)

Basic Flow (Using Authorization Code Flow as an Example)

The most common mode is Authorization Code Flow, with the following steps:

  1. 1. User Requests Authorization

    A application redirects you to B service’s authorization page (for example, Google login page).

  2. 2. User Grants Authorization

    You log in to B service and click “Allow A application to access my data (like email)”.

  3. 3. B Service Issues Authorization Code

    B service gives A application a temporary authorization code (not the final token yet).

  4. 4. A Application Exchanges for Token

    A application uses this authorization code + its own identity (client_id & client_secret) to request an Access Token from B service’s Authorization Server.

  5. 5. Use Token to Access Resources

    A application uses the Access Token to access B service’s API and can retrieve the data.

Key Points

  • • Access Token: Similar to a one-time “ticket”, has a limited period, needs to be refreshed after expiration
  • • Refresh Token: Can be used to request a new Access Token (without asking the user again)
  • • Scopes: Limits the range of data that third-party applications can access (for example, read-only emails, not delete emails)

In the basic flow of OAuth 2 mentioned above, the authorization code is one of the authorization methods. In fact, OAuth 2 has four basic authorization methods: authorization code, implicit, password, and client credentials.

In summary, OAuth 2 is an “authorization mechanism that replaces passwords”: users do not need to give their passwords to third-party applications but control access to resources through “tokens” that define the scope and duration of access.

Implementing OAuth 2 in FastAPI

Using GitHub as the third-party application for authorization, we will implement OAuth 2 authorization authentication in FastAPI.

First, you need to create an OAuth application on the GitHub official website to obtain the client ID and client secret.

Below is the Python code for implementing OAuth 2 authorization authentication in FastAPI:

# Using GitHub OAuth for authentication
import os
from fastapi import FastAPI, Depends
from fastapi.responses import RedirectResponse
from fastapi.security import OAuth2PasswordBearer
import httpx
from dotenv import load_dotenv
import uvicorn

load_dotenv()

app = FastAPI()

# GitHub OAuth configuration
CLIENT_ID = os.getenv("GITHUB_CLIENT_ID")
CLIENT_SECRET = os.getenv("GITHUB_CLIENT_SECRET")
AUTH_URL = "https://github.com/login/oauth/authorize"
TOKEN_URL = "https://github.com/login/oauth/access_token"
USER_API_URL = "https://api.github.com/user"

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@app.get("/")
async def root():
    return {"message": "Hello! Visit /login to authenticate with GitHub."}

@app.get("/login")
async def login():
    """Redirect to GitHub authorization page"""
    redirect_uri = "http://localhost:8000/auth/callback"
    return RedirectResponse(
        url=f"{AUTH_URL}?client_id={CLIENT_ID}&redirect_uri={redirect_uri}&scope=read:user"
    )

@app.get("/auth/callback")
async def auth_callback(code: str):
    """GitHub callback, exchange token and get user information"""
    async with httpx.AsyncClient() as client:
        # 1. Exchange code for access_token
        token_res = await client.post(
            TOKEN_URL,
            data={
                "client_id": CLIENT_ID,
                "client_secret": CLIENT_SECRET,
                "code": code
            },
            headers={"Accept": "application/json"}
        )
        token_data = token_res.json()
        access_token = token_data.get("access_token")

        if not access_token:
            return {"error": "Failed to get access token", "details": token_data}

        # 2. Use access_token to get user information
        user_res = await client.get(
            USER_API_URL,
            headers={"Authorization": f"token {access_token}"}
        )
        user_data = user_res.json()

    # Here you can create JWT or session
    return {
        "access_token": access_token,
        "github_user": user_data
    }

# Example of a protected interface (using token)
@app.get("/me")
async def me(token: str = Depends(oauth2_scheme)):
    """Get name and location using GitHub access_token"""
    async with httpx.AsyncClient() as client:
        user_res = await client.get(
            USER_API_URL,
            headers={"Authorization": f"token {token}"}
        )
        user_data = user_res.json()

    return {
        "name": user_data.get("name"),
        "location": user_data.get("location")
    }


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

Start the web service, enter http://localhost:8000/login in the browser to obtain the access_token and complete the OAuth 2 authentication.

Next, you can use the request header with the token to successfully complete the /me interface. The curl command and result are as follows:

-> % curl --location 'http://localhost:8000/me' \
--header 'Authorization:Bearer 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' | jq .

{
  "name": "Jclian",
  "location": "Shanghai"
}

Conclusion

This article briefly introduced what OAuth 2 authorization in HTTP requests is and how to implement OAuth 2 authorization in FastAPI.

Reference Websites

  1. 1. A Simple Explanation of OAuth 2.0: https://www.ruanyifeng.com/blog/2019/04/oauth_design.html
  2. 2. GitHub OAuth Third-party Login Example Tutorial: https://www.ruanyifeng.com/blog/2019/04/github-oauth.html
  3. 3. HTTP Request Authentication with JWT

Leave a Comment