OAuth2 Integration in Python — Core Concepts
What problem OAuth2 solves
Before OAuth, if an app needed access to your data on another service, you’d give it your username and password for that service. The app stored your credentials, had full access, and you couldn’t limit what it did. If the app got hacked, your password was exposed.
OAuth2 replaces this with a delegated authorization system. Users grant specific, limited permissions. Apps receive tokens instead of passwords. Permissions can be revoked without changing passwords.
The four roles
OAuth2 defines four participants in every flow:
Resource Owner — the user who owns the data (you).
Client — the application requesting access (your Python app).
Authorization Server — the service that authenticates the user and issues tokens (Google’s auth server, GitHub’s auth server).
Resource Server — the API holding the protected data (Google’s API, GitHub’s API). Often runs on the same infrastructure as the authorization server.
The Authorization Code flow
This is the most common flow for web applications and the most secure:
- Your app redirects the user to the authorization server with your app’s client ID, requested permissions (scopes), and a redirect URL.
- The user logs in directly with the authorization server and approves the requested scopes.
- The authorization server redirects back to your app with a short-lived authorization code.
- Your app exchanges that code (plus your client secret) for an access token and optionally a refresh token.
- Your app uses the access token to call APIs on behalf of the user.
The code-to-token exchange happens server-to-server, so the access token never passes through the user’s browser.
Scopes define boundaries
Scopes are strings that specify what the token can access. Google uses scopes like email, profile, and https://www.googleapis.com/auth/drive.readonly. GitHub uses read:user, repo, gist.
Always request the minimum scopes your app actually needs. Users are more likely to approve narrow requests, and if the token is compromised, the damage is limited.
Grant types beyond Authorization Code
Client Credentials — for machine-to-machine communication where no user is involved. The app authenticates directly with its own credentials and gets a token. Used for backend services calling other backend services.
Device Code — for devices without browsers, like smart TVs or CLI tools. The device shows a code; the user visits a URL on their phone to authorize.
Refresh Token — not a standalone grant, but a mechanism. When the access token expires, the app uses the refresh token to get a new one without bothering the user again.
The “Implicit” grant and “Resource Owner Password” grant exist in older specs but are now discouraged due to security weaknesses. Modern apps should use Authorization Code with PKCE instead.
PKCE: protecting public clients
Single-page apps and mobile apps can’t safely store a client secret. PKCE (Proof Key for Code Exchange) adds security without needing one. The client generates a random code verifier, sends a hash of it (code challenge) in the initial request, and sends the original verifier when exchanging the code. The server checks that they match. This prevents an attacker who intercepts the authorization code from exchanging it.
Common misconception
OAuth2 is often called an “authentication” protocol. It’s actually an authorization protocol — it grants access to resources. OpenID Connect (OIDC) is a layer on top of OAuth2 that adds authentication, providing a standardized way to verify who the user is (via an ID token). When you implement “Sign in with Google,” you’re using OIDC, which builds on OAuth2.
Python ecosystem
The authlib library provides both client and server OAuth2 implementations. For simpler client-side needs, requests-oauthlib extends the popular requests library with OAuth2 support. Web frameworks have their own integrations: python-social-auth for Django, authlib integrations for Flask and FastAPI.
The one thing to remember: OAuth2 separates who the user is from what an app can do, using tokens with limited scope instead of shared passwords — and Python has mature libraries that handle the complex redirect-and-exchange flow for you.
See Also
- Python Api Key Management Why apps use special passwords called API keys, and how to keep them safe — explained with a library card analogy
- Python Attribute Based Access Control How apps make fine-grained permission decisions based on who you are, what you're accessing, and the circumstances — explained with an airport analogy
- Python Audit Logging Learn Audit Logging with a clear mental model so your Python code is easier to trust and maintain.
- Python Bandit Security Scanning Why Bandit Security Scanning helps Python teams catch painful mistakes early without slowing daily development.
- Python Clickjacking Prevention How invisible website layers trick you into clicking the wrong thing, and how Python apps stop it