Paul Gadal
02/13/2026, 1:10 PMMarvin
02/13/2026, 1:10 PMMarvin
02/13/2026, 1:12 PM# On the server
export PREFECT_SERVER_API_AUTH_STRING="admin:pass"
# On clients/agents
export PREFECT_API_AUTH_STRING="admin:pass"
Questions to help me recommend the best path:
- Are you using Prefect Cloud or self-hosted Prefect Server?
- Do you need per-role UI/API permissions (RBAC) or just gated access to the UI?
- If Cloud: are you able to use the Enterprise plan for SSO/RBAC? If self‑hosted: do you have a reverse proxy where we can add Keycloak auth?Paul Gadal
02/13/2026, 1:15 PMMarvin
02/13/2026, 1:15 PMMarvin
02/13/2026, 1:16 PMOAUTH2_PROXY_PROVIDER=oidc
OAUTH2_PROXY_OIDC_ISSUER_URL=<https://keycloak.example.com/realms/myrealm>
OAUTH2_PROXY_CLIENT_ID=prefect-ui
OAUTH2_PROXY_CLIENT_SECRET=YOUR_CLIENT_SECRET
OAUTH2_PROXY_REDIRECT_URL=<https://prefect.example.com/oauth2/callback>
OAUTH2_PROXY_EMAIL_DOMAINS=*
OAUTH2_PROXY_SCOPE=openid email profile
OAUTH2_PROXY_COOKIE_SECRET=BASE64_32_BYTE_SECRET
OAUTH2_PROXY_COOKIE_SECURE=true
OAUTH2_PROXY_COOKIE_SAMESITE=lax
OAUTH2_PROXY_SET_XAUTHREQUEST=true
OAUTH2_PROXY_PASS_ACCESS_TOKEN=true
OAUTH2_PROXY_PASS_AUTHORIZATION_HEADER=true
# Session/timeout knobs
OAUTH2_PROXY_COOKIE_EXPIRE=8h
OAUTH2_PROXY_COOKIE_REFRESH=1h
2) Nginx (enforce auth, proxy to Prefect; includes Upgrade headers for SSE/WebSocket compatibility)
server {
listen 443 ssl;
server_name <http://prefect.example.com|prefect.example.com>;
# TLS config omitted for brevity
# oauth2-proxy endpoints
location /oauth2/ {
proxy_pass <http://oauth2-proxy:4180;>
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
}
# Auth check for every request
location = /oauth2/auth {
proxy_pass <http://oauth2-proxy:4180/oauth2/auth;>
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
}
# Protect everything behind oauth2
location / {
auth_request /oauth2/auth;
error_page 401 = /oauth2/start?rd=$request_uri;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
# Forward user info (optional, for logging/auditing)
proxy_set_header X-Auth-Request-Email $upstream_http_x_auth_request_email;
proxy_set_header X-Auth-Request-User $upstream_http_x_auth_request_user;
# Upgrade for streaming/websocket endpoints if any
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_pass <http://prefect-server:4200;>
}
}
# Map required for Connection upgrade
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
3) Keycloak setup
- Create a confidential client (e.g., “prefect-ui”) in your realm.
- Valid Redirect URI: https://prefect.example.com/oauth2/callback
- Web origins: https://prefect.example.com
- Adjust session + token settings to control timeouts:
- SSO Session Idle / Max
- Access token lifespan
- Refresh token lifespan
Docs: Keycloak session/timeouts
4) Prefect Server
- Remove PREFECT_SERVER_API_AUTH_STRING so the proxy is the only auth gate.
- Point users to https://prefect.example.com
- Keep workers and automations pointing at the internal API URL (bypass the proxy), e.g.:
- PREFECT_API_URL=<http://prefect-server:4200/api> (inside your network)
This avoids headless auth issues for workers.
Option B: Traefik + oauth2-proxy (ForwardAuth)
- Traefik enforces auth via ForwardAuth to oauth2-proxy.
- Example (static/dynamic config sketch):Marvin
02/13/2026, 1:16 PMhttp:
middlewares:
oauth2-forwardauth:
forwardAuth:
address: "<http://oauth2-proxy:4180/oauth2/auth>"
trustForwardHeader: true
authResponseHeaders:
- X-Auth-Request-Email
- X-Auth-Request-User
Router and service:
http:
routers:
prefect:
rule: "Host(`<http://prefect.example.com|prefect.example.com>`)"
entryPoints: ["websecure"]
tls: {}
middlewares: ["oauth2-forwardauth"]
service: "prefect"
services:
prefect:
loadBalancer:
servers:
- url: "<http://prefect-server:4200>"
Expose oauth2-proxy routes through Traefik too (for /oauth2/*) without the ForwardAuth middleware, and configure oauth2-proxy with the same env as in Option A.
Session timeout behavior
- Prefect’s basic auth has no session timeout; it’s effectively “remembered” until cleared.
- With the proxy approach:
- Set Keycloak realm SSO idle/max session and token lifespans to your policy.
- Set oauth2-proxy cookie_expire/cookie_refresh to align with your policy.
- Users will be redirected to re-auth when their session expires.
Useful references
- Prefect security settings (self-hosted): Security settings (self-hosted)
- oauth2-proxy docs: oauth2-proxy
- Nginx auth_request: nginx auth_request
- Traefik ForwardAuth: Traefik ForwardAuth
- Keycloak sessions/timeouts: Keycloak session/timeouts
Questions to tailor this for you
- Which proxy do you prefer (Nginx or Traefik)?
- Will your workers access the API internally (recommended) or through the same external URL?
- Do you want to keep Prefect’s basic auth behind the proxy (double gate), or use the proxy as the sole gate?