torii / backend
Backend SDK for torii — verify end-user JWTs without a per-request round trip, manage users from your PHP server.
Requires
- php: ^8.2
- ext-curl: *
- ext-json: *
- ext-mbstring: *
- ext-openssl: *
- firebase/php-jwt: ^6.10
- guzzlehttp/guzzle: ^7.8
- guzzlehttp/psr7: ^1.7 || ^2.0
- psr/cache: ^2.0 || ^3.0
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.1 || ^2.0
- psr/simple-cache: ^2.0 || ^3.0
Requires (Dev)
- illuminate/contracts: ^11.0 || ^12.0
- illuminate/http: ^11.0 || ^12.0
- illuminate/support: ^11.0 || ^12.0
- phpunit/phpunit: ^11.0
- symfony/process: ^6.4 || ^7.0
Suggests
- illuminate/support: Required to use the Laravel service provider and middleware (^11.0).
Provides
None
Conflicts
None
Replaces
None
README
Backend SDK for torii — verify end-user JWTs without a per-request round trip and manage users from your PHP 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 SDK:
composer require torii/backend
Requires PHP 8.2+ with the
openssl,curl,json, andmbstringextensions. -
Verify an end-user JWT:
use function Torii\Backend\verify_token; $auth = verify_token( token: $bearerToken, issuer: 'https://acme.torii.so', ); echo $auth->userId, $auth->environmentId, $auth->emailVerified;
The first call fetches the issuer's JWKS; subsequent calls reuse the cache and rotate keys automatically (handled by
firebase/php-jwt'sCachedKeySet). No round trip per request. Pass a PSR-6CacheItemPoolInterfacevia thecache:argument to share JWKS storage with Redis/Memcached. -
Call the backend REST API:
use Torii\Backend\Torii; $torii = Torii::create(secretKey: getenv('TORII_SECRET_KEY')); $user = $torii->users->get($userId);
Authenticate a request
use function Torii\Backend\authenticate_request; // PSR-7 ServerRequestInterface, or any framework whose request exposes headers $auth = authenticate_request($request, issuer: 'https://acme.torii.so'); // Or plain header arrays $auth = authenticate_request( request: ['Authorization' => 'Bearer ' . $token], issuer: 'https://acme.torii.so', );
Laravel
Register the service provider (Laravel 11+ in bootstrap/providers.php):
return [ // ... Torii\Backend\Laravel\ToriiServiceProvider::class, ];
Publish the config and set env vars:
php artisan vendor:publish --tag=torii-config
TORII_SECRET_KEY=sk_live_... TORII_ISSUER=https://acme.torii.so # Optional — defaults to https://api.torii.so # TORII_API_URL=https://api.torii.so
Protect routes with the RequireAuth middleware:
use Torii\Backend\Laravel\Middleware\RequireAuth; Route::middleware(RequireAuth::class)->get('/me', function (Request $request) { return [ 'user_id' => $request->torii_auth->userId, 'env_id' => $request->torii_auth->environmentId, ]; });
On failure the middleware returns 401 with:
{ "error": { "code": "authentication_failed", "message": "..." } }
REST client
use Torii\Backend\Patch; $page = $torii->users->list(limit: 50); $user = $torii->users->create(['email' => 'x@y.com', 'name' => 'Ada']); $torii->users->ban($user->getId()); $sessions = $torii->sessions->listForUser($user->getId()); $torii->sessions->revokeAllForUser($user->getId());
Updating users (tri-state PATCH)
PHP arrays can't natively distinguish "leave this field alone" from "set this field to null", so Users::update() takes an array of Patch instances:
use Torii\Backend\Patch; $torii->users->update($user->getId(), [ 'name' => Patch::set('Ada Lovelace'), // update field 'phone' => Patch::set(null), // explicitly null on the server // omit a key entirely → server leaves that field alone ]);
Patch::set($value)— server updates the field to$value.Patch::set(null)— server clears the field (sends JSONnull).- Omit the key from the patch array entirely — server leaves the field alone.
The REST client is generated by openapi-generator-cli from spec/server-v1.json. To regenerate after a spec change:
npx -y @openapitools/openapi-generator-cli generate \ -i spec/server-v1.json \ -g php \ -o src/Generated \ --additional-properties=invokerPackage=Torii\\Backend\\Generated,packageName=torii-backend-generated # Delete docs/, test/, composer.json, README.md, .travis.yml, .openapi-generator/, etc. afterwards.
Tests
composer install vendor/bin/phpunit
Tests spin up an in-process php -S server that serves a JWKS document signed by a fresh ES256 keypair, then exercise the verifier against it.
License
MIT