mrkeyoor.com_
Sun 20 Sept 02:43 UTC
PyPISecurityupdated 16 Sept 2026

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.

Verdict

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

Lab card: what happened when we installed requests-oauthlibScreenshot of requests-oauthlib documentation
Install✓ · 0.3s7 packages on disk · 4 MB
Importimport requests_oauthlib in 0.63s · pure Python · requires Python >=3.4
Known vulns0(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

API stability4/5OAuth1Session and OAuth2Session have used Requests-shaped calls for years, which makes existing integrations easy to recognize. Version 2.0.0 removed deprecated token helpers and added PKCE without replacing the core session pattern. Provider endpoints, scopes, authentication methods, and response quirks can still change independently, so stable Python method names do not remove the need for provider contract tests.
Docs4/5Read the Docs walks through OAuth 1, authorization code, implicit and legacy flows, client credentials, token refresh, mobile clients, provider examples, compliance hooks, and insecure-transport controls. The examples explain protocol calls but assume the application already handles server-side state, redirect validation, atomic token rotation, and account linking. Those omitted security responsibilities are where copied web-route examples most often fail.
Maintenance2/5The current 2.0.0 release was published on 2024-03-22, GitHub shows the last repository push on 2025-06-18, and 129 open items combine issues with pull requests. A narrow adapter does not need weekly releases, but OAuth provider rules and security guidance continue moving around it. The quiet release line raises the cost of depending on a quick fix for a new provider-specific edge case.
Ecosystem4/5The available weekly snapshot records about 79.6 million PyPI downloads, while GitHub lists 1,775 stars. requests-oauthlib composes two established packages and lets old integrations retain Requests adapters, proxies, certificates, cookies, and timeout handling. New applications increasingly use async clients, discovery, PKCE defaults, and provider SDKs, so high transitive download volume should not decide a greenfield identity architecture.

Discussed on

  1. hnShow HN: My first article: SSO using Flask and selenium8 points

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
Skip it if

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

PackageRegistryPick it when
authlibPyPIUse it when Python 3 OAuth or OIDC work needs discovery, JOSE, and Requests or HTTPX integrations
httpx-oauthPyPIUse it when an asyncio service already standardizes on HTTPX client flows
oauthlibPyPIUse 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.