add auth
This commit is contained in:
+48
-26
@@ -2,56 +2,78 @@ package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/prabhupadasays/spsays-bff/internal/repository"
|
||||
"github.com/prabhupadasays/spsays-bff/pkg/auth"
|
||||
"github.com/prabhupadasays/spsays-bff/pkg/response"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
type ctxKey string
|
||||
|
||||
const UserIDKey contextKey = "user_id"
|
||||
const (
|
||||
userIDKey ctxKey = "user_id"
|
||||
tokenVersionKey ctxKey = "tv"
|
||||
)
|
||||
|
||||
// Auth is a placeholder middleware for JWT authentication.
|
||||
// It extracts the Bearer token from the Authorization header,
|
||||
// validates it, and sets the user ID in the request context.
|
||||
func Auth(jwtSecret string) func(next http.Handler) http.Handler {
|
||||
// RequireAuth is the middleware applied to every protected route.
|
||||
//
|
||||
// It pulls the JWT from the cookie, verifies signature + expiry, then asks
|
||||
// the UserRepo for the current token_version and rejects if the JWT carries
|
||||
// a stale version (password-change or forced logout invalidates older JWTs).
|
||||
//
|
||||
// On success it stuffs (user_id, token_version) into the request context;
|
||||
// handlers read them via UserID() / TokenVersion().
|
||||
func RequireAuth(issuer *auth.Issuer, users *repository.UserRepo) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
response.Error(w, http.StatusUnauthorized, "missing authorization header")
|
||||
raw := auth.Read(r)
|
||||
if raw == "" {
|
||||
response.Error(w, http.StatusUnauthorized, "not authenticated")
|
||||
return
|
||||
}
|
||||
|
||||
parts := strings.SplitN(authHeader, " ", 2)
|
||||
if len(parts) != 2 || strings.ToLower(parts[0]) != "bearer" {
|
||||
response.Error(w, http.StatusUnauthorized, "invalid authorization format")
|
||||
claims, err := issuer.Parse(raw)
|
||||
if err != nil {
|
||||
response.Error(w, http.StatusUnauthorized, "invalid or expired session")
|
||||
return
|
||||
}
|
||||
|
||||
token := parts[1]
|
||||
|
||||
// TODO: validate JWT token and extract user ID
|
||||
_ = token
|
||||
_ = jwtSecret
|
||||
userID := "" // placeholder
|
||||
|
||||
if userID == "" {
|
||||
response.Error(w, http.StatusUnauthorized, "invalid or expired token")
|
||||
u, err := users.FindByID(r.Context(), claims.UserID)
|
||||
if err != nil {
|
||||
if errors.Is(err, repository.ErrUserNotFound) {
|
||||
response.Error(w, http.StatusUnauthorized, "account no longer exists")
|
||||
return
|
||||
}
|
||||
response.Error(w, http.StatusInternalServerError, "auth check failed")
|
||||
return
|
||||
}
|
||||
if u.TokenVersion != claims.TokenVersion {
|
||||
response.Error(w, http.StatusUnauthorized, "session expired — please log in again")
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), UserIDKey, userID)
|
||||
ctx := context.WithValue(r.Context(), userIDKey, claims.UserID)
|
||||
ctx = context.WithValue(ctx, tokenVersionKey, claims.TokenVersion)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserID extracts the user ID from the request context.
|
||||
func GetUserID(ctx context.Context) string {
|
||||
if v, ok := ctx.Value(UserIDKey).(string); ok {
|
||||
// UserID returns the authenticated user's id from the request context.
|
||||
// Returns "" if RequireAuth has not run.
|
||||
func UserID(ctx context.Context) string {
|
||||
if v, ok := ctx.Value(userIDKey).(string); ok {
|
||||
return v
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// TokenVersion returns the JWT's token_version claim from context.
|
||||
func TokenVersion(ctx context.Context) int {
|
||||
if v, ok := ctx.Value(tokenVersionKey).(int); ok {
|
||||
return v
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user