Ruby on Rails

Add Nyoxis threat detection to a Rails application using a Rack middleware class, compatible with Rails 6 and later.

Prerequisites

  • Ruby 3.0 or later
  • Rails 6 or later
  • A Nyoxis workspace API key — get one here

Install

bash
bundle add faraday

net/http from the Ruby standard library also works — see the alternative section at the bottom.

Middleware

Create app/middleware/nyoxis_waf.rb:

ruby
require "faraday" require "json" class NyoxisWAF NYO_API = "https://api.nyoxis.com" # @param app [#call] The Rack app to wrap # @param api_key [String] Your Nyoxis workspace token # @param block_on_high [Boolean] Return 403 when risk == "high" # @param on_error [Symbol] :open (default) or :closed def initialize(app, api_key:, block_on_high: false, on_error: :open) raise ArgumentError, "api_key is required" if api_key.blank? @app = app @api_key = api_key @block_on_high = block_on_high @on_error = on_error @conn = Faraday.new(url: NYO_API) do |f| f.request :json f.response :json f.options.timeout = 3 end end def call(env) req = Rack::Request.new(env) payload = { method: req.request_method, path: req.path, query: req.query_string.presence, ip_addr: req.ip, body: extract_body(env), headers: extract_headers(env) }.compact response = @conn.post( response = @conn.post( "/v0/predict?api_key=#{@api_key}", payload ) verdict = response.body env["nyoxis.verdict"] = verdict if @block_on_high && dig(verdict, "prediction", "risk") == "high" return [403, { "Content-Type" => "application/json" }, ['{"error":"Forbidden"}']] end @app.call(env) rescue => e Rails.logger.warn("[nyoxis] prediction error: #{e.message}") if @on_error == :closed [503, { "Content-Type" => "application/json" }, ['{"error":"Service unavailable"}']] else @app.call(env) end end private def extract_body(env) input = env["rack.input"] return nil unless input body = input.read input.rewind body.presence end def extract_headers(env) env.each_with_object({}) do |(k, v), h| h[k.sub(/^HTTP_/, "").downcase.tr("_", "-")] = v if k.start_with?("HTTP_") end end def dig(hash, *keys) keys.reduce(hash) { |h, k| h.is_a?(Hash) ? h[k] : nil } end end

Register in application.rb

ruby
# config/application.rb require_relative "../app/middleware/nyoxis_waf" module MyApp class Application < Rails::Application # Insert near the top of the middleware stack config.middleware.insert_after( ActionDispatch::RequestId, NyoxisWAF, api_key: ENV.fetch("NYOXIS_API_KEY"), block_on_high: true, ) end end

Acting on the verdict

The verdict is stored in the Rack environment as nyoxis.verdict:

ruby
# app/controllers/application_controller.rb class ApplicationController < ActionController::API before_action :check_nyoxis_verdict private def nyoxis_verdict request.env["nyoxis.verdict"] end def check_nyoxis_verdict prediction = nyoxis_verdict&.dig("prediction") return unless prediction if %w[medium high].include?(prediction["risk"]) render json: { error: "Forbidden" }, status: :forbidden end end end

Access attack details in a specific controller:

ruby
class UsersController < ApplicationController def search prediction = nyoxis_verdict&.dig("prediction") || {} attacks = prediction["attacks"] || [] if attacks.any? { |a| a["kind"] == "sql_injection" && a["confidence"].to_f > 0.8 } Rails.logger.warn "[security] SQL injection signal on #{request.path}" end render json: { users: User.search(params[:q]) } end end

Alternative: pure net/http (no Faraday)

ruby
require "net/http" require "json" require "uri" def call_predict(payload, api_key) uri = URI("https://api.nyoxis.com/v0/predict?api_key=#{api_key}") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.open_timeout = 3 http.read_timeout = 3 req = Net::HTTP::Post.new(uri) req["Content-Type"] = "application/json" req.body = payload.to_json JSON.parse(http.request(req).body) rescue => e Rails.logger.warn("[nyoxis] error: #{e.message}") nil end

Next steps

  • API Reference — complete field descriptions and status codes.
  • Overview — how the classifier and redaction pipeline work.

Cookie preferences

Nyoxis uses essential cookies for authentication and session security. We only enable Analytics after you consent. See our Cookie Policy for details.