Files
todo-api/internal/middleware/auth.go

38 lines
1.1 KiB
Go
Raw Normal View History

package middleware
import (
"net/http"
"code.nochebuena.dev/go/rbac"
"code.nochebuena.dev/go/todo-api/internal/repository"
)
// Auth reads the X-User-ID request header, looks up the user in the database,
// and stores an rbac.Identity in the context.
//
// Returns 401 if the header is absent or the user ID is not found — the two
// cases are intentionally indistinguishable to callers.
func Auth(userRepo repository.UserRepository) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
uid := r.Header.Get("X-User-ID")
if uid == "" {
http.Error(w, `{"code":"UNAUTHENTICATED","message":"missing X-User-ID header"}`,
http.StatusUnauthorized)
return
}
user, err := userRepo.FindByID(r.Context(), uid)
if err != nil {
http.Error(w, `{"code":"UNAUTHENTICATED","message":"user not found"}`,
http.StatusUnauthorized)
return
}
identity := rbac.NewIdentity(user.ID, user.Name, user.Email)
ctx := rbac.SetInContext(r.Context(), identity)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}