package server import ( "context" "net/http" "github.com/gin-gonic/gin" "github.com/google/uuid" ) // headerUserID is the identity header the gateway injects after resolving a // session to an internal account. const headerUserID = "X-User-ID" // contextKey is an unexported type for request-context keys set by this package. type contextKey string const userIDContextKey contextKey = "scrabble.user_id" // RequireUserID returns middleware that requires a valid X-User-ID header and // stores the parsed account id in the request context. Requests without a // parseable UUID are rejected with 401. The backend treats X-User-ID as the // sole identity input and never derives identity from the request body. func RequireUserID() gin.HandlerFunc { return func(c *gin.Context) { id, err := uuid.Parse(c.GetHeader(headerUserID)) if err != nil { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing or invalid X-User-ID"}) return } c.Request = c.Request.WithContext(context.WithValue(c.Request.Context(), userIDContextKey, id)) c.Next() } } // UserIDFromContext returns the authenticated account id stored by // RequireUserID, and whether it was present. func UserIDFromContext(ctx context.Context) (uuid.UUID, bool) { id, ok := ctx.Value(userIDContextKey).(uuid.UUID) return id, ok }