From 76909ae86905a5008a50b727275921c35c856df2 Mon Sep 17 00:00:00 2001 From: Hein Date: Thu, 21 May 2026 09:48:46 +0200 Subject: [PATCH] feat(security): add cookie support for login and logout methods * Implement LoginWithCookie and LogoutWithCookie in CompositeSecurityProvider * Update Authenticator interface to include cookie methods * Add cookie support in HeaderAuthenticator and JWTAuthenticator --- pkg/security/composite.go | 10 ++++++++++ pkg/security/interfaces.go | 10 ++++++++++ pkg/security/providers.go | 16 ++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/pkg/security/composite.go b/pkg/security/composite.go index 24d01a5..6808020 100644 --- a/pkg/security/composite.go +++ b/pkg/security/composite.go @@ -43,11 +43,21 @@ func (c *CompositeSecurityProvider) Login(ctx context.Context, req LoginRequest) return c.auth.Login(ctx, req) } +// LoginWithCookie delegates to the authenticator +func (c *CompositeSecurityProvider) LoginWithCookie(ctx context.Context, req LoginRequest, w http.ResponseWriter) (*LoginResponse, error) { + return c.auth.LoginWithCookie(ctx, req, w) +} + // Logout delegates to the authenticator func (c *CompositeSecurityProvider) Logout(ctx context.Context, req LogoutRequest) error { return c.auth.Logout(ctx, req) } +// LogoutWithCookie delegates to the authenticator +func (c *CompositeSecurityProvider) LogoutWithCookie(ctx context.Context, req LogoutRequest, w http.ResponseWriter) error { + return c.auth.LogoutWithCookie(ctx, req, w) +} + // Authenticate delegates to the authenticator func (c *CompositeSecurityProvider) Authenticate(r *http.Request) (*UserContext, error) { return c.auth.Authenticate(r) diff --git a/pkg/security/interfaces.go b/pkg/security/interfaces.go index b6e6903..395b0e1 100644 --- a/pkg/security/interfaces.go +++ b/pkg/security/interfaces.go @@ -83,9 +83,19 @@ type Authenticator interface { // Login authenticates credentials and returns a token Login(ctx context.Context, req LoginRequest) (*LoginResponse, error) + // LoginWithCookie authenticates credentials and, when cookie sessions are enabled, + // writes the session cookie to w. Implementations that do not support cookies + // should delegate to Login and ignore w. + LoginWithCookie(ctx context.Context, req LoginRequest, w http.ResponseWriter) (*LoginResponse, error) + // Logout invalidates a user's session/token Logout(ctx context.Context, req LogoutRequest) error + // LogoutWithCookie invalidates a user's session/token and, when cookie sessions are + // enabled, clears the session cookie on w. Implementations that do not support cookies + // should delegate to Logout and ignore w. + LogoutWithCookie(ctx context.Context, req LogoutRequest, w http.ResponseWriter) error + // Authenticate extracts and validates user from HTTP request // Returns UserContext or error if authentication fails Authenticate(r *http.Request) (*UserContext, error) diff --git a/pkg/security/providers.go b/pkg/security/providers.go index 9afbfa4..b634dbb 100644 --- a/pkg/security/providers.go +++ b/pkg/security/providers.go @@ -30,10 +30,18 @@ func (a *HeaderAuthenticator) Login(ctx context.Context, req LoginRequest) (*Log return nil, fmt.Errorf("header authentication does not support login") } +func (a *HeaderAuthenticator) LoginWithCookie(ctx context.Context, req LoginRequest, w http.ResponseWriter) (*LoginResponse, error) { + return a.Login(ctx, req) +} + func (a *HeaderAuthenticator) Logout(ctx context.Context, req LogoutRequest) error { return nil } +func (a *HeaderAuthenticator) LogoutWithCookie(ctx context.Context, req LogoutRequest, w http.ResponseWriter) error { + return a.Logout(ctx, req) +} + func (a *HeaderAuthenticator) Authenticate(r *http.Request) (*UserContext, error) { userIDStr := r.Header.Get("X-User-ID") if userIDStr == "" { @@ -625,6 +633,14 @@ func (a *JWTAuthenticator) Logout(ctx context.Context, req LogoutRequest) error return nil } +func (a *JWTAuthenticator) LoginWithCookie(ctx context.Context, req LoginRequest, w http.ResponseWriter) (*LoginResponse, error) { + return a.Login(ctx, req) +} + +func (a *JWTAuthenticator) LogoutWithCookie(ctx context.Context, req LogoutRequest, w http.ResponseWriter) error { + return a.Logout(ctx, req) +} + func (a *JWTAuthenticator) Authenticate(r *http.Request) (*UserContext, error) { authHeader := r.Header.Get("Authorization") if authHeader == "" {