Changelog
All notable changes to dagster-authkit will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[1.0.0] - 2026-08-05
Features
- Helm Chart: New production-ready Kubernetes chart under
helm/dagster-authkit/, synced with the application's config (env vars, secrets, image tag) and wired into semantic-release versioning.
Bug Fixes
- CSRF: Tokens now bound to the client via a double-submit signed cookie.
- GraphQL parsing: Fail closed on malformed batch payloads instead of erroring.
- Metrics: Added optional token-based protection for
/auth/metrics; removed username/action labels to prevent unbounded cardinality. - RBAC deny-by-default:
can_executeandDagsterAuthMiddlewarenow deny unknown mutations with anADMINdefault role. - Rate limiting:
check_and_recordmade atomic via the backend method; added double-checked locking to the singleton; rate limiterEXPIREnow compatible with Redis 6. - LDAP: Unbind connection in
_get_user_attributesfinally; safe LDAP attribute first-value extraction inlist_users; scalar_first_valuehandling. - Sessions: Hard cap on
_MAX_REVOKEDrevoked-token store to prevent OOM;CookieBackendrevocation capped. - Detection layer: Check
Middleware.clsattribute for Starlette compatibility. - Change role: Restored
change-roleCLI command; pass operator identity tochange_roleaudit. - Security headers: Inject headers on all response paths.
- Logging:
exc_info=Trueonlogger.error/criticalcalls; HTML-escape user data before JSON injection. - Secret key: Replace
printwith logging for auto-generatedSECRET_KEYwarning. - Proxy auth: Removed trusted IP list from proxy auth log.
- Helm: Require explicit
image.tagin the chart.
CI / DevEx
- Semantic-release + uv-based workflows; fix docs deploy.
- Replace
[all]extra with[sqlite]in CI to avoid native build deps. - Restore
contents:writefor the semantic-release push; grantactions:writein the publish workflow.
Testing
- Boosted coverage 44% → 52% (+98 tests).
- Added suites: detection layer, Redis rate limiter, metrics token gate, CookieBackend, CLI (24 tests), LDAP (64 tests), middleware (WebSocket/proxy/RBAC/helpers).
[0.4.2] - 2026-07-17
Bug Fixes
- UI Injection (Starlette 1.x compat): Fixed
TypeError: 'coroutine' object is not callablewhen Dagster uses a syncindex_html_endpoint. The patched handler now always awaits — previously the sync branch called_inject_resilient_ui(async) withoutawait, returning an unawaited coroutine that Starlette could not invoke as a Response. - Middleware State Access: Fixed silent injection skip on Starlette >=1.3.1 where
request.stateis backed by a plain dict. Now checks bothrequest.scope["state"](dict) andrequest.state(State object) for the authenticated user. - CSP Nonce Support: Copied the
<script nonce="...">from Dagster's existing scripts to injected blocks, fixing UI injection breakage on Dagster deployments with Content Security Policy nonces.
[0.4.1] - 2026-07-14
Bug Fixes
- Bootstrap: Admin username now configurable via
DAGSTER_AUTH_ADMIN_USER(default:admin). Previously the username was hardcoded, making the documentedDAGSTER_AUTH_ADMIN_USERenv var non-functional.
[0.4.0] - 2026-07-13
Major Changes
Cross-Pod Session Revocation (DB-backed)
- Added
session_versioncolumn touserstable — bumps onchange_password,change_role,delete_user CookieBackendnow reads version from DB (with 10s TTL cache) for multi-pod safe revocation without Redis- Automatic migration on first boot for existing databases
- Non-SQL backends get a
WARNINGabout single-pod limitation
Pure ASGI Middleware
- Rewrote
DagsterAuthMiddlewarefromBaseHTTPMiddlewareto pure ASGI - WebSocket connections (GraphQL subscriptions at
/graphql) now authenticated via session cookie - Unauthenticated WS connections closed with code 4001
- CORS preflight (
OPTIONS) passes through before auth check
RBAC: Deny-by-Default
- Unknown GraphQL mutations now require
ADMINby default (was: open toVIEWER) - Configurable via
DAGSTER_AUTH_UNKNOWN_MUTATION_ROLE operationNamesupport — multi-operation documents only check the named operation- REST write minimum role configurable via
DAGSTER_AUTH_REST_WRITE_ROLE
Security Hardening
- CSRF protection — Signed double-submit cookie on login form (stateless, works multi-pod)
- XSS prevention —
html.escape()on all user-controlled values in login and 403 pages - Open redirect hardening — Protocol-relative URLs (
//evil.com) blocked - Empty password rejection — All backends refuse empty passwords (prevents unauthenticated LDAP binds)
- Password hash compatibility — Accepts
$2a$/$2y$bcrypt prefixes in addition to$2b$ - Proxy trust enforcement —
DAGSTER_AUTH_PROXY_TRUSTED_IPSrequired in proxy mode - Username sanitization — Applied in SQL
add_user(was only in web route) - Metrics hardening — Removed
usernamefrom metric labels (prevented info leak via/metrics)
Core Improvements
- Patch resilience — Async/sync detection via
iscoroutinefunction,try/exceptfallback to vanilla Dagster, idempotency guard - Backend instance caching — Backend connections reused across requests (prevents connection pool exhaustion)
- Dual rate-limiting — Independent limits per username AND per IP
- Unified role serialization —
AuthUser.to_dict()usesrole.value(int) for cross-backend consistency - LDAP fixes — Connection leak fixed (
try/finally), timeout on all connections, single-value attribute handling - Health check — Database check works for both
sqlandsqlitebackends via cached Peewee connection - OAuth stub —
OAuthBackendclass implemented (was empty file causing import errors) - Blocking I/O —
backend.authenticate()runs viarun_in_threadpoolto avoid event loop starvation
Bug Fixes
change_rolenow revokes sessions (was missingrevoke_allcall)- Audit JSON now reflects actual method/path for REST denials (was hardcoded
POST /graphql) _find_user_dnconnection cleanup on LDAP exceptions- Non-dict GraphQL payloads rejected with 400 instead of AttributeError
- CLI
delete-usermessage corrected (soft-delete, not permanent) verify_patches()checks sentinel (was always returningTrue)- Bare
except:replaced with explicit exception types - Portuguese comments translated to English
datetime.utcnow()replaced withdatetime.now(timezone.utc)InMemoryRateLimiterprunes empty entries to prevent memory leak
Testing
- 258 unit + integration tests across 14 test files
- Multi-pod integration tests (session + CSRF portability)
operationNameand fragment traversal tests for GraphQL analyzer- Security regression tests (empty password, XSS escape, open redirect, RBAC default-deny)
Configuration Changes
New Environment Variables:
DAGSTER_AUTH_UNKNOWN_MUTATION_ROLE # Role for unrecognized mutations (default: ADMIN)
DAGSTER_AUTH_REST_WRITE_ROLE # Minimum role for REST write requests (default: EDITOR)
DAGSTER_AUTH_PROXY_TRUSTED_IPS # Comma-separated proxy IPs (REQUIRED in proxy mode)
DAGSTER_AUTH_PROXY_TRUST_ALL # Opt-in to proxy mode without IP allowlist (default: false)
Breaking Changes
SECRET_KEYis now required in production. Server refuses to start without it.- Proxy mode requires
DAGSTER_AUTH_PROXY_TRUSTED_IPSor explicitTRUST_ALL=true. AuthUser.to_dict()now serializes role as int (40) instead of string ("ADMIN").from_dict()handles both formats (backward-compatible).- Database migration —
session_versioncolumn added touserstable. Automatic on boot; manual fallback documented. - Default RBAC posture changed — Unknown mutations now require
ADMINinstead of being open. SESSION_COOKIE_SECUREnow defaults totrue(wasfalse).
[0.3.0] - 2026-02-14
Major Changes
Proxy Authentication Mode (Stable)
- Added
ProxyAuthBackendfor delegating authentication to external reverse proxies (Authelia, Traefik, Caddy, oauth2-proxy) - User identity extracted from HTTP headers (
Remote-User,Remote-Groups,Remote-Email,Remote-Name) - Configurable group-to-role mapping via
DAGSTER_AUTH_PROXY_GROUP_PATTERN - Logout endpoint now redirects to external provider logout URL in proxy mode
- Smart group header parser handles JSON arrays, LDAP DNs, CSV, and mixed delimiters
Kubernetes Deployment (Examples)
- Complete Minikube example with full SSO stack:
- OpenLDAP with pre-seeded users and RBAC groups
- Authelia configured with LDAP backend
- Caddy as reverse proxy with TLS termination and forward auth
- Dagster-AuthKit in proxy mode
- Comprehensive Makefile with build, deploy, connect, and monitoring targets
- Critical Kubernetes fixes documented:
enableServiceLinks: falseto prevent deprecated env vars- Separate
/datavolume withemptyDirfor writable storage - LoadBalancer service for proper HTTPS exposure
- Sequential LDIF imports via ConfigMap with numbered files
Authelia + Caddy Example (Docker)
- Complete SSO integration with Authelia, Caddy, and OpenLDAP
- Caddy configured with
forward_authand header injection - Test users with password123 mapped to RBAC roles (admin, editor, launcher, viewer)
- Optional
users_database.ymlfor testing without LDAP
Enhancements
GraphQL Analysis
- Replaced fragile regex parser with official
graphql-coreAST parser - Added
GraphQLMutationAnalyzerfor accurate mutation detection - Handles aliases, multiple mutations, and complex queries properly
- Added
list-permissionsCLI command to display RBAC matrix
Redis Operations
- Atomic
expirewithnx=Truein rate limiter (sets TTL only on first increment) - Fixed session revocation: properly clean user token sets before deletion
- Added Redis URL format validation in config
Code Organization
- Centralized all UI templates (HTML/CSS/JS) in
utils/templates.py - Removed 600+ lines of inline strings from routes and patch modules
- Cleaner separation between logic and presentation
Observability
- Added RBAC decision tracking via
track_rbac_decision() - Metrics now count allowed/denied mutations per role and action
- Better error logging with query truncation for debugging
Documentation & Examples
- New
examples/authelia/- Complete Authelia + Caddy + LDAP stack - New
examples/kubernetes/- Same stack running on Minikube - Updated
examples/ldap/with better OpenLDAP configuration - Added
list-permissionsto CLI documentation - Clearer backend matrix with proxy mode status
Bug Fixes
- GraphQL: Replaced generic
unknown_mutationwith explicit__UNPARSEABLE_QUERY__sentinel - Middleware: Fixed incorrect header extraction in proxy mode
- Session: Redis session revocation now properly removes user token mappings
- Rate Limiter: TTL now set correctly only on first attempt
Configuration Changes
New Environment Variables:
# Proxy Mode
DAGSTER_AUTH_PROXY_USER_HEADER # Header for username (default: Remote-User)
DAGSTER_AUTH_PROXY_GROUPS_HEADER # Header for groups (default: Remote-Groups)
DAGSTER_AUTH_PROXY_EMAIL_HEADER # Header for email (default: Remote-Email)
DAGSTER_AUTH_PROXY_NAME_HEADER # Header for display name (default: Remote-Name)
DAGSTER_AUTH_PROXY_GROUP_PATTERN # Pattern for LDAP group mapping
DAGSTER_AUTH_PROXY_LOGOUT_URL # External logout URL for proxy mode
Breaking Changes
- GraphQL Error Format: Unparseable queries now return
__UNPARSEABLE_QUERY__instead of generic fallback - Redis Session Format: Session data structure updated; existing Redis sessions will be invalidated on upgrade
[0.2.0] - 2026-01-28
Major Changes
Multi-Backend Support (SQL & Redis)
- Added Peewee ORM support, enabling connection to PostgreSQL, MySQL, and MariaDB.
- Added Redis backend for production-grade session storage (fixes the issue of logouts on server restart).
- Introduced
DAGSTER_AUTH_DB_CONNECTION_URLfor flexible database configuration.
LDAP Integration (Experimental)
- Added
ldap3based backend for Active Directory/LDAP integration. - Note: Marked as Experimental/Alpha pending community validation.
Refined RBAC (4 Levels)
- New Role: Added
LAUNCHERrole. - Updated Hierarchy:
- Admin: Full control.
- Editor: Can edit code/assets and manage runs.
- Launcher: Can launch/retry runs but cannot modify code/assets (New).
- Viewer: Read-only access (GraphQL mutations blocked).
Enhancements
Health & Observability
- Fixed:
/auth/healthand/auth/metricsendpoints were previously returning 404 due to middleware misconfiguration. They are now intercepted correctly. - Health checks now return status for the specific backend in use (SQL, Redis, or LDAP).
Developer Experience
- Added
examples/directory with ready-to-use Docker Compose stacks: quickstart-sqlite: Zero config.postgresql_redis: Production reference architecture.-
ldap: Local OpenLDAP testing setup. -
Added
Makefilein example directories for easy startup (make up).
Bug Fixes
- Middleware Dispatch: Fixed a critical bug where
call_nextwas invoked for internal endpoints (/auth/health), causing Dagster to return 404. - Dependency Management: Clarified optional dependencies in
pyproject.toml(install via[postgresql],[redis], etc).
Breaking Changes
- Project Status: Downgraded status label from "General Availability" to BETA. Use in production at your own risk.
- RBAC Logic: Existing users in database might need role migration if custom roles were manually hacked (standard roles map automatically).
[0.1.0] - 2026-01-25
Initial Release
First working version of dagster-authkit - community authentication for Dagster OSS.
Features
Authentication System
- SQLite-based authentication backend with bcrypt password hashing
- Login/logout pages with clean UI
- Session management using cryptographically signed cookies (itsdangerous)
- Rate limiting for brute-force protection (5 attempts per 5 minutes)
- Automatic session expiration (24h default, configurable)
Role-Based Access Control (RBAC)
- Three roles: admin, editor, viewer
- GraphQL mutation detection and blocking for non-editors
- Proper error responses that stop UI loading states
- Viewer role can see everything but cannot modify (read-only)
User Management CLI
dagster-authkit init-db- Initialize database with optional admin userdagster-authkit add-user- Add users with rolesdagster-authkit list-users- List all usersdagster-authkit change-password- Change user passwordsdagster-authkit delete-user- Soft-delete users
Audit Logging
- Structured JSON audit logs to stdout
- Tracks: login attempts, logout, access control decisions, password changes, user management
- Ready for log aggregation systems (Datadog, Splunk, CloudWatch, ELK)
Security Features
- Bcrypt password hashing with SHA-256 pre-hash (prevents BCrypt 72-byte limit issues)
- Constant-time password comparison (timing attack prevention)
- Security headers: X-Frame-Options, CSP, X-Content-Type-Options
- Open redirect protection
- Username sanitization
- CSRF token generation (foundation for future CSRF protection)
Monkey-Patching System
- Dagster API compatibility detection layer
- Non-invasive middleware injection (first layer in ASGI stack)
- Route injection for /auth/* endpoints
- UI injection - user menu in Dagster sidebar with username, role, and logout
Health & Monitoring
/auth/health- Unified health check endpoint/auth/health?type=live- Kubernetes liveness probe/auth/health?type=ready- Kubernetes readiness probe/auth/metrics- Basic metrics (login attempts, uptime, etc.)
Docker/Kubernetes Support
- Admin user bootstrap via environment variables
DAGSTER_AUTH_ADMIN_USER,DAGSTER_AUTH_ADMIN_PASSWORDfor IaC deployments- Automatic database initialization on first run
Architecture
Modular Structure
dagster_authkit/core/- Core patching and middlewaredagster_authkit/auth/- Authentication backends and securitydagster_authkit/api/- Routes and health checksdagster_authkit/cli/- User management CLIdagster_authkit/utils/- Config, audit, logging
Plugin System
- Backend discovery via setuptools entry points
- Easy to add custom backends without modifying core code
- Dummy backend for development (admin/admin, editor/editor, viewer/viewer)
Dependencies
Core
dagster>=1.10.0,<2.0.0dagster-webserver>=1.10.0,<2.0.0starlette>=0.27.0itsdangerous>=2.1.0python-multipart>=0.0.6
Optional
bcrypt>=4.0.0- For SQLite backend
Known Issues
- Monkey-patching fragility - May break across Dagster versions (tested on 1.10-1.12)
- In-memory rate limiting - Does not work across multiple instances (use Redis for distributed)
- GraphQL mutation detection - Regex-based, may have edge cases
- No fine-grained permissions - Only 3 roles (admin/editor/viewer)
- LDAP backend - Stub only, not implemented
- OAuth backend - Stub only, not implemented
Documentation
- README.md with quick start guide
- Inline code documentation (docstrings)
- CLI help messages (
dagster-authkit --help)
Configuration
All configuration via environment variables:
- Session management (SECRET_KEY, SESSION_MAX_AGE, cookie settings)
- Backend selection (AUTH_BACKEND)
- Rate limiting (RATE_LIMIT_*, configurable attempts/window)
- Audit logging (AUDIT_LOG_ENABLED)
- Admin bootstrap (ADMIN_USER, ADMIN_PASSWORD)
Breaking Changes
N/A - Initial release
[Unreleased]
Planned Features
- Helm chart for Kubernetes deployments
- OIDC backend (native, beyond proxy mode)
- Fine-grained asset-level RBAC