Voyti

Voyti

User management, authentication & authorization

REST API

The JSON REST API is optional and pluggable: the base API package carries no resource endpoints of its own, only Bearer-token authentication, RBAC-admin gating, and the shared route groups resource packages plug into. Install a resource package to expose actual endpoints.

There are three route groups, contributed under yiirocks/voytiapiroutes / authenticatedRoutes / publicRoutes respectively:

Params key Middleware Use for
routes Bearer auth + extensions + admin-access check Admin-only endpoints (e.g. user CRUD, RBAC)
authenticatedRoutes Bearer auth + extensions Any authenticated caller acting on their own behalf (e.g. “my profile”, “my sessions”)
publicRoutes Extensions only, no auth Endpoints reachable before a token exists (e.g. login, registration)

Every group still passes through installed extension middleware. The optional rate limiter enforces limits only after Bearer authentication resolves a user, so public routes pass through it unchanged. routes additionally has AccessRuleMiddleware enforce administratorPermissionName. Each resource package also contributes its own OpenAPI paths and schemas, merged into one openapi.json document.

SCIM 2.0
SCIM 2.0

SCIM 2.0 provisioning for identity providers: Voyti users and RBAC roles exposed through Users and Groups resources. See the full SCIM provisioning page for endpoint and behavior details.

Stateless Client
Stateless Client

A REST API for any stateless client: credential login/logout, self-registration, password reset, own-profile and own-sessions management, plus admin RBAC and audit-log endpoints. See the full Stateless Client page for the complete endpoint list.

User CRUD
User CRUD

REST CRUD endpoints for users, built on this package's token authentication and admin-access middleware. Contributes its routes into the shared authenticated group below and its own OpenApiSpecContributorInterface implementation into the merged openapi.json spec - no route or OpenAPI wiring of its own.

Route name Method Path Purpose
voyti/api-v1-users-index GET v1/users List users
voyti/api-v1-users-view GET v1/users/{id} View a user
voyti/api-v1-users-create POST v1/users Create a user
voyti/api-v1-users-update PATCH v1/users/{id} Update a user
voyti/api-v1-users-delete DELETE v1/users/{id} Delete a user
API Base Package
API Base Package

Pulled in automatically as a dependency by resource packages, the base package supplies token authentication, admin-access gating, OpenAPI spec assembly, and the shared route group.

Route name Method Path Purpose
voyti/api-openapi GET openapi.json OpenAPI 3.1 spec (JSON), assembled from every installed resource package. Public, so tooling (Swagger UI, codegen) can fetch it without a Bearer token.

Two console commands are registered under yiisoft/yii-console:

Command Description
voyti:api-token:generate Generate a REST API access token for a user (printed once)
voyti:api-token:revoke Revoke all REST API access tokens for a user

Configuration

// config/params.php
return [
    'yiirocks/voyti' => [
        'api' => [
            'apiTokenLifespan' => 31536000,
        ],
    ],
];
apiTokenLifespan int
0
API token lifetime in seconds. 0 disables expiry entirely (tokens never expire). Enforced when resolving a Bearer token.

Routes are not auto-registered. Pull the voyti-routes-api config group into your router and mount it at whatever prefix you like:

use Yiisoft\Config\Config;
use Yiisoft\Definitions\DynamicReference;
use Yiisoft\Router\Group;
use Yiisoft\Router\RouteCollection;
use Yiisoft\Router\RouteCollectionInterface;
use Yiisoft\Router\RouteCollector;

/** @var Config $config */

return [
    RouteCollectionInterface::class => [
        'class' => RouteCollection::class,
        '__construct()' => [
            'collector' => DynamicReference::to(
                static fn() => (new RouteCollector())
                    ->addRoute(
                        Group::create('/api/')
                            ->routes(...$config->get('voyti-routes-api')),
                    )
            ),
        ],
    ],
];

Requests authenticate with an Authorization: Bearer <token> header. ApiTokenAuthenticationMiddleware resolves the token to a user for that request only and returns 401 when the header is missing or the token is invalid or expired. AccessRuleMiddleware then enforces administratorPermissionName as usual, so API tokens only grant what that permission grants.

API Rate Limiter
API Rate Limiter

Per-user rate limiting for these routes ships as a separate package, voyti-api-rate-limiter, built on yiisoft/rate-limiter. It scopes limits per authenticated user. It applies to every installed package’s authenticated endpoints, while public routes pass through without rate-limit headers because no user identity exists to key the limit. Limited responses carry X-Rate-Limit-Limit, X-Rate-Limit-Remaining, and X-Rate-Limit-Reset headers; requests over the limit get a 429 Too Many Requests response.

No wiring is required: this package’s own middleware chain runs every installed extension package automatically, so installing voyti-api-rate-limiter turns rate limiting on immediately, and removing it turns rate limiting back off.

By default, your application must have a PSR-16 Psr\SimpleCache\CacheInterface implementation configured and bound in your DI container. Any PSR-16 compliant cache works; see the yiisoft/cache documentation for one option and its available backends. Setting useApcu to true drops this requirement entirely: counters are stored in APCu instead, for real atomic compare-and-swap.

// config/params.php
return [
    'yiirocks/voyti' => [
        'api' => [
            'rateLimiter' => [
                'useApcu' => true,
            ],
        ],
    ],
];
requestsPerWindow int
60
Requests allowed per window, per authenticated user.
windowSeconds int
60
Window length in seconds.
useApcu bool
false
Store counters in APCu instead of the host's PSR-16 cache, for real atomic compare-and-swap. Only safe on a single-server deployment - a load-balanced/multi-server host would enforce the limit independently per server instead of across the cluster.
  1. Append routes to yiirocks/voytiapiroutes in config/params.php. They’re spliced into the base package’s shared authenticated group, inheriting Bearer-token auth, extension middleware (e.g. rate limiting), and the admin-access check:

    // config/params.php
    use MyNamespace\MyResourceController;
    use Yiisoft\Router\Route;
    
    return [
        'yiirocks/voyti' => [
            'api' => [
                'routes' => [
                    Route::get('v1/my-resource')
                        ->name('voyti/api-v1-my-resource-index')
                        ->action([MyResourceController::class, 'index']),
                ],
            ],
        ],
    ];

    Route lists merge and append, so multiple resource packages coexist without collision. The group itself isn’t version-scoped: carry your own version segment in each route’s path/name (v1/..., v2/...).

  2. OpenApiSpecContributorInterface (namespace YiiRocks\Voyti\Api\OpenApi, provided by the base package) is the contract you implement and tag with voyti-api.openapi-contributor in config/di.php:

    Method Purpose
    getMethodSpec($routeName, $method) The OpenAPI operation object for a route name + HTTP method your package owns, or null if it isn’t yours.
    schemas() Component schemas to merge into components.schemas, keyed by schema name.
    // config/di.php
    use MyNamespace\MyResourceOpenApiSpecContributor;
    
    return [
        MyResourceOpenApiSpecContributor::class => [
            'class' => MyResourceOpenApiSpecContributor::class,
            'tags' => ['voyti-api.openapi-contributor'],
        ],
    ];

    No wiring beyond the tag is needed: openapi.json merges every installed contributor’s paths and schemas automatically, alongside the base package’s generic info/servers/security shell and ErrorResponse/MessageResponse schemas.