torii-backend (Ruby)
Backend SDK for torii — verify end-user JWTs without a per-request round trip and manage users from your Ruby server.
v0.x — API may still change.
Setup
Sign in to app.torii.so and from your dashboard copy:
- your issuer URL (e.g.
https://acme.torii.so) - a secret key (
sk_test_…for development,sk_live_…for production)
- your issuer URL (e.g.
Install the gem:
gem install torii-backend
or in your Gemfile:
gem 'torii-backend'
Requires Ruby 3.1+.
- Verify an end-user JWT:
require 'torii/backend'
auth = Torii::Backend.verify_token(token, issuer: 'https://acme.torii.so')
auth.user_id # => "user_abc"
auth.environment_id # => "env_xyz"
auth.email_verified # => true
The first call fetches the issuer's JWKS at {issuer}/_torii/.well-known/jwks.json; subsequent calls reuse a process-wide cache (5-minute TTL, automatic refresh on kid miss). ES256 only.
- Call the backend REST API:
torii = Torii::Backend::Client.new(secret_key: ENV.fetch('TORII_SECRET_KEY'))
user = torii.users.get(user_id)
Default base URL is https://api.torii.so. Override with api_url: for staging or self-hosted.
Rack middleware (Rails / Sinatra / Roda)
# config/application.rb (Rails)
config.middleware.use Torii::Backend::Rack::RequireAuth,
issuer: 'https://acme.torii.so'
# config.ru (Sinatra / plain Rack)
use Torii::Backend::Rack::RequireAuth, issuer: 'https://acme.torii.so'
run MyApp
On success the verified Torii::Backend::Auth is placed at env['torii.auth']. On failure the middleware short-circuits with a 401 JSON body:
{ "error": { "code": "authentication_failed", "message": "..." } }
For ad-hoc verification outside Rack:
auth = Torii::Backend.authenticate_request(
request.env,
issuer: 'https://acme.torii.so',
)
authenticate_request accepts a Rack env, a plain Hash of headers (string or symbol keys), or anything that responds to #each with [name, value] pairs.
Backend API (REST client)
page = torii.users.list(limit: 50)
page[:items] # => [{ id: "...", ... }, ...]
page[:next_cursor] # => "cursor_..." or nil
page[:has_more] # => true / false
user = torii.users.create(email: 'x@y.com')
torii.users.update(user[:id], name: Torii::Backend::Patch.set('New name'))
torii.users.ban(user[:id])
sessions = torii.sessions.list_for_user(user[:id])
torii.sessions.revoke_all_for_user(user[:id])
The REST client is generated from the OpenAPI spec at spec/server-v1.json via openapi-generator-cli (target: ruby); hand-written wrappers in lib/torii/backend/client.rb give it the Ruby-idiomatic surface above.
Partial updates
PATCH fields are tri-state: set to a value, clear (JSON null on the wire), or leave alone. Ruby keyword args can't express that on their own (a literal nil can't be told apart from "absent"), so every kwarg accepted by update must be wrapped in Torii::Backend::Patch:
torii.users.update(user_id,
name: Torii::Backend::Patch.set('New name'), # update the name
phone: Torii::Backend::Patch.set(nil), # null on the wire
# locale, address, date_of_birth omitted -> untouched
)
Patch.set(value) updates the field; Patch.set(nil) clears it; omitted kwargs are left untouched on the server.
Errors
Torii::Backend::Error— base.Torii::Backend::AuthError— raised byverify_token/authenticate_request.Torii::Backend::ApiError— raised by REST calls on non-2xx. Inspectstatus,code,support_id,body.
License
MIT