NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #1822 most downloaded on PyPI
OAuth 2.0 authorization server for Django
Last release 1 months ago
21 Aug 2026
Release timing varies
gaps range from 4 weeks to 13 months
Nearly every release is documented
notes for 50 of 51 stable releases
1 version withdrawn
withdrawn after publishing
13 years old
52 releases · first in 2013
This release is dominated by security hardening of redirect URI matching, token revocation and refresh token handling . Several entries below change b
This release is dominated by security hardening of redirect URI matching, token revocation and
refresh token handling. Several entries below change behavior that was previously accepted, and
they are spread across Fixed and Security: the "Upgrading to 3.4.1" section of the
Upgrading guide collects everything you need to act on in one place, so start there. Of particular
note: redirect URIs are now matched exactly per
RFC 9700 §2.1, so a request may no
longer carry query parameters, path parameters, credentials or a fragment that the registered URI
does not have; REFRESH_TOKEN_EXPIRE_SECONDS, where set, is now enforced when a refresh token is
presented rather than only by the cleartokens sweep; and the built-in templates now link a
stylesheet shipped with the package instead of a CDN, so run collectstatic or the pages render
unstyled.
oauth2_provider logger at DEBUG,post_logout_redirect_uri and for the token endpoint's comparison against theAbstractApplication.redirect_uri_allowed()post_logout_redirect_uri_allowed() now call the new check_redirect_to_uri_allowed()redirect_to_uri_allowed(), so codeoauth2_provider.W011) that warns when the AccessToken andRefreshToken models are swapped into different apps, and a newform-action Content Security Policy, whichredirect_uri.TokenHasResourceScoperequired_scopes entry suffixed with the READ_SCOPE/WRITE_SCOPE settingread/write, e.g. music:read, music:write), so a bare music scopeSCOPES.SCOPES_BACKEND_CLASS, including a worked model-basedgettext_lazy) verbose_name labels on every field of theApplication, Grant, AccessToken, RefreshToken, IDToken and DeviceGrant models, sooauth2_provider.0021_translatable_field_labels records the label changes; it makes noJSONOAuthLibCore (OAUTH2_PROVIDER["OAUTH2_BACKEND_CLASS"] set tooauth2_provider.oauth2_backends.JSONOAuthLibCore) is deprecated and now emits aDeprecationWarning. It makes the OAuth token, introspection, andapplication/json bodies, but those endpoints are defined toapplication/x-www-form-urlencoded (RFC 6749, RFC 7662, RFC 7009); the JSON mode isApplication.clean() now reports its validation errors per field instead of asredirect_uris, a non-https CORS origin on allowed_origins, an unusable algorithm onalgorithm, and the HS256 client-secret conflicts on client_secret /hash_client_secret. ValidationError.message_dict is keyed by those field names, soApplication.full_clean() (including dynamic client registration and CIMD)ModelForm that omits one ofoauth2_provider.forms.ApplicationForm.oauth2_provider/base.html now links a small stylesheet distributedstatic/oauth2_provider/css/oauth2_provider.css), which also absorbs<style> block that template carried. The built-in pages therefore render indefault-src 'self', which blocks a foreign style host and an inline style block alike,staticfiles, so run collectstatic for the pages to be styled. The Bootstrap 2css block of base.html isAccessToken and RefreshToken admins now invalidate tokens through a "Revoke selected"RefreshToken.access_token is SET_NULL) — an orphanREFRESH_TOKEN_REUSE_PROTECTION relies on. The revoke action invalidatescleartokens. Grant andIDToken admins keep the default delete. The access-token revoke logic is now a single sharedoauth2_provider.models.revoke_access_token() helper used by the admin action, the /revoke/AuthorizedTokenDeleteView.cleartokens management command now prints a warning to stderr whenREFRESH_TOKEN_EXPIRE_SECONDS is unset (or 0), explaining that only revoked and/revoke/ endpoint) now also revokesaccess_token foreign key is SET_NULL). Whether a refresh token may surviveREFRESH_TOKEN_EXPIRE_SECONDS as defense-in-depth (rotation remains the primaryOIDC_RP_INITIATED_LOGOUT_ACCEPT_EXPIRED_TOKENS defaultsTrue (the id_token_hint is a previously issued token per OIDC RP-Initiated Logout)AccessToken, IDToken, and RefreshToken models aremodels tag instead of database.database-tagged checks unless a database alias is passedmanage.py check --database default), because such checks may do more thanmanage.py check wouldREFRESH_TOKEN_REUSE_PROTECTION now revokes a compromised token family as a setSELECT ... FOR UPDATE roundAbstractRefreshToken.revoke_family(), and token_family is indexed0022_refreshtoken_token_family_index) so it no longer scans the whole refreshmakemigrations torevoke() override revoke_family() to match.RefreshToken's(token_checksum, revoked) uniqueness permits but the bulk write cannot express (#1816) --invalid_grant rather than raising.com.example.app:/oauth2redirect), but Application.clean() reassembled every URI with:// before validating and rejected the result with "Enter a valid URL." — leaving nativeredirect_uri_mismatch against each other. Schemes that require an authorityhttp, https, ws, wss, ftp) must still include a host, and the redundantcom.example.app:///oauth2redirect and rootless com.example.app:oauth2redirect spellingscom.example.app://oauth2redirect — registering oauth2redirect as aredirect_to_uri_allowed() no longer raises AttributeError whenALLOW_URI_WILDCARDS is enabled and a redirect URI has no hostname, as is the case forREFRESH_TOKEN_EXPIRE_SECONDS is now enforced when a refresh token is presented,cleartokens (clear_expired) cleanup job. Previously a refresh tokencleartokens was never scheduled. Expiry is idle-based: a refresh tokenREFRESH_TOKEN_EXPIRE_SECONDS after its access token expires (the deadlineREFRESH_TOKEN_EXPIRE_SECONDS = None) still never expires refresh tokens. UpgradeREFRESH_TOKEN_EXPIRE_SECONDS may see idle refresh tokensclear_expired() now reclaims "orphaned" refresh tokens — non-revoked refreshaccess_token NULL. Theaccess_token__expires__lt join could never match a NULL access token, soREFRESH_TOKEN_GRACE_PERIOD_SECONDS no longerAttributeError: 'NoneType' object has no attribute 'token' (HTTP 500) when theclear_expired or a concurrent rotation._save_bearer_token now re-issues a refresh token bound to the surviving access tokenAccessToken.source_refresh_token relation).AssertionErrorredirect_uris (e.g. aclient_credentials application) is driven through a flow that needs a defaultApplication.default_redirect_uri now raisesoauthlib's MissingRedirectURIError, consistent with the multiple-URI case.OAuth2Validator.validate_bearer_token now rejects a token whoseApplication.is_usable() returns False) with aninvalid_token error, mirroring the check the issuance path already performs_load_application. The default is_usable() returns True, so this onlyTokenHasScope and TokenMatchesOASRequirements permissions nowFalse) and log a warning, instead of raising an AssertionErrorrequest.auth is not an OAuth2 access token. This lets them be#1819 The device authorization flow's confirmation and status views now act only on a device
grant that belongs to the signed-in user. DeviceUserCodeView claims a pending grant for the
user who enters the user_code, but DeviceConfirmView and DeviceGrantStatusView looked the
grant up by client_id and user_code alone. Any other authenticated user who learned that
short, human-readable code — it is displayed on the device's screen for a person to read and
type — could therefore approve the pending authorization, handing the device tokens bound to
the account of the user who entered it, or deny it, or read its status page. RFC 8628 §3.3 has
the user who is being asked to authorize the device grant that authorization. Both views now
filter on user=request.user and return 404 to anyone else; a grant that has not yet been
claimed through the user-code step likewise can no longer be confirmed by navigating straight
to the confirmation URL.
#1816 A refresh token that was deliberately revoked is no longer honored inside
REFRESH_TOKEN_GRACE_PERIOD_SECONDS. The grace window exists to shield the token a
client retries when it did not receive the rotated response, but revoked records both
that supersession and a deliberate revocation (the RFC 7009 /revoke/ endpoint,
AuthorizedTokenDeleteView, the admin, RP-initiated logout, revoking the bound access
token), and validation could not tell them apart. A revoked token was therefore usable
for the length of the window, contrary to
RFC 7009 §2.1 ("the
invalidation takes place immediately, and the token cannot be used again after the
revocation"). With ROTATE_REFRESH_TOKEN = False it was additionally re-issued as a new
live row carrying the same token value, bringing the repudiated credential back to life
in the database. The two are now distinguished by whether the token was ever consumed to
mint a successor access token. A genuine rotation retry inside the window is unaffected,
and deployments on the default REFRESH_TOKEN_GRACE_PERIOD_SECONDS = 0 were never
exposed.
This generalizes a test that previously applied only when
REFRESH_TOKEN_REUSE_PROTECTION was enabled, so it is also a behavior change with reuse
protection off: a superseded token whose successor access token has since been deleted is
now rejected inside the window rather than accepted.
Redirect URIs are now matched exactly, as
RFC 9700 §2.1 requires
("authorization servers MUST utilize exact string matching except for port numbers in
localhost redirection URIs of native apps") and OpenID Connect Core §3.1.2.1 restates
via RFC 3986 §6.2.1 Simple String Comparison. Four deviations are closed, each of which
let a request differ from the registered URI while still matching it:
redirect_uri and have thehttps://example.com/cb;evil=1). urlparse();params off the last path segment into a separate attribute, and only .pathurlsplit(), which leaves them in the path.https://evil@example.com/cb). Only .hostnameurlparse() split off before comparison,https://example.com/cb#x matched a registered https://example.com/cb.# is an%23 is not aRegistration is tightened to match: AllowedURIValidator tested the parsed fragment,
which is empty both for a URI with no fragment and for one ending in a bare #, so
https://example.com/cb# was accepted at save time. With matching now denying any #,
such a registration would be stored and then never authorize anything; it is rejected
up front instead. Registering a URI ending in # now raises a ValidationError where
it previously succeeded.
Case-insensitive scheme/host comparison (RFC 3986 §6.2.2.1 normalization) and the
RFC 8252 §7.3 loopback any-port exemption are unchanged; ALLOW_URI_WILDCARDS still
opts out of exact host matching and remains flagged by oauth2_provider.W009/E004.
Upgrade note: clients that pass per-request data through the redirect_uri query
string will now be rejected — every query parameter must be registered, and in the same
order. Register the full URI including its query, or move per-request data into the
state parameter, which is what it is for. Applications whose registered
redirect_uris already carry no query component are unaffected.
#1510 Revoking an access token from the authorized-tokens page
(AuthorizedTokenDeleteView) now also revokes the refresh token issued
alongside it. Previously only the access token was deleted, leaving the
refresh token usable to mint a fresh access token and defeating the
revocation (a regression from 2.3.0). Per
RFC 7009 §2.1 an
access token revocation may also revoke the respective refresh token; for a
user-initiated revocation that is now the behavior.
#1617 With REFRESH_TOKEN_REUSE_PROTECTION enabled, REFRESH_TOKEN_GRACE_PERIOD_SECONDS
no longer extends the validity of a refresh token that is several generations old in
the rotation chain. The grace period now only shields the immediately preceding
refresh token (the token a client retries when it did not receive the rotated
response); replaying an older, already-rotated-past token within the grace window is
rejected and revokes the whole token family, instead of being honored (and, without a
requested scope, minting a fresh token pair).
#727 The token revocation endpoint (/o/revoke_token/) now only revokes tokens that
were issued to the authenticated client. Previously it revoked any token matching the
submitted value regardless of which application issued it, so a client could revoke
another client's tokens. Per
RFC 7009 §2.1 the server
verifies the token was issued to the client making the request; a token belonging to a
different client is now left untouched and the endpoint still returns 200 (RFC 7009
§2.2) without disclosing whether the token exists.
#1799 RFC 7592 registration access tokens now honour COMPLIANT_BCP_RFC9700_TOKEN_STORAGE. The
dynamic client registration views assigned the token straight onto the model instead of routing it
through the storage path that honours the setting, so a deployment that had opted into hashed-at-rest
storage still had this one token persisted in cleartext. The registration response and the management
endpoint continue to return the token to its owner; only what is written to the database changes.
One column per quarter.
It also carries a batch of security fixes : an unauthenticated open redirect from the authorization endpoint ( prompt=none ), HS256 ID tokens being si…
The headline of this release is first-class support for the Model Context Protocol (MCP)
authorization server role.
MCP's authorization spec is built on a stack of modern OAuth RFCs,
and this cycle landed the whole stack: Authorization Server Metadata (RFC 8414) and Protected
Resource Metadata (RFC 9728) for discovery, Dynamic Client Registration (RFC 7591 / RFC 7592) and
OAuth Client ID Metadata Documents (CIMD) so clients can register themselves, Resource Indicators
(RFC 8707) for audience-bound access tokens, and the OAuth 2.0 Security Best Current Practice
(RFC 9700) together with the RFC 9207 iss parameter. The RFC 9700 compliance gates double as a
configurable OAuth 2.1 security posture — they can reject the implicit and password grants and
enforce S256-only PKCE (legacy behavior by default in 3.4, scheduled to flip to compliant in 4.0).
The new ALLOW_LOCALHOST_LOOPBACK setting smooths the ephemeral-port loopback callback used by
native clients such as Claude Code, MCP Inspector, and mcp-remote.
Beyond MCP, the release adds a Django Ninja integration alongside the existing DRF support and
support for RP-Initiated Registration, lifts the 255-character cap on refresh tokens (mirroring the
access-token checksum scheme), makes cleartokens reclaim revoked refresh tokens sooner, and
harmonizes Bearer Authorization header parsing across the middleware.
It also carries a batch of security fixes: an unauthenticated open redirect from the
authorization endpoint (prompt=none), HS256 ID tokens being signed with the hashed client
secret, cleartext tokens and codes exposed in the Django admin, client secrets written to debug
logs, and predictable device-flow user_code generation. Longstanding operational bugs are fixed
too, including a multi-database migrate deadlock (#1591) and duplicate unique indexes that broke
fresh installs on Oracle and strict MySQL (#1656).
Before upgrading, read the breaking-changes section below: most items are makemigrations
steps for swapped models, but applications using the HS256 signing algorithm now require
hash_client_secret=False.
HS256 signing algorithm must now be configured withhash_client_secret=False. Previously such applications signed ID tokens with the hashed clientApplication.clean() now raises aValidationError for HS256 + hash_client_secret=True, and Application.jwk_key raisesImproperlyConfigured at signing time if the secret is hashed. To migrate an affectedhash_client_secret=False so the plaintextAbstractRefreshToken model require doing a manage.py migrate after upgrading.OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL) you will need tomanage.py makemigrations. If your table already contains refreshtoken_checksum with a data migration — adapt the batched backfillforwards_func inoauth2_provider/migrations/0015_refreshtoken_token_checksum.py (dropping its swapped-model("token", "revoked") unique constraint → widen token toTextField → backfill → make checksum non-nullable → add the ("token_checksum", "revoked")OAUTH2_PROVIDER_APPLICATION_MODEL), runmanage.py makemigrations after upgrading: AbstractApplication gained aregistration_source CharField (choices manual/dcr/cimd, default manual) to markdcr_created BooleanField. Installs using the built-in Applicationmanage.py migrate (migration 0019).OAUTH2_PROVIDER_APPLICATION_MODEL), runmanage.py makemigrations after upgrading: for CIMD (#1742) AbstractApplication gained acimd_expires_at DateTimeField, and client_id widened from max_length=100 to255 so a metadata-document URL fits. Installs using the built-in Application model just needmanage.py migrate (migration 0020).OAUTH2_PROVIDER_DEVICE_GRANT_MODEL), runmanage.py makemigrations after upgrading: the redundant field-level unique=True was removedAbstractDeviceGrant.device_code (#1656), and AbstractDeviceGrant.scope changed fromCharField(max_length=64, null=True) to a non-nullable TextField(blank=True) (#1693). Whenscope rows, provide the one-off default "" —oauth2_provider/migrations/0016_alter_devicegrant_scope.py. Uniqueness remains enforced by the<app_label>_<class>_unique_device_code constraint. If you are doing a fresh install onCreateModel migration for the swapped model, since it still declares0013 did.OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL) and have not0012_add_token_checksum migration (i.e. you are upgrading from a versiontoken_checksum backfill now deterministically skips the swapped model — themigrate logs a warningtoken_checksum istoken_checksum): adapt the batched backfill loop from forwards_func inoauth2_provider/migrations/0012_add_token_checksum.py, dropping its swapped-model guard (theYourAccessToken.objects.filter(token_checksum__isnull=True).exists(). Installs that already0012 (any 3.x deployment) are unaffected./.well-known/oauth-authorization-server)/.well-known/oauth-protected-resource), plus opt-inProtectedResourceMetadataMixin, protected_resource_metadata) and a DRF authenticatorOAuth2ProtectedResourceAuthentication) that advertise it via the resource_metadata WWW-Authenticate challenge parameterclient_secret field, warning users to copy theApplicationAdmin uses ApplicationForm, and a shared oauth2_provider/js/application_form.jshash_client_secret checkbox is toggled on either surface. TheHS256 algorithm is selected while the client secret is —DynamicClientRegistrationView andDynamicClientRegistrationManagementView with configurable permission classes and registration accessAbstractApplication.registration_source"dcr" and can be filtered in the Django admin.ALLOW_LOCALHOST_LOOPBACK setting to extend the RFC 8252 §7.3 any-port loopback exemption to http://localhost redirect URIs (opt-in, default False)draft-ietf-oauth-client-id-metadata-document). A client may present an https URL as itsclient_id; when CIMD_ENABLED is on the server fetches, validates and persists the metadataAbstractApplication.registration_source set to "cimd".CIMD_REGISTRATION_PERMISSION_CLASSES (default allow-all;HostAllowlistCIMDPermission restricts it to CIMD_ALLOWED_HOSTS), and theclearcimdapplications management command prunes expired CIMD applications that hold no livedocs/cimd.rst.registration_endpoint in the RFC 8414DCR_ENABLED is onresource parameter during authorization or access token requestsaud claim for tokens with resource indicatorsCOMPLIANT_BCP_RFC9700_<topic> setting that defaults to False (current behavior,True in 4.0 (enforces theCOMPLIANT_BCP_RFC9700_IMPLICIT_GRANT (§2.1.2),COMPLIANT_BCP_RFC9700_PASSWORD_GRANT (§2.4), COMPLIANT_BCP_RFC9700_PKCE_METHOD (§2.1.1),COMPLIANT_BCP_RFC9700_ACCESS_TOKEN_TRANSPORT (§4.3.2), COMPLIANT_BCP_RFC9700_AUTHZ_RESPONSE_ISS (§4.4),COMPLIANT_BCP_RFC9700_TOKEN_STORAGE (§4). Enforced behaviors are also removed from the RFC 8414iss authorization-response parameter and theauthorization_response_iss_parameter_supported metadata field (mix-up defense), gated byCOMPLIANT_BCP_RFC9700_AUTHZ_RESPONSE_ISS.False,True): COMPLIANT_BCP_RFC9700_REFRESH_TOKENREFRESH_TOKEN_REUSE_PROTECTION, §4.14.2), COMPLIANT_BCP_RFC9700_REDIRECT_URI_SCHEMEALLOWED_REDIRECT_URI_SCHEMES, §2.1), COMPLIANT_BCP_RFC9700_REDIRECT_URI_MATCHINGALLOW_URI_WILDCARDS, §4.1.1), and COMPLIANT_BCP_RFC9700_PKCE_REQUIRED (PKCE_REQUIRED, §2.1.1).--deploy security system check that flags every RFC 9700 recommendation currently on a non-compliant valueoauth2_provider.W001–W010, errors oauth2_provider.E002–E005 when the correspondingoauth2_provider.E001) for the incompatible combination ofREFRESH_TOKEN_GRACE_PERIOD_SECONDS.docs/security.rst page mapping each RFC 9700 recommendation to the corresponding setting. The demo IdPOAUTH2_PROVIDER_COMPLIANT_BCP_RFC9700_* environment variable so the Docker image and theHttpRequest creation in OAuth2Validator.validate_user into an overridablebuild_http_request method, so subclasses can pass extra attributes through to their authentication backends.Authorization header parsing is now harmonized across the codebase via a sharedoauth2_provider.utils.parse_bearer_token helper implementing RFC 7235 / RFC 6750 semantics.OAuth2TokenMiddleware and OAuth2ExtraTokenMiddleware now accept the schemebearer header, which is RFC-correct, is no longerBearerBearerX token was previously treated as a Bearer token and is now rejected).cleartokens now removes revoked refresh tokens once REFRESH_TOKEN_GRACE_PERIOD_SECONDSREFRESH_TOKEN_EXPIRE_SECONDS. WhenREFRESH_TOKEN_REUSE_PROTECTION is enabled, revoked tokens are still kept until they expire soRefreshToken.token is now a TextField and lookups use a new SHA-256 token_checksumAccessToken.token_checksum approach introduced in 3.0.00012_add_token_checksum backfill now computes checksums in batched bulk_updatecleartokens before upgrading is still the best preparation for tables with many expiredplaincode_challenge_method, or an access token in the URI query string now emits a DeprecationWarning, perCOMPLIANT_BCP_RFC9700_* setting, whose default is scheduled to flip to True (enforcing rejection) in 4.0.AUTHENTICATION_SERVER_EXP_TIME_ZONE setting. Token introspection exp values areDeprecationWarning and will be removed in a futureredirect_uris whose hostname uses the double-dash form required forhttps://*--sitename.netlify.app). The validator previously stripped*, leaving a hostname that began with - and wasURIValidator; it now strips up to two leading hyphens while rejecting longer runs.ReadWriteScopedResourceMixin.__new__() no longer forwards positional/keyword arguments toobject.__new__(), which raised TypeError: object.__new__() takes exactly one argument whencls(**initkwargs) view instantiation.client_id or username containing a NUL (\x00) byte no longer causes a 500 errorValueError instead of executing the query;rw_protected_resource decorator accumulating the read/write scope on a shared listPOST) request the write scope stayed in the list and aGET) request with a read-only token was wrongly rejected. The behaviour wasscopes list. TheAbstractDeviceGrant.scope is now a TextField(blank=True) like the other grant and tokenCharField(max_length=64, null=True). 64 characters is well below the limits0016.pk instead of id in clear_expired() and RefreshToken.revoke() so token models with a custom primary key field are supported.datetime.utcfromtimestamp.auth_time in oauth2 validator when user has never logged in.OIDC_SERVER_CLASS when OIDC_ENABLED is True and OAUTH2_SERVER_CLASS is not explicitly set; previously only the default was used in this fallback path.migrate hanging on 0012_add_token_checksum when a database router orRunPython data migrations in 0006 and 0012 nowschema_editor.connection.alias, so the backfill runs on the connectionmigrate --database=...). Thanks to Igor Petrik forunique=True on DeviceGrant.device_code, which duplicated theunique_device_code UniqueConstraint and created two identical unique indexes on the sameORA-02261) and on MySQL backends that raise databaseER_DUP_INDEX, 1831). Migration 0013 is fixed in place because theCREATE TABLE, so a follow-up migration could never fix fresh0013 keep one harmless extra unique index;user_code values with the cryptographically secure secrets modulerandom module (Mersenne Twister). The user_code is a deviceOAuth2Validatorclient_secret (and, for Basic auth, the base64 client_id:client_secretDEBUG level. These messages now log at most the client_id (when it isAccessTokenAdmin, RefreshTokenAdmin, and GrantAdmin classes listed thetoken/code in list_display and included them in search_fields. Because these values?q= query string (captured by access logs and browser history).token/code field is also excluded fromhas_add_permission returns False on the AccessToken, RefreshToken, Grant, andIDToken admins) — these are issued by the OAuth flows and are not meant to be hand-created, andAccessToken,RefreshToken, and Grant model __str__ methods no longer return the raw token/code (which therepr() and"<Model> #<pk>" identifier.HS256 algorithm with hash_client_secret=True (the default), the ID token was signedHS256 now requires hash_client_secret=False:Application.clean() rejects the combination, and jwk_key raises ImproperlyConfiguredHS256 with an empty client secret is likewise rejectedprompt=none request fromredirect_uri with a login_required errorredirect_uri were validated, allowing an attacker to redirect a victim's## [3.3.0] - 2025-05-21 ### Added * #1637 Support for Django 6.0 * #1642 Provide App Name and Scope in Device Confirmation View ### Removed * #1636 Re
list_select_related to RefreshTokenAdmin to avoid unbounded JOIN queries on the changelistDeviceGrant model usage across the device authorization flowCache-Control header value on the OIDC JWKS endpointSupport for Python 3.14 (Django >= 5.2.8)
Bearer keyword.NOTE: This is the first release under the new django-oauth organization. The project moved in order to be more independent and to bypass quota limits
NOTE: This is the first release under the new django-oauth organization. The project moved in order to be more independent and to bypass quota limits on parallel CI jobs we were encountering in Jazzband. The project will emulateDjango Commons going forward in it's operation. We're always on the look for willing maintainers and contributors. Feel free to start participating any time. PR's are always welcome.
The project is now hosted in the django-oauth organization.
<!--
-->
-->
Nothing published for this version
bugfix #1491 Fix migration error when there are pre-existing Access Tokens.
bugfix #1491 Fix migration error when there are pre-existing Access Tokens.
A few deprecations warned about in 2.4.0 (#1345) have been removed. See below.
AbstractAccessToken model require doing a manage.py migrate after upgrading.manage.py makemigrations).LoginRequiredMiddleware introduced in Django 5.1.pk instead of id. This enables, for example, custom swapped models to have a different primary key field.token_checksum field that is used to validate tokens.RedirectURIValidator, WildcardSet per #1345; validate_logout_request per #1274ui_locales request parameter triggers AttributeError under certain circumstancesREFRESH_TOKEN_REUSE_PROTECTION.ROTATE_REFRESH_TOKEN,Issues caused by Release 2.0.0 breaking changes continue to be logged. Please make sure to carefully read these release notes before performing a MAJO…
Issues caused by Release 2.0.0 breaking changes continue to be logged. Please make sure to carefully read these release notes before performing a MAJOR upgrade to 2.x.
These issues both result in {"error": "invalid_client"}:
The application client secret is now hashed upon save. You must copy it before it is saved. Using the hashed value will fail.
PKCE_REQUIRED is now True by default. You should use PKCE with your client or set PKCE_REQUIRED=False if you are unable to fix the client.
If you are going to revert migration 0006 make note that previously hashed client_secret cannot be reverted!
OAuth2ExtraTokenMiddleware for adding access token to request.
See Setup a provider in the Tutorial.post_logout_redirect_uris field in the Application Registration formcode_challenge_methods_supported property to auto discovery information, per RFC 8414 section 2EXP in AccessToken always as UTC instead of (possibly) local timezone.
Use setting AUTHENTICATION_SERVER_EXP_TIME_ZONE to enable different time zone in case the remote
authentication server does not provide EXP in UTC.0006_alter_application_client_secret. Note that reversing this migration cannot undo a hashed client_secret.RedirectURIValidator in favor of AllowedURIValidator.validate_user.Issues caused by Release 2.0.0 breaking changes continue to be logged. Please make sure to carefully read these release notes before performing a MAJO…
Issues caused by Release 2.0.0 breaking changes continue to be logged. Please make sure to carefully read these release notes before performing a MAJOR upgrade to 2.x.
These issues both result in {"error": "invalid_client"}:
The application client secret is now hashed upon save. You must copy it before it is saved. Using the hashed value will fail.
PKCE_REQUIRED is now True by default. You should use PKCE with your client or set PKCE_REQUIRED=False if you are unable to fix the client.
cleartokens management commandIssues caused by Release 2.0.0 breaking changes continue to be logged. Please make sure to carefully read these release notes before performing a MAJO…
Issues caused by Release 2.0.0 breaking changes continue to be logged. Please make sure to carefully read these release notes before performing a MAJOR upgrade to 2.x.
These issues both result in {"error": "invalid_client"}:
The application client secret is now hashed upon save. You must copy it before it is saved. Using the hashed value will fail.
PKCE_REQUIRED is now True by default. You should use PKCE with your client or set PKCE_REQUIRED=False if you are unable to fix the client.
Issues caused by Release 2.0.0 breaking changes continue to be logged. Please make sure to carefully read these release notes before performing a MAJO…
Issues caused by Release 2.0.0 breaking changes continue to be logged. Please make sure to carefully read these release notes before performing a MAJOR upgrade to 2.x.
These issues both result in {"error": "invalid_client"}:
The application client secret is now hashed upon save. You must copy it before it is saved. Using the hashed value will fail.
PKCE_REQUIRED is now True by default. You should use PKCE with your client or set PKCE_REQUIRED=False if you are unable to fix the client.
prompt=login for the OIDC Authorization Code Flow end user Authentication Request.createapplication management command enhanced to display an auto-generated secret before it gets hashed.WIP: Hash application client secrets using Django password hashing by @n2ygk in https://github.com/jazzband/django-oauth-toolkit/pull/1093
createapplication command by @vector-kerr in https://github.com/jazzband/django-oauth-toolkit/pull/1132Full Changelog: https://github.com/jazzband/django-oauth-toolkit/compare/1.7.0...2.0.0
This is a major release with BREAKING changes. Please make sure to review these changes before upgrading:
PKCE_REQUIRED = False in your settings.pyapplication.client_secret values to be hashed with Django's default password hashing algorithm
and can not be reversed. When adding or modifying an Application in the Admin console, you must copy the
auto-generated or manually-entered client_secret before hitting Save.oidc_claim_scope = None in your subclass of OAuth2Validator.access_token available to get_oidc_claims when called from get_userinfo_claims.--algorithm argument to createapplication management commandvalidate_bearer_token() to properly set request.scopes to the list of granted scopes.--skip-authorization argument of the createapplication management command.urn:ietf:wg:oauth:2.0:oob and urn:ietf:wg:oauth:2.0:oob:auto which are replaced
by RFC 8252 "OAuth 2.0 for Native Apps" BCP. Google has
deprecated use of oob with
a final end date of 2022-10-03. If you still rely on oob support in django-oauth-toolkit, do not upgrade to this release.### Removed * #1126 Reverts #1070 which incorrectly added Celery auto-discovery tasks.py (as described in #1123) and because it conflicts with Huey's
## [1.7.0] 2022-01-23 ### Added * #969 Add batching of expired token deletions in cleartokens management command and models.clear_expired() to improve
cleartokens management command and models.clear_expired()
to improve performance for removal of large numers of expired tokens. Configure with
CLEAR_EXPIRED_TOKENS_BATCH_SIZE and
CLEAR_EXPIRED_TOKENS_BATCH_INTERVAL.claims_supported available at the OIDC auto-discovery endpoint (.well-known/openid-configuration).{"active": false} when introspecting a nonexistent token
per RFC 7662. It had been incorrectly returning 401.## [1.6.3] 2022-01-11 ### Fixed * #1085 Fix for #1083 admin UI search for idtoken results in django.core.exceptions.FieldError: Cannot resolve keyword
django.core.exceptions.FieldError: Cannot resolve keyword 'token' into field.NOTE: This release reverts an inadvertently-added breaking change.
NOTE: This release reverts an inadvertently-added breaking change.
Note: Only Django 4.0.1+ is supported due to a regression in Django 4.0.0. Explanation
# Added #949 Provide django.contrib.auth.authenticate() with a request for compatibiity with more backends (like django-axes). #968, #1039 Add support
#949 Provide django.contrib.auth.authenticate() with a request for compatibiity with more backends (like django-axes). #968, #1039 Add support for Django 3.2 and 4.0. #953 Allow loopback redirect URIs using random ports as described in RFC8252 section 7.3. #972 Add Farsi/fa language support. #978 OIDC: Add support for rotating multiple RSA private keys. #978 OIDC: Add new OIDC_JWKS_MAX_AGE_SECONDS to improve jwks_uri caching. #967 OIDC: Add additional claims beyond sub to the id_token. #1041 Add a search field to the Admin UI (e.g. for search for tokens by email address).
#981 Require redirect_uri if multiple URIs are registered per RFC6749 section 3.1.2.3 #991 Update documentation of REFRESH_TOKEN_EXPIRE_SECONDS to indicate it may be int or datetime.timedelta. #977 Update Tutorial to show required include.
#968 Remove support for Django 3.0 & 3.1 and Python 3.6 #1035 Removes default_app_config for Django Deprecation Warning #1023 six should be dropped
#963 Fix handling invalid hex values in client query strings with a 400 error rather than 500. #973 Tutorial updated to use django-cors-headers. #956 OIDC: Update documentation of get_userinfo_claims to add the missing argument.
### Added * #915 Add optional OpenID Connect support. ### Changed * #942 Help via defunct Google group replaced with using GitHub issues
### Changed * #925 OAuth2TokenMiddleware converted to new style middleware, and no longer extends MiddlewareMixin. ### Removed * #936 Remove support f
### Added * #917 Documentation improvement for Access Token expiration. * #916 (for DOT contributors) Added tox -e livedocs which launches a local web
tox -e livedocs which launches a local web server on localhost:8000
to display Sphinx documentation with live updates as you edit.select_for_update statement (impacts Oracle 12c database).redirect_uri field length limit for AbstractGrantadded select_related in intospect view for better query performance
select_related in intospect view for better query performanceSee release 1.3.1; no changes.
See release 1.3.1; no changes.
N.B. this feature appears to be deprecated and replaced with methods described in RFC 8252: OAuth2 for Native Apps and *may* be deprecated and/or remo…
From the CHANGELOG:
OAUTH2_PROVIDER settings:
ACCESS_TOKEN_GENERATOR to override the default access token generator.REFRESH_TOKEN_GENERATOR to override the default refresh token generator.EXTRA_SERVER_KWARGS options dictionary for oauthlib's Server class.PKCE_REQUIRED to require PKCE.createapplication management command to create an application.id in toolkit admin console applications list.redirect_uri
for Google OAuth2 "manual copy/paste".
N.B. this feature appears to be deprecated and replaced with methods described in
RFC 8252: OAuth2 for Native Apps and may be deprecated and/or removed
from a future release of Django-oauth-toolkit.manage.py migrate before
upgrading to >= 1.3.0.request to django.contrib.auth.authenticate() (#636)oauth2_error property exception oauthlib_core.verify_request method raises exceptions in authenticate.
(#633)Compatibility: Python 3.4 is the new minimum required version.
redirect_uris validation to the application clean() method.Nothing published for this version
Return state with Authorization Denied error (RFC6749 section 4.1.2.1)
Critical: Django OAuth Toolkit 1.1.0 contained a migration that would revoke all existing RefreshTokens (0006_auto_20171214_2232). This release correc
0006_auto_20171214_2232). This release corrects the migration.
If you have already ran it in production, please see the following issue for more details:
https://github.com/django-oauth/django-oauth-toolkit/issues/589Notice: The Django OAuth Toolkit project is now hosted by JazzBand.
ALLOWED_REDIRECT_URI_SCHEMES
setting by returning a list of allowed redirect uri schemes in Application.get_allowed_schemes().ERROR_RESPONSE_WITH_SCOPES can now be set to True to include required
scopes when DRF authorization fails due to improper scopes.REFRESH_TOKEN_GRACE_PERIOD_SECONDS controls a grace period during which
refresh tokens may be reused.app_authorized signal is fired when a token is generated.New feature: AccessToken, RefreshToken and Grant models are now swappable.
oauth2_provider.ext.rest_framework module
has been moved to oauth2_provider.contrib.rest_frameworkid field on Application, AccessToken, RefreshToken and Grant to BigAutoField (bigint/bigserial)created and updated auto fields to Application, AccessToken, RefreshToken and Granturl parameter in some error responses.Support for the scopes query parameter, deprecated in 0.6.1, has been dropped
SCOPES_BACKEND_CLASS setting points to.
By default, this is set to oauth2_provider.scopes.SettingsScopes which implements the
legacy settings-based scope behaviour. No changes are necessary.scopes query parameter, deprecated in 0.6.1, has been droppedis_usable(request) method on the Application model can be overridden to dynamically
enable or disable applications.- #424: Added a ROTATE_REFRESH_TOKEN setting to control whether refresh tokens are reused or not - #315: AuthorizationView does not overwrite requests
- #322: dropping support for python 2.6 and django 1.4, 1.5, 1.6 - #310: Fixed error that could occur sometimes when checking validity of incomplete A
oauthlib_backend_class is now pluggable through Django settings
oauthlib_backend_class is now pluggable through Django settingsapplication/json Content-Type is now supported using JSONOAuthLibCoreFix the migrations to be two-step and allow upgrade from 0.7.2
South migrations fixed. Added new django migrations.
Several docs improvements and minor fixes
client_id and client_secret characters setskip_authorization_completely class fieldget_application_model on Django 1.7client_secret length* Don't pin oauthlib
Added database indexes to the OAuth2 related models to improve performances.
Warning: schema migration does not work for sqlite3 database, migration should be performed manually
Backwards incompatible changes in 0.7.0
Backwards incompatible changes in 0.7.0
OAUTH2_PROVIDER_APPLICATION_MODEL)added support for scope query parameter keeping backwards compatibility for the original scopes parameter.
__str__ method in Application model returns content of name field when availableSkip authorization form via approval_prompt parameter
approval_prompt parameterBugfixes
Backwards incompatible changes in 0.5.0
New stuff
Backwards incompatible changes in 0.5.0
Bugfixes
Optimize queries on access token validation
Backwards incompatible changes in 0.4.0
New Features
Backwards incompatible changes in 0.4.0
SCOPE attribute in settings is now a dictionary to store {'scope_name': 'scope_description'}oauth2_provider is mandatory in urls. See issue #36Bugfixes
client_id with ":" colon char when using HTTP Basic Authdefault_redirect_uri is mandatory when grant_type is implicit, authorization_code or all-in-onevalidate_urisBugfix #37: Error in migrations with custom user on Django 1.5
Bugfix #27: OAuthlib refresh token refactoring
Backwards incompatible changes in 0.3.0
validate_bearer_tokenBackwards incompatible changes in 0.3.0
requested_scopes parameter in ScopedResourceMixin changed to required_scopes* Core optimizations
Add support for Django1.4 and Django1.6
Support OAuth2 Authorization Flows
Your coding agent can read these notes before it upgrades. Set up the MCP server →