Skip to content

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_execute and DagsterAuthMiddleware now deny unknown mutations with an ADMIN default role.
  • Rate limiting: check_and_record made atomic via the backend method; added double-checked locking to the singleton; rate limiter EXPIRE now compatible with Redis 6.
  • LDAP: Unbind connection in _get_user_attributes finally; safe LDAP attribute first-value extraction in list_users; scalar _first_value handling.
  • Sessions: Hard cap on _MAX_REVOKED revoked-token store to prevent OOM; CookieBackend revocation capped.
  • Detection layer: Check Middleware.cls attribute for Starlette compatibility.
  • Change role: Restored change-role CLI command; pass operator identity to change_role audit.
  • Security headers: Inject headers on all response paths.
  • Logging: exc_info=True on logger.error/critical calls; HTML-escape user data before JSON injection.
  • Secret key: Replace print with logging for auto-generated SECRET_KEY warning.
  • Proxy auth: Removed trusted IP list from proxy auth log.
  • Helm: Require explicit image.tag in 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:write for the semantic-release push; grant actions:write in 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 callable when Dagster uses a sync index_html_endpoint. The patched handler now always awaits — previously the sync branch called _inject_resilient_ui (async) without await, 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.state is backed by a plain dict. Now checks both request.scope["state"] (dict) and request.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 documented DAGSTER_AUTH_ADMIN_USER env var non-functional.

[0.4.0] - 2026-07-13

Major Changes

Cross-Pod Session Revocation (DB-backed)

  • Added session_version column to users table — bumps on change_password, change_role, delete_user
  • CookieBackend now 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 WARNING about single-pod limitation

Pure ASGI Middleware

  • Rewrote DagsterAuthMiddleware from BaseHTTPMiddleware to 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 ADMIN by default (was: open to VIEWER)
  • Configurable via DAGSTER_AUTH_UNKNOWN_MUTATION_ROLE
  • operationName support — 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 preventionhtml.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 enforcementDAGSTER_AUTH_PROXY_TRUSTED_IPS required in proxy mode
  • Username sanitization — Applied in SQL add_user (was only in web route)
  • Metrics hardening — Removed username from metric labels (prevented info leak via /metrics)

Core Improvements

  • Patch resilience — Async/sync detection via iscoroutinefunction, try/except fallback 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 serializationAuthUser.to_dict() uses role.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 sql and sqlite backends via cached Peewee connection
  • OAuth stubOAuthBackend class implemented (was empty file causing import errors)
  • Blocking I/Obackend.authenticate() runs via run_in_threadpool to avoid event loop starvation

Bug Fixes

  • change_role now revokes sessions (was missing revoke_all call)
  • Audit JSON now reflects actual method/path for REST denials (was hardcoded POST /graphql)
  • _find_user_dn connection cleanup on LDAP exceptions
  • Non-dict GraphQL payloads rejected with 400 instead of AttributeError
  • CLI delete-user message corrected (soft-delete, not permanent)
  • verify_patches() checks sentinel (was always returning True)
  • Bare except: replaced with explicit exception types
  • Portuguese comments translated to English
  • datetime.utcnow() replaced with datetime.now(timezone.utc)
  • InMemoryRateLimiter prunes empty entries to prevent memory leak

Testing

  • 258 unit + integration tests across 14 test files
  • Multi-pod integration tests (session + CSRF portability)
  • operationName and 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_KEY is now required in production. Server refuses to start without it.
  • Proxy mode requires DAGSTER_AUTH_PROXY_TRUSTED_IPS or explicit TRUST_ALL=true.
  • AuthUser.to_dict() now serializes role as int (40) instead of string ("ADMIN"). from_dict() handles both formats (backward-compatible).
  • Database migrationsession_version column added to users table. Automatic on boot; manual fallback documented.
  • Default RBAC posture changed — Unknown mutations now require ADMIN instead of being open.
  • SESSION_COOKIE_SECURE now defaults to true (was false).

[0.3.0] - 2026-02-14

Major Changes

Proxy Authentication Mode (Stable)

  • Added ProxyAuthBackend for 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: false to prevent deprecated env vars
  • Separate /data volume with emptyDir for 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_auth and header injection
  • Test users with password123 mapped to RBAC roles (admin, editor, launcher, viewer)
  • Optional users_database.yml for testing without LDAP

Enhancements

GraphQL Analysis

  • Replaced fragile regex parser with official graphql-core AST parser
  • Added GraphQLMutationAnalyzer for accurate mutation detection
  • Handles aliases, multiple mutations, and complex queries properly
  • Added list-permissions CLI command to display RBAC matrix

Redis Operations

  • Atomic expire with nx=True in 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-permissions to CLI documentation
  • Clearer backend matrix with proxy mode status

Bug Fixes

  • GraphQL: Replaced generic unknown_mutation with 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_URL for flexible database configuration.

LDAP Integration (Experimental)

  • Added ldap3 based backend for Active Directory/LDAP integration.
  • Note: Marked as Experimental/Alpha pending community validation.

Refined RBAC (4 Levels)

  • New Role: Added LAUNCHER role.
  • 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/health and /auth/metrics endpoints 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 Makefile in example directories for easy startup (make up).

Bug Fixes

  • Middleware Dispatch: Fixed a critical bug where call_next was 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 user
  • dagster-authkit add-user - Add users with roles
  • dagster-authkit list-users - List all users
  • dagster-authkit change-password - Change user passwords
  • dagster-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_PASSWORD for IaC deployments
  • Automatic database initialization on first run

Architecture

Modular Structure

  • dagster_authkit/core/ - Core patching and middleware
  • dagster_authkit/auth/ - Authentication backends and security
  • dagster_authkit/api/ - Routes and health checks
  • dagster_authkit/cli/ - User management CLI
  • dagster_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.0
  • dagster-webserver>=1.10.0,<2.0.0
  • starlette>=0.27.0
  • itsdangerous>=2.1.0
  • python-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