OAuth and JWT Authentication Basics in Python APIs

Table of Contents

  • Introduction to Authentication
  • What is OAuth?
  • OAuth 2.0 Core Concepts
  • OAuth 2.0 Grant Types
  • What is JWT (JSON Web Token)?
  • JWT Structure Explained
  • How OAuth and JWT Work Together
  • Implementing OAuth with JWT Authentication in Python
  • Common Pitfalls and Best Practices
  • Conclusion

Introduction to Authentication

Authentication is a crucial element in any application that deals with user data or protected resources. In modern web development, two widely used standards for securing APIs and applications are OAuth 2.0 and JWT (JSON Web Token). Together, they create a robust mechanism for managing access control in distributed systems, ensuring security without compromising scalability or developer efficiency.


What is OAuth?

OAuth stands for Open Authorization. It is an open-standard protocol that allows secure authorization in a simple and standardized manner from web, mobile, and desktop applications.

Instead of sharing passwords, OAuth provides access tokens to third-party applications, enabling them to access user resources on a server without exposing user credentials.

In simple terms: OAuth is a delegation protocol — a way to grant limited access to your resources without exposing your credentials.


OAuth 2.0 Core Concepts

OAuth 2.0, the widely adopted version, introduces four critical roles:

  • Resource Owner: Typically the user who owns the data.
  • Client: The application requesting access to the resources.
  • Authorization Server: Verifies the user identity and issues tokens.
  • Resource Server: Hosts the protected resources and validates tokens.

OAuth 2.0 involves two major types of tokens:

  • Access Tokens: Short-lived tokens that grant access to protected resources.
  • Refresh Tokens: Long-lived tokens that allow clients to obtain new access tokens without re-authenticating.

OAuth 2.0 Grant Types

Different use cases require different flows, known as grant types:

  1. Authorization Code Grant:
    Ideal for server-side applications. Redirects users to the authorization server to approve access.
  2. Client Credentials Grant:
    Used when the client itself is the resource owner (typically machine-to-machine communication).
  3. Resource Owner Password Credentials Grant:
    Deprecated for security reasons. User shares credentials directly with the client application.
  4. Implicit Grant:
    Used for single-page applications (SPAs), but largely replaced by Authorization Code Flow with PKCE.
  5. Authorization Code with PKCE (Proof Key for Code Exchange):
    Designed for mobile and public clients, providing enhanced security.

What is JWT (JSON Web Token)?

JWT (JSON Web Token) is a compact, URL-safe token format that represents claims between two parties. It is commonly used in OAuth 2.0 to transmit access tokens securely.

JWT is composed of three parts:

  • Header: Specifies the signing algorithm and token type.
  • Payload: Contains the claims (user information, permissions, expiration, etc.).
  • Signature: Ensures the token’s integrity by signing the header and payload with a secret or private key.

Example of a JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

JWT Structure Explained

  1. Header Example:
{
"alg": "HS256",
"typ": "JWT"
}
  1. Payload Example:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516242622
}
  1. Signature:

Generated by encoding the header and payload and then signing them using a secret key or a private key.

The integrity of the JWT can be verified by recalculating the signature and comparing it with the one provided.


How OAuth and JWT Work Together

In a modern OAuth 2.0 workflow, especially in microservices and distributed architectures, JWT is often used as the format for the OAuth access token.

  • After the user authorizes the client, the authorization server issues an access token, which is a JWT.
  • The client stores this JWT and attaches it to every subsequent request in the Authorization header.
  • The resource server (API) verifies the JWT’s signature and claims before allowing access.

Example of sending a JWT in a request:

GET /protected-resource
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Advantages of using JWTs:

  • Self-Contained: All the necessary information is stored within the token itself.
  • Stateless Authentication: No need to query a database or session store for each request.
  • Compact: JWTs are ideal for passing information through URL, POST parameters, or inside HTTP headers.

Implementing OAuth with JWT Authentication in Python

Let’s set up a simple JWT-based authentication system using FastAPI and PyJWT.

Installation:

pip install fastapi
pip install uvicorn
pip install python-jose[cryptography]

Example FastAPI app with JWT authentication:

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from datetime import datetime, timedelta

SECRET_KEY = "your_secret_key_here"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

def create_access_token(data: dict, expires_delta: timedelta = None):
to_encode = data.copy()
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=15))
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
if form_data.username != "admin" or form_data.password != "secret":
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials")

access_token = create_access_token(data={"sub": form_data.username})
return {"access_token": access_token, "token_type": "bearer"}

@app.get("/protected")
async def read_protected(token: str = Depends(oauth2_scheme)):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username = payload.get("sub")
if username is None:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")
except JWTError:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")

return {"message": f"Hello, {username}"}

This example demonstrates:

  • User submits username/password to /token
  • Server issues JWT as access token
  • Client uses this token to access protected routes

Common Pitfalls and Best Practices

  • Do Not Store Sensitive Data in the Payload: JWT payloads are base64 encoded, not encrypted.
  • Use HTTPS: Always transmit tokens over secure channels.
  • Short Expiry Times: Keep access tokens short-lived; use refresh tokens for longevity.
  • Token Revocation Strategy: Design a method to invalidate tokens (e.g., blacklisting).
  • Rotate Secrets: Change signing keys regularly if feasible.
  • Validate All Claims: Always validate expiration (exp), issuer (iss), and audience (aud) claims if applicable.

Conclusion

Understanding OAuth and JWT authentication is essential for developing secure, scalable APIs. OAuth enables secure authorization delegation, while JWT provides a stateless, compact token mechanism perfect for modern distributed systems.

By mastering these concepts, you can design APIs that not only meet today’s security standards but also deliver seamless user experiences without compromising performance or maintainability.

Syskoolhttps://syskool.com/
Articles are written and edited by the Syskool Staffs.