feat(http/mw): bearer token auth middleware with optional mode

This commit is contained in:
2026-04-28 15:34:38 +08:00
parent f88c352e55
commit 782247a239
3 changed files with 189 additions and 1 deletions
@@ -0,0 +1,79 @@
package middleware
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/require"
)
// fakeAuth is a stub SessionResolver used by the auth middleware tests.
// It returns either the configured user (ok=true) or the configured error,
// so each test can target a specific branch in Auth without spinning up
// the real user.Service (which lives in a later phase).
type fakeAuth struct {
user uuid.UUID
err error
}
func (f fakeAuth) ResolveSession(_ context.Context, _ string) (uuid.UUID, bool, error) {
if f.err != nil {
return uuid.Nil, false, f.err
}
return f.user, true, nil
}
func TestAuth_NoTokenAllowedWhenOptional(t *testing.T) {
called := false
mw := Auth(fakeAuth{}, AuthOptions{Optional: true})
h := mw(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
called = true
_, ok := UserIDFromContext(r.Context())
require.False(t, ok)
}))
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
require.True(t, called)
require.Equal(t, http.StatusOK, rec.Code)
}
func TestAuth_NoTokenRejectedWhenRequired(t *testing.T) {
mw := Auth(fakeAuth{}, AuthOptions{})
h := mw(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
t.Fatal("handler should not be called")
}))
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest("GET", "/", nil))
require.Equal(t, http.StatusUnauthorized, rec.Code)
}
func TestAuth_ValidTokenPopulatesContext(t *testing.T) {
uid := uuid.New()
mw := Auth(fakeAuth{user: uid}, AuthOptions{})
h := mw(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
got, ok := UserIDFromContext(r.Context())
require.True(t, ok)
require.Equal(t, uid, got)
}))
req := httptest.NewRequest("GET", "/", nil)
req.Header.Set("Authorization", "Bearer tok")
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
require.Equal(t, http.StatusOK, rec.Code)
}
func TestAuth_BadTokenReturns401(t *testing.T) {
mw := Auth(fakeAuth{err: errors.New("invalid")}, AuthOptions{})
h := mw(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
t.Fatal("handler should not be called")
}))
req := httptest.NewRequest("GET", "/", nil)
req.Header.Set("Authorization", "Bearer x")
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
require.Equal(t, http.StatusUnauthorized, rec.Code)
}