Ruby SDK
Idiomatic Ruby client for InferaDB with Rails integration.
Coming soon. The Ruby SDK is under active development. The API surface shown here is based on the Rust SDK and may change before release.
Idiomatic Ruby client for InferaDB’s authorization APIs. Requires Ruby 3.2+. Works with Rails, Sinatra, and any Rack-based framework.
Installation
gem "inferadb"
bundle install
Authentication
Three authentication methods:
| Method | Use Case | Security |
|---|---|---|
| Client Credentials (Ed25519 JWT) | Service-to-service | High |
| Bearer Token | User sessions, OAuth | Medium |
| API Key | Testing, simple integrations | Basic |
Client Credentials (Recommended)
require "inferadb"
client = InferaDB::Client.new(
url: "https://engine.inferadb.com",
credentials: InferaDB::ClientCredentials.new(
client_id: "my-client",
private_key: InferaDB::Ed25519PrivateKey.from_pem_file("client.pem"),
certificate_id: "cert-id"
)
)
Bearer Token
client = InferaDB::Client.new(
url: "https://engine.inferadb.com",
token: ENV.fetch("INFERADB_TOKEN")
)
API Key
client = InferaDB::Client.new(
url: "https://engine.inferadb.com",
api_key: ENV.fetch("INFERADB_API_KEY")
)
Permission Checks
vault = client.organization("my-org").vault("production")
# Simple check
allowed = vault.check("user:alice", "can_edit", "document:readme")
With ABAC Context
allowed = vault.check("user:alice", "can_view", "document:readme",
context: { ip_address: "10.0.0.1" }
)
Require — Raises on Deny
# Raises InferaDB::AccessDeniedError if permission is denied
vault.require!("user:alice", "can_edit", "document:readme")
With Consistency Token
allowed = vault.check("user:alice", "can_view", "document:readme",
at_least_as_fresh: revision_token
)
Batch Check
results = vault.check_batch([
{ subject: "user:alice", permission: "can_edit", resource: "document:readme" },
{ subject: "user:bob", permission: "can_view", resource: "document:readme" },
])
results.all_allowed? # => true/false
Relationships
Write
# Returns a revision token
token = vault.relationships.write(
resource: "document:readme",
relation: "editor",
subject: "user:alice"
)
Batch Write
vault.relationships.write_batch([
{ resource: "document:readme", relation: "editor", subject: "user:alice" },
{ resource: "document:readme", relation: "viewer", subject: "user:bob" },
])
List
rels = vault.relationships.list(resource: "document:readme")
Delete
vault.relationships.delete_where(
resource: "document:readme",
relation: "viewer",
subject: "user:bob"
)
Lookups
# What resources can Alice view?
resources = vault.resources
.accessible_by("user:alice")
.with_permission("can_view")
.resource_type("document")
.to_a
# Who can edit this document?
subjects = vault.subjects
.with_permission("can_edit")
.on_resource("document:readme")
.to_a
Testing
MockClient (Fastest)
require "inferadb/testing"
client = InferaDB::Testing::MockClient.new do |mock|
mock.on_check("user:alice", "can_edit", "document:readme").allow
mock.on_check("user:bob", "can_edit", "document:readme").deny
mock.on_check_any_subject("can_view", "document:readme").allow
mock.default_deny
mock.verify_on_teardown! # asserts all expectations were invoked on teardown
end
InMemoryClient (Full Policy Evaluation)
require "inferadb/testing"
client = InferaDB::Testing::InMemoryClient.with_schema_and_data(
schema: <<~IPL,
type document {
relation viewer
relation editor
relation can_view = viewer | editor
}
IPL
data: [
{ resource: "document:readme", relation: "editor", subject: "user:alice" },
{ resource: "document:readme", relation: "viewer", subject: "user:bob" },
]
)
TestVault (Real Instance)
require "inferadb/testing"
vault = InferaDB::Testing::TestVault.create(org, schema: schema_ipl)
# vault auto-cleans up when garbage collected
# call vault.preserve! to keep data for debugging
RSpec Integration
require "inferadb/testing/rspec"
RSpec.describe "Document authorization" do
let(:client) do
InferaDB::Testing::InMemoryClient.with_schema_and_data(
schema: "...",
data: [{ resource: "document:readme", relation: "editor", subject: "user:alice" }]
)
end
let(:vault) { client.organization("test").vault("test") }
it "allows Alice to edit" do
expect(vault.check("user:alice", "can_edit", "document:readme")).to be true
end
it "denies Bob from editing" do
expect(vault.check("user:bob", "can_edit", "document:readme")).to be false
end
end
Minitest Integration
require "inferadb/testing"
class DocumentAuthorizationTest < Minitest::Test
def setup
@client = InferaDB::Testing::InMemoryClient.with_schema_and_data(
schema: "...",
data: [{ resource: "document:readme", relation: "editor", subject: "user:alice" }]
)
@vault = @client.organization("test").vault("test")
end
def test_alice_can_edit
assert @vault.check("user:alice", "can_edit", "document:readme")
end
end
Error Handling
begin
vault.require!("user:alice", "can_edit", "document:readme")
rescue InferaDB::AccessDeniedError
# permission denied
rescue InferaDB::Error => e
if e.retriable?
sleep e.retry_after
retry
end
logger.error("Authorization error: kind=#{e.kind} request_id=#{e.request_id}")
end
ErrorKind values: :unauthorized, :forbidden, :not_found, :rate_limited, :schema_violation, :unavailable, :timeout, :invalid_argument.
Framework Integrations
Rails Controller Concern
# app/controllers/concerns/inferadb_authorization.rb
module InferadbAuthorization
extend ActiveSupport::Concern
private
def authorize_inferadb!(permission, resource)
InferaDB.vault.require!("user:#{current_user.id}", permission, resource)
rescue InferaDB::AccessDeniedError
head :forbidden
end
end
class DocumentsController < ApplicationController
include InferadbAuthorization
before_action :set_document
def show
authorize_inferadb!("can_view", "document:#{@document.id}")
end
def update
authorize_inferadb!("can_edit", "document:#{@document.id}")
@document.update!(document_params)
end
private
def set_document = Document.find(params[:id])
end
Rails Initializer
# config/initializers/inferadb.rb
InferaDB.configure do |config|
config.url = ENV.fetch("INFERADB_URL")
config.credentials = InferaDB::ClientCredentials.new(
client_id: ENV.fetch("INFERADB_CLIENT_ID"),
private_key: InferaDB::Ed25519PrivateKey.from_pem_file(
ENV.fetch("INFERADB_KEY_PATH")
),
certificate_id: ENV.fetch("INFERADB_CERT_ID")
)
config.organization = ENV.fetch("INFERADB_ORG")
config.vault = ENV.fetch("INFERADB_VAULT")
end