fix(auth): exempt swagger ui path in authentik middleware

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-02 06:29:34 +00:00
parent b8fd020bb2
commit dd834211d8
3 changed files with 40 additions and 3 deletions

View file

@ -26,7 +26,7 @@ type AuthentikConfig struct {
TrustedProxy bool
// PublicPaths lists additional paths that do not require authentication.
// /health and /swagger are always public.
// /health and the configured Swagger UI path are always public.
PublicPaths []string
}
@ -134,7 +134,7 @@ func validateJWT(ctx context.Context, cfg AuthentikConfig, rawToken string) (*Au
// The middleware is PERMISSIVE: it populates the context when credentials are
// present but never rejects unauthenticated requests. Downstream handlers
// use GetUser to check authentication.
func authentikMiddleware(cfg AuthentikConfig) gin.HandlerFunc {
func authentikMiddleware(cfg AuthentikConfig, publicPaths func() []string) gin.HandlerFunc {
// Build the set of public paths that skip header extraction entirely.
public := map[string]bool{
"/health": true,
@ -153,6 +153,14 @@ func authentikMiddleware(cfg AuthentikConfig) gin.HandlerFunc {
return
}
}
if publicPaths != nil {
for _, p := range publicPaths() {
if isPublicPath(path, p) {
c.Next()
return
}
}
}
// Block 1: Extract user from X-authentik-* forward-auth headers.
if cfg.TrustedProxy {

View file

@ -343,6 +343,33 @@ func TestBearerAndAuthentikCoexist_Good(t *testing.T) {
}
}
func TestAuthentik_Good_CustomSwaggerPathBypassesAuth(t *testing.T) {
gin.SetMode(gin.TestMode)
cfg := api.AuthentikConfig{TrustedProxy: true}
e, err := api.New(
api.WithAuthentik(cfg),
api.WithSwagger("Test API", "A test API service", "1.0.0"),
api.WithSwaggerPath("/docs"),
)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
srv := httptest.NewServer(e.Handler())
defer srv.Close()
resp, err := http.Get(srv.URL + "/docs/doc.json")
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("expected 200 for custom swagger path without auth, got %d", resp.StatusCode)
}
}
// ── RequireAuth / RequireGroup ────────────────────────────────────────
func TestRequireAuth_Good(t *testing.T) {

View file

@ -140,7 +140,9 @@ func WithWSPath(path string) Option {
// The middleware is permissive: unauthenticated requests are allowed through.
func WithAuthentik(cfg AuthentikConfig) Option {
return func(e *Engine) {
e.middlewares = append(e.middlewares, authentikMiddleware(cfg))
e.middlewares = append(e.middlewares, authentikMiddleware(cfg, func() []string {
return []string{resolveSwaggerPath(e.swaggerPath)}
}))
}
}