From f4620dff3afe1419d2ad53647d83bf817ecb97b3 Mon Sep 17 00:00:00 2001 From: Kenneth Date: Mon, 29 Dec 2025 00:07:44 +0000 Subject: [PATCH] fix(backend): optional auth for share routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add auth.NewOptionalAuthMiddleware to run auth only when credentials are present (Authorization header or auth cookies). Use it on share consumption routes so public shares remain accessible unauthenticated, while authenticated callers can resolve account-scoped shares. This prevents a panic in share middleware when accountId was provided but the request wasn’t authenticated (nil reqctx.AuthenticatedUser type assertion). --- apps/backend/internal/auth/middleware.go | 22 ++++++++++++++++++++++ apps/backend/internal/sharing/http.go | 6 +++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/apps/backend/internal/auth/middleware.go b/apps/backend/internal/auth/middleware.go index 8404751..d158cc6 100644 --- a/apps/backend/internal/auth/middleware.go +++ b/apps/backend/internal/auth/middleware.go @@ -102,3 +102,25 @@ func NewAuthMiddleware(s *Service, db *bun.DB, cookieConfig CookieConfig) fiber. return c.Next() } } + +// NewOptionalAuthMiddleware conditionally runs the given auth middleware only when +// the request contains auth credentials (Authorization header or auth cookies). +// +// This is useful for endpoints that are publicly accessible but can also behave +// differently for authenticated callers (e.g. share consumption routes that may +// resolve additional permissions for a specific account when credentials are +// present). +// +// Usage: +// authMiddleware := auth.NewAuthMiddleware(...) +// router.Use(auth.NewOptionalAuthMiddleware(authMiddleware)) +func NewOptionalAuthMiddleware(authMiddleware fiber.Handler) fiber.Handler { + return func(c *fiber.Ctx) error { + hasAuthHeader := c.Get("Authorization") != "" + hasAuthCookies := c.Cookies(cookieKeyAccessToken) != "" || c.Cookies(cookieKeyRefreshToken) != "" + if !hasAuthHeader && !hasAuthCookies { + return c.Next() + } + return authMiddleware(c) + } +} diff --git a/apps/backend/internal/sharing/http.go b/apps/backend/internal/sharing/http.go index 9d7da59..c979281 100644 --- a/apps/backend/internal/sharing/http.go +++ b/apps/backend/internal/sharing/http.go @@ -5,6 +5,7 @@ import ( "time" "github.com/get-drexa/drexa/internal/account" + "github.com/get-drexa/drexa/internal/auth" "github.com/get-drexa/drexa/internal/httperr" "github.com/get-drexa/drexa/internal/nullable" "github.com/get-drexa/drexa/internal/reqctx" @@ -50,7 +51,10 @@ func NewHTTPHandler(sharingService *Service, accountService *account.Service, vf } func (h *HTTPHandler) RegisterShareConsumeRoutes(r fiber.Router) *virtualfs.ScopedRouter { - g := r.Group("/shares/:shareID", h.shareMiddleware) + // Public shares should be accessible without authentication. However, if the client provides auth + // credentials (cookies or Authorization header), attempt auth so share scopes can be resolved for + // account-scoped shares. + g := r.Group("/shares/:shareID", auth.NewOptionalAuthMiddleware(h.authMiddleware), h.shareMiddleware) return &virtualfs.ScopedRouter{Router: g} }