package middleware import ( "context" "net/http" "strings" "datarush/internal/gw/domain" "datarush/internal/gw/grpc_client" ) type contextKey string const ( UserIDKey contextKey = "user_id" ) type AuthMiddleware struct { authClient *grpc_client.AuthClient } func NewAuthMiddleware(authClient *grpc_client.AuthClient) *AuthMiddleware { return &AuthMiddleware{ authClient: authClient, } } func (m *AuthMiddleware) Authenticate(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { authHeader := r.Header.Get("Authorization") if authHeader == "" { respondWithError(w, domain.NewUnauthorizedError("missing authorization header")) return } parts := strings.Split(authHeader, " ") if len(parts) != 2 || parts[0] != "Bearer" { respondWithError(w, domain.NewUnauthorizedError("invalid authorization header format")) return } token := parts[1] userID, err := m.authClient.ValidateToken(r.Context(), token) if err != nil { respondWithError(w, domain.NewUnauthorizedError("invalid token")) return } ctx := context.WithValue(r.Context(), UserIDKey, userID) next.ServeHTTP(w, r.WithContext(ctx)) }) } func GetUserIDFromContext(ctx context.Context) (string, error) { userID, ok := ctx.Value(UserIDKey).(string) if !ok || userID == "" { return "", domain.ErrUnauthorized } return userID, nil } func respondWithError(w http.ResponseWriter, err *domain.AppError) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(err.StatusCode) response := domain.NewErrorResponse(err.Err, err.Message) w.Write([]byte(`{"error":"` + response.Error + `","message":"` + response.Message + `"}`)) }