# OAuthLib: the signing logic underneath Python's OAuth stack

> A framework that implements OAuth1 and OAuth2 without assuming your HTTP library, sitting under django-oauth-toolkit, Flask-Dance, requests-oauthlib and a dozen others. Its own docs admit they are sparse.

**oauthlib/oauthlib** — A generic, spec-compliant, thorough implementation of the OAuth request-signing logic

- Repository: https://github.com/oauthlib/oauthlib
- Website: https://oauthlib.readthedocs.io/en/latest/
- Stars: 2,984 · Forks: 534
- Language: Python
- License: BSD-3-Clause
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/oauthlib-oauthlib

## A signing layer, not an HTTP client

The project describes itself as a generic, spec-compliant, thorough implementation of the OAuth request-signing logic, and that phrase sets the scope precisely. It is not an HTTP client and not a web framework. It implements the logic of OAuth1 or OAuth2 without assuming a specific HTTP request object or web framework, and the stated use is grafting OAuth client support onto your favourite HTTP library, or providing OAuth support onto your favourite web framework.

The reason that design exists is stated as a criticism of other libraries. OAuthLib's README says several prominent libraries for handling OAuth requests suffer from one or more of three problems: they predate the OAuth 1.0 specification (RFC 5849), they predate the OAuth 2.0 specification (RFC 6749), or they assume the use of a specific HTTP request library.

Those are the three things to check when you evaluate any OAuth library, including this one. The last one is the reason `requests-oauthlib` exists as a separate package: if you use `requests`, that is the wrapper, and OAuthLib is what it wraps.

The README also draws a line the name can obscure. This is authorization plumbing. It does not authenticate end users, manage sessions, or store passwords. If you are looking for the best Python library for authentication, OAuthLib is a component of that answer rather than the answer itself.

## Reading the extras to know what you actually pull in

The `setup.py` file is the most useful thing in this repository, because optional capabilities are expressed as extras rather than assumed.

```python
rsa_require = ['cryptography>=3.0.0']
signedtoken_require = ['cryptography>=3.0.0', 'pyjwt>=2.0.0,<3']
signals_require = ['blinker>=1.4.0']
```

That gives you three decisions to make at install time. The `rsa` extra pulls in `cryptography` for RSA support. The `signedtoken` extra pulls in `cryptography` plus `pyjwt`, held above version 2.0.0 and below 3, and it is what you need for JWT bearer flows. The `signals` extra pulls in `blinker`, which is how the provider side emits events.

The base install is genuinely small, which matters for a library that ends up inside other people's web applications. The development requirements file shows the full set the project works against.

```text
blinker==1.4
cryptography>=3.0.0
pyjwt>=2.0.0,<3
```

Notice `blinker` is pinned exactly at 1.4 in development while `cryptography` and `pyjwt` use ranges. That asymmetry is what you would expect from a library that must keep working across a wide range of downstream applications: the signalling dependency is a compatibility surface, the cryptography ones are not.

## Two version floors that disagree

The README's opening line says this is an implementation for Python 3.8 and later. `setup.py` says `python_requires='>=3.9'`.

These are not reconcilable into one supported range, and rather than pick a side it is worth understanding what each one governs. The README sentence is descriptive prose about the library's history, while `python_requires` is the constraint your installer actually enforces. If you are on Python 3.8, the metadata will refuse the install regardless of what the README claims.

The practical rule that follows: check `setup.py` or the PyPI metadata for the floor, and treat README version prose as stale by default. That is a small thing on its own, but it is the clearest example in this repository of documentation drifting from packaging metadata.

The same file is otherwise well made. It declares the licence as BSD-3-Clause, the version is read from `oauthlib.__version__` rather than duplicated, packages are found with `docs`, `examples` and `tests` excluded, and the classifier set includes Development Status 5, Production/Stable. Version 3.3.0 changed the licence declaration to use a proper SPDX identifier, and 3.3.1 followed up by no longer installing the `examples` directory into `site-packages`, which is a small packaging bug that would have shipped sample code into every install.

## The Makefile tests the libraries that depend on this one

The most distinctive thing about this repository is that its `Makefile` clones and tests other people's projects.

```makefile
clean:
	rm -rf bottle-oauthlib
	rm -rf dance
	rm -rf django-oauth-toolkit
	rm -rf flask-oauthlib
	rm -rf requests-oauthlib
```

There are per-project targets beyond `clean`, and each one follows the same shape: change into a directory if it exists, otherwise clone the downstream repository, rewrite its tox configuration with `sed` to install the local editable copy of oauthlib in place of the released one, strip oauthlib from its requirements file, then run its test suite.

```makefile
requests:
	cd requests-oauthlib 2>/dev/null || git clone https://github.com/requests/requests-oauthlib.git
	cd requests-oauthlib && sed -i.old 's,oauthlib.*,--editable=file://{toxinidir}/../../[signedtoken],' requirements.txt && uvx --with tox-uv tox
```

That rewrite is the crux. Substituting an editable install means a change to OAuthLib that passes its own test suite but breaks a dependent library gets caught before release. The comment at the top of the file is candid about the state of this: it says to try not to break the libraries below, and that there is unfortunately no neat way to run downstream tests, so they stuck with a Makefile until they have a proper system. Each target also carries a named maintainer contact because those people get GitHub mentions when things break.

Very few foundational libraries maintain that kind of reverse test coverage by hand. It is the single strongest quality signal in this repository, and it is the part most worth borrowing if you maintain a library other people build on.

## Downstream reach, and where OAuth is actually implemented

The README lists which frameworks ship OAuth support through OAuthLib, and it is a long list. For Django there is `django-oauth-toolkit`, which includes Django REST framework support, and `django-allauth`, which includes Django REST framework and Django Ninja. For Flask there is `flask-oauthlib` and `Flask-Dance`. For Pyramid there is `pyramid-oauthlib`, and for Bottle there is `bottle-oauthlib`.

If you want to make OAuth requests rather than issue tokens, the README points you at `requests-oauthlib`, which provides OAuth support powered by OAuthLib on top of the `requests` library.

So the practical decision tree is short. Building an OAuth client against `requests` means using `requests-oauthlib`. Building an OAuth provider inside a web framework means using that framework's package, which depends on OAuthLib for the protocol logic. Building something else, or building the framework package yourself, means using OAuthLib directly and writing the thin veneer it invites.

That last case is the reason the project asks maintainers to write a veneer rather than contribute upstream. The scope is deliberately small enough that a framework maintainer can implement it without adopting a large dependency, which is why the ecosystem has as many OAuthLib-based packages as it does.

The topics on the repository extend past OAuth itself into OpenID Connect, OIDC providers and JWT authentication, which matches the `signedtoken` extra and the OIDC server work visible in the 3.3.0 release notes, where the preconfigured OIDC server was updated to use the OIDC flavour of the refresh token grant type.

## Security reporting, a known CVE, and the state of the docs

Two things here deserve attention before you build on the library. The repository carries a `SECURITY.md`, and version 3.3.1 added an explicit GHSA for vulnerability disclosure, which suggests reporting is routed through GitHub's advisory system rather than only a mailbox.

The other is history. Version 3.2.2 carries a CVE reference, CVE-2022-36087, in its notes under the OAuth2.0 provider heading. An OAuth provider library having a published vulnerability is not remarkable on its own, but it is the reason to read the changelog rather than assume a stable version number means a settled codebase.

Against that, the release cadence looks healthy for a mature project. Version 3.3.0 shipped on 2025-06-17 and 3.3.1 on 2025-06-20, three days later. The 3.3.1 contents are a good illustration of what a maintenance release for this kind of library looks like: the packaging fix for examples, the disclosure policy, a mandatory Read the Docs configuration, and a regression fix for `expires_in` that had been introduced in 3.3.0 itself.

That regression fix is the detail worth sitting with. A three-day-old release broke token expiry handling and the fix shipped within days, which tells you something about how actively this is watched even though the version numbers move slowly.

The last push was on 2026-07-14 and the repository is not archived. Documentation is the acknowledged weak point: the README says the documentation is still quite sparse and invites issues and pull requests to fill it, and points to a feature matrix page for what is supported on providers and clients. There is also a `CHANGELOG.rst` at the repository root for the full history.

## Conclusion

OAuthLib is the right layer when you are building an OAuth integration, an OAuth provider, or a thin framework veneer, because it deliberately stops short of owning your HTTP stack. What the repository settles is the optional dependency structure, the downstream test targets it maintains, and the fact that the docs are thin by the maintainers' own admission. What it does not settle is the security posture question, which you answer by reading `SECURITY.md`, the GHSA disclosure policy added in 3.3.1, and the CVE-2022-36087 entry in the 3.2.2 changelog. Install the `signedtoken` extra if you use JWT bearer flows, since `pyjwt` is not a base dependency. Start with the feature matrix on Read the Docs to confirm your grant type is covered, and remember that this library authenticates nothing on its own: it signs and verifies the protocol messages, and your framework still owns the end user.

## FAQ

### Is there a library for OAuth in Python?

There are several, and OAuthLib is the layer most of them build on rather than an HTTP client itself. If you want to make OAuth requests with `requests`, the package is `requests-oauthlib`. If you are building a web framework integration, packages such as django-oauth-toolkit, django-allauth, flask-oauthlib, Flask-Dance, pyramid-oauthlib and bottle-oauthlib all delegate the protocol logic to OAuthLib.

### What is the best Python library for authentication?

OAuthLib is not an authentication library in that sense. It implements the OAuth1 and OAuth2 request-signing logic, for clients and providers, without assuming a particular HTTP library, so it handles authorization protocol messages rather than verifying who a user is. Sessions, passwords and identity belong to whatever web framework you use, with OAuthLib providing the OAuth layer underneath.

### Which optional dependencies does OAuthLib need for JWT bearer tokens?

The `signedtoken` extra, which installs `cryptography>=3.0.0` and `pyjwt>=2.0.0,<3`. Those are not base dependencies. There are two other extras worth knowing about: `rsa` for RSA support with `cryptography`, and `signals` for `blinker` on the provider side.

### How do I report a security issue in OAuthLib?

The repository includes a `SECURITY.md` file, and version 3.3.1 added an explicit GitHub Security Advisory for vulnerability disclosure, so advisories are the intended route. Version 3.2.2 carries a published advisory of its own, CVE-2022-36087, in the OAuth2.0 provider notes, which is the sort of entry to look for when reviewing a version you plan to pin.

## Sources

- [License: BSD-3-Clause](https://github.com/oauthlib/oauthlib/blob/master/LICENSE)
- [oauthlib/oauthlib on GitHub](https://github.com/oauthlib/oauthlib)
- [Project website](https://oauthlib.readthedocs.io/en/latest/)
- [README](https://github.com/oauthlib/oauthlib/blob/master/README.md)
- [Releases](https://github.com/oauthlib/oauthlib/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/oauthlib-oauthlib
