requests-oauthlib review
requests-oauthlib 2.0.0 connects oauthlib's OAuth protocol code to blocking Requests sessions. OAuth2Session builds authorization URLs, exchanges callbacks, attaches bearer tokens, and can refresh them. OAuth1Session covers request-token, user-authorization, access-token, and signed-resource calls for older OAuth 1 providers. Version 2.0 added PKCE and removed deprecated OAuth 2 helpers. This adapter does not provide identity discovery, browser sessions, account linking, token storage, redirect policy, or authorization rules. Our import worked, but the distribution has no py.typed marker for static type checkers.
requests-oauthlib 2.0.0 installed in 0.3 seconds and used 4 MB across 7 packages in our sandbox, with 0 audit findings and no py.typed marker. Keep it for working synchronous Requests or OAuth 1 integrations; compare Authlib or a provider SDK before starting a new OAuth 2 or OIDC client.
We installed it
| Install | ✓ · 0.3s | 7 packages on disk · 4 MB |
| Import | ✓ | import requests_oauthlib in 0.63s · pure Python · requires Python >=3.4 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does requests-oauthlib install cleanly?
Yes. In a fresh container with an empty cache, pip install requests-oauthlib finished in 0.3s, leaving 7 packages and 4 MB on disk. pip-audit reported no known vulnerabilities.
What does requests-oauthlib need to run?
Python >=3.4, and nothing compiled: it is pure Python. In our run import requests_oauthlib succeeded in 0.63s.
requests-oauthlib or authlib: which should you use?
authlib: Use it when Python 3 OAuth or OIDC work needs discovery, JOSE, and Requests or HTTPX integrations. requests-oauthlib 2.0.0 installed in 0.3 seconds and used 4 MB across 7 packages in our sandbox, with 0 audit findings and no py.typed marker.
When should you not use requests-oauthlib?
A new OAuth 2 or OpenID Connect client needs discovery, JOSE, and more current client-auth options; compare Authlib
Discussed on
Use it if
- A synchronous Requests integration needs OAuth 1 signatures or OAuth 2 bearer-token handling
- An authorization-code client can securely retain state, the PKCE verifier, and all token fields across redirects
- Existing provider code already depends on oauthlib compliance hooks and Requests adapters
- A client-credentials service has a defined secret store, scope policy, and token-refresh path
- A new OAuth 2 or OpenID Connect client needs discovery, JOSE, and more current client-auth options; compare Authlib
- The service is asyncio-first and uses HTTPX; httpx-oauth avoids blocking Requests calls
- A provider SDK already owns token caching and account-specific behavior that generic sessions leave to your code
- Login security is being delegated to the package; the application must still verify state, restrict redirects, and define account linking
- Rapid OAuth guidance updates are essential; version 2.0.0 dates to 2024 and the repository's last push was in 2025
Setup reality
We installed requests-oauthlib 2.0.0 in 0.3 seconds under Python 3.12. It left 7 packages consuming 4 MB, declared 3 direct dependencies, and pip-audit found 0 known vulnerabilities. import requests_oauthlib completed in 0.63 seconds. The code is pure Python, accepts Python 3.4+, uses the ISC license, and does not include py.typed. Our How we test run also confirms that its network behavior remains the blocking Requests model.
An authorization-code login spans at least 2 browser-facing requests. Save state and, with PKCE, the verifier in server-side storage tied to the initiating session. Recreate OAuth2Session with that exact state before fetch_token processes the callback. Keep redirect URIs on an allowlist and use HTTPS outside local development. oauthlib refuses insecure transport unless its development escape setting is enabled, which must never leak into a deployed process.
Automatic refresh needs the existing token, refresh endpoint, client parameters, and a token_updater that writes the complete replacement. A provider can rotate the refresh token, so saving only access_token may break the next refresh. Two workers can refresh the same credential concurrently and overwrite newer data. Serialize that path or use compare-and-swap storage keyed by a token version, then attach a timeout to every protected-resource call.
Provider differences still reach application code: scope separators, token placement, client authentication, and unusual responses are not identical. Compliance hooks cover named services, but weakening checks globally to satisfy 1 provider can affect every request on that session. requests-oauthlib 2.0.0 installs cleanly, yet its 129 open GitHub items and 2025 last push make Authlib or a provider SDK worth testing before a new long-lived OAuth 2 integration.
Patterns
Create an authorization URL start-authorization-flow
from requests_oauthlib import OAuth2Session
oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=['read'])
url, state = oauth.authorization_url(authorize_url)
session['oauth_state'] = state
return redirect(url)Store state on the server and bind it to the initiating browser. Compare that value during the callback to stop login CSRF.
Fetch a token from the callback exchange-callback-code
oauth = OAuth2Session(
client_id,
redirect_uri=redirect_uri,
state=session.pop('oauth_state'),
)
token = oauth.fetch_token(
token_url,
authorization_response=request.url,
client_secret=client_secret,
)Persist every returned field, including expiry and refresh_token. Use only the registered HTTPS callback outside local testing.
Add PKCE to authorization code enable-pkce
oauth = OAuth2Session(
client_id,
redirect_uri=redirect_uri,
scope=['read'],
pkce='S256',
)
url, state = oauth.authorization_url(authorize_url)Version 2.0.0 supports PKCE. Preserve both state and the generated verifier until the callback exchange completes.
Call an API with a stored token request-protected-resource
oauth = OAuth2Session(client_id, token=stored_token)
response = oauth.get('https://api.example/v1/me', timeout=10)
response.raise_for_status()
data = response.json()OAuth2Session remains a Requests session. Set a timeout because Requests otherwise waits without a deadline.
Save a rotated token atomically persist-token-refresh
def save_token(token):
token_store.compare_and_swap(account_id, stored_version, token)
oauth = OAuth2Session(
client_id, token=stored_token,
auto_refresh_url=token_url,
auto_refresh_kwargs={'client_id': client_id, 'client_secret': client_secret},
token_updater=save_token,
)A provider may rotate the refresh token. Persist the complete replacement and prevent 2 workers from overwriting each other.
Use client credentials for service access fetch-client-token
from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session
backend = BackendApplicationClient(client_id=client_id)
oauth = OAuth2Session(client=backend)
token = oauth.fetch_token(token_url=token_url, client_id=client_id, client_secret=client_secret)This grant authenticates the application rather than a person. Assign only scopes intended for that service identity.
Send an OAuth 1 request sign-oauth1-call
from requests_oauthlib import OAuth1Session
oauth = OAuth1Session(
client_key, client_secret=client_secret,
resource_owner_key=access_token,
resource_owner_secret=access_secret,
)
response = oauth.get(resource_url, timeout=10)OAuth 1 signatures include a timestamp and nonce. Check the host clock when a provider rejects an otherwise valid signature.
Permit a local HTTP callback allow-development-http
import os
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'Use this in an isolated local process only. Leaving it enabled removes an HTTPS guard around live credentials and tokens.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| authlib | PyPI | Use it when Python 3 OAuth or OIDC work needs discovery, JOSE, and Requests or HTTPX integrations |
| httpx-oauth | PyPI | Use it when an asyncio service already standardizes on HTTPX client flows |
| oauthlib | PyPI | Use the protocol implementation directly when a Requests session is the wrong transport abstraction |
More security guides
cryptography · pyjwt · jose · dompurify · jsonwebtoken · oauthlib · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

