Changelog¶
All significant changes to the project are documented in this file.
The format is based on Keep a Changelog.
[2.0.1] - 2026-08-01¶
Documentation-only release: the package code is identical to 2.0.0. A new version is required because PyPI cannot update the project description of an already published release.
Changed¶
- README: added the Fin3000 sponsor section.
[2.0.0] - 2026-06-11¶
This release fixes correctness and security defects in token validation. Several fixes change runtime behavior, so it is a major release. Read the Changed (breaking) and Removed sections before upgrading.
Changed (breaking)¶
- Invalid/expired tokens now return 401 instead of being silently treated as
anonymous. Previously a malformed, expired, or wrongly-signed token caused
authenticate()to returnNone, so the request continued unauthenticated (and was allowed through onAllowAnyviews). It now raisesAuthenticationFailedwith codetoken_not_valid, ortoken_expiredfor an expired token so clients can trigger a refresh. - Inactive/unknown users now raise 401 (
user_inactive) instead of returningNone, which previously setrequest.user = Noneand could 500 downstream code. - A Keycloak outage now fails closed (503). With
VERIFY_TOKENS_WITH_KEYCLOAK=True, introspection/network failures raiseKeycloakAPIError(503) instead of silently downgrading to anonymous access. - Mapped user fields are synced from the token on every login (with a
dirty-check so a write only happens on change), not just at user creation.
Keycloak is the source of truth for the fields in
CLAIM_MAPPING. SERVER_URLdefault is nowNoneand resolves toISSUERwhen unset, so configuring onlyISSUERno longer silently talks tolocalhost.ALGORITHMis normalized to a list before being handed to PyJWT (a bare string could previously match by substring).WWW-Authenticaterealm now uses double quotes (Bearer realm="api") and the bearer scheme is matched case-insensitively (RFC 6750/7235).- Minimum supported versions raised: Python >= 3.10, Django >= 4.2, DRF
= 3.14. EOL Python/Django versions are no longer supported.
HeaderMiddlewarehas been removed. It overlapped with Django'sSecurityMiddlewareand set HSTS unconditionally with a hardcodedincludeSubDomains. Use Django'sSecurityMiddlewareand theSECURE_*settings for security headers — see the README and Django's security docs.
Added¶
VERIFY_TOKENS_WITH_KEYCLOAKnow actually performs token introspection (after local validation) — previously the setting only changed key lookup.LEEWAYsetting (default0) for clock-skew tolerance onexp/iat/nbf.VERIFY_CERTIFICATEis now a documented default setting and is honored for the JWKS fetch as well.- A
drf_keycloaklogger emits warnings on Keycloak failures and debug lines on token rejection (never logging token or secret material). KeycloakAPIError(503) exception for upstream availability failures.SECURITY.mdwith a vulnerability disclosure policy.
Fixed¶
- OpenAPI schema: corrected
TokenScheme.target_class(keycloak.…→drf_keycloak.…) so drf-spectacular actually emits thesecuritySchemesentry. - JWKS handling consolidated into a single cached client with native key rotation; an unreachable JWKS endpoint now yields 503 (was an uncaught 500), and a missing realm public key no longer crashes.
- Forced JWKS refreshes are rate-limited so a flood of tokens with random
kidvalues can't amplify into unbounded requests against Keycloak. HasPermissionno longer raises when used as a bare class (permission_classes = [HasPermission]) and tolerates non-dict segments inPERMISSION_PATH.- Keycloak HTTP errors surface with the correct status (5xx → 503) instead of a
generic 500; long Keycloak claim values are truncated during sync instead of
500-ing the request; empty
USER_ID_CLAIMno longer creates a blank user. KeycloakApireads settings live, sooverride_settingsand runtime reconfiguration take effect.- Test suite no longer mutates module globals (order-independent).
Removed¶
KeycloakApi.get_public_keyandKeycloakApi.get_jwks(replaced by the internaldrf_keycloak.keysmodule).drf_keycloak.token.PUBLIC_KEYCLOAK_KEY_CACHEanddrf_keycloak.token.TokenError(unused).REALMsetting (the realm is part ofSERVER_URL/ISSUER).drf_keycloak.middleware.HeaderMiddleware(use Django'sSecurityMiddlewareand theSECURE_*settings instead).python-joseoptional dependency (unused; had known CVEs).
Security¶
- The README previously claimed tokens were validated against the Keycloak API
even though introspection was never invoked. Token revocation checking now
works when
VERIFY_TOKENS_WITH_KEYCLOAK=True, and the documentation reflects the actual behavior.
[1.0.3] - 2025-09-16¶
Added¶
- GitHub Actions CI/CD: Complete CI pipeline with ruff linting, formatting checks, and automated testing using uv
- Dependabot Integration: Automatic dependency updates for Python packages and GitHub Actions
- Pre-commit Hooks: Code quality enforcement with ruff formatting and linting on commit
- Automated PR Labeling: Smart labeling system for pull requests based on changed files
Changed¶
- Development Tooling: Migrated from traditional pip to modern uv package manager for faster dependency resolution
- Code Style: Refactored codebase for improved consistency and readability across all modules
- CI Strategy: Replaced pre-commit.ci with GitHub Actions for more control over CI processes
Improved¶
- Developer Experience: Streamlined setup with uv and comprehensive pre-commit configuration
- Code Quality: Enhanced linting and formatting with updated ruff configuration
- Project Maintenance: Automated dependency management and PR organization
[1.0.2] - 2025-06-11¶
Added¶
- Docker Test Environment: Complete Docker setup with Keycloak integration for testing
- Integration Tests: Comprehensive test scripts to validate authentication flow
- SERVER_URL Configuration: New
SERVER_URLsetting to separate API calls from JWT issuer validation - Custom Exception Classes: Added
TokenBackendErrorandTokenBackendExpiredTokenfor better error handling
Changed¶
- Simplified Configuration: Replaced
JWKS_URLwith automatic generation fromSERVER_URL - Removed Keycloak API Verification: Eliminated
VERIFY_TOKENS_WITH_KEYCLOAKsetting for simplified token validation - Enhanced Error Handling: Improved exception handling in authentication backend
- PyJWT Crypto Support: Added
PyJWT[crypto]dependency for RS256 algorithm support
Fixed¶
- Docker Network Communication: Fixed internal vs external URL handling for Docker environments
- JWT Algorithm Support: Resolved "Algorithm 'RS256' could not be found" error
- Token Issuer Validation: Fixed issuer mismatch in Docker environments
Removed¶
- VERIFY_TOKENS_WITH_KEYCLOAK: Removed complex dual-validation approach
- JWKS_URL: Auto-generated from SERVER_URL to reduce configuration complexity
[1.0.1] - 2024-11-12¶
Added¶
- Support for different types of
raw_token(byte strings and regular strings) - Additional tests to ensure compatibility with both token types
Changed¶
- Adaptation of the
KeycloakAuthBackendclass for conditional decoding ofraw_token - Updated the test cases to include both
bytesandstrtokens
Fixed¶
- Fixed comparison assertion bug in tests by comparing
validated_tokentoclaimsinstead ofraw_token
[1.0.0] - 2023-09-12¶
Added¶
- Initial release of the
drf_keycloakpackage - Support for keycloak-based authentication in Django REST Framework