The standard Traefik ForwardAuth setup works seamlessly when all your apps share a common parent domain (for example app.example.com and other.example.com can both receive a cookie set on .example.com). When apps live on completely different domains (for example app.example.com and app.otherdomain.io), cookies set by GateKeeper cannot be shared across domains - this is a browser security constraint.
GateKeeper solves this with a cross-domain token handoff.
How it works
- A user visits
app.otherdomain.io. Traefik sends the verify request to GateKeeper. - GateKeeper sees there is no valid session for this host and redirects to
/login?redirect_uri=https://app.otherdomain.io/the-page. - The user logs in on
auth.example.com. After authentication, GateKeeper detects that the redirect target is outside the shared cookie domain. - Instead of redirecting directly, GateKeeper generates a cross-domain token - a short-lived (5-minute), HMAC-SHA256 signed token containing the session ID.
- The browser is sent to
https://app.otherdomain.io/_gk/auth?token=XXX&redirect=/the-page. - Traefik intercepts this request and forwards it to GateKeeper's verify endpoint.
- GateKeeper validates the HMAC signature and expiry, extracts the session ID, and sets a
gk_sessioncookie scoped toapp.otherdomain.io(noDomainattribute, so the browser scopes it to the exact host). - GateKeeper redirects back to
/the-page. The user is now authenticated onapp.otherdomain.ioand future requests carry the host-scoped session cookie.
Configuration
No extra configuration is needed if you set COOKIE_DOMAIN. GateKeeper automatically detects when a redirect target is outside the shared domain and triggers the cross-domain handoff.
If COOKIE_DOMAIN is not set, all apps are treated as same-domain and the cross-domain flow is never used.
COOKIE_DOMAIN=.example.com # covers *.example.com
BASE_URL=https://auth.example.comToken security
Cross-domain tokens are signed with HMAC-SHA256 using SECRET_KEY. Properties:
- Short-lived - tokens expire after 5 minutes.
- Single use - the token contains the session ID but is consumed when the cookie is set.
- Not replayable - a token captured in transit cannot be replayed after expiry, and it is tied to the specific session.
- Transmitted in the URL - the token appears in the query string and may appear in server logs. The short expiry limits the window an intercepted token is useful.
Traefik configuration
The /_gk/auth path on each protected app's domain must be reachable by Traefik's ForwardAuth check. No special configuration is needed - the standard gk-auth middleware handles this path automatically.
http:
middlewares:
gk-auth:
forwardAuth:
address: "http://gatekeeper:8282/auth/verify"
authResponseHeaders:
- X-Auth-User
- X-Auth-EmailPoint address directly at the GateKeeper container (gatekeeper:8282, a private IP, or a Tailscale address), not at the public auth.example.com. Routing the ForwardAuth request through the auth domain rewrites X-Forwarded-Host and breaks the cross-domain redirect back to the app.
Apply this middleware to routes on any domain, including domains unrelated to example.com. GateKeeper handles the cross-domain handoff transparently.