Building a Versioned REST API with Authentication in Yii2 Advanced

Published: (June 9, 2026 at 01:51 AM EDT)
5 min read
Source: Dev.to

Source: Dev.to

Yii2 Advanced comes with separate applications for frontend, backend, console, and shared code in common. It does not include an api application by default, but Yii2 Advanced is designed in a way that makes adding one straightforward. In this post, we’ll create a separate API application, configure REST routes, add versioned URLs like /v1/users and /v2/users, and prepare the structure for authentication. A default Yii2 Advanced project usually looks like this: backend/ common/ console/ frontend/ vendor/ composer.json

To build an API, create a new application folder at the same level as frontend and backend: api/

After adding it, your structure becomes: api/ backend/ common/ console/ frontend/ vendor/ composer.json

Inside the api folder, create this structure: api/ config/ main.php main-local.php params.php controllers/ modules/ runtime/ web/ index.php

The api/web folder is the public document root for the API application. api/web/index.php

Create the entry file: run();

This bootstraps Yii and loads the shared common config plus API-specific configuration. api/config/main.php

Create the main API config file: ‘app-api’, ‘basePath’ => dirname(DIR), ‘controllerNamespace’ => ‘api\controllers’,

'components' => [
    'request' => [
        'csrfParam' => '_csrf-api',
        'parsers' => [
            'application/json' => yii\web\JsonParser::class,
        ],
    ],

    'response' => [
        'format' => yii\web\Response::FORMAT_JSON,
    ],

    'urlManager' => [
        'enablePrettyUrl' => true,
        'showScriptName' => false,
        'rules' => [
            'GET /' => 'site/index',
        ],
    ],
],

];

The important parts are: ‘parsers’ => [ ‘application/json’ => yii\web\JsonParser::class, ],

This allows Yii2 to read JSON request bodies. And: ‘response’ => [ ‘format’ => yii\web\Response::FORMAT_JSON, ],

This makes API responses return JSON by default. api/config/main-local.php

Create a local config file: [ ‘request’ => [ ‘cookieValidationKey’ => ‘generate-a-random-secret-key-here’, ], ], ];

Use a real random string for cookieValidationKey. api/config/params.php

Create an empty params file: ‘ok’, ‘app’ => ‘api’, ]; } }

With this URL rule: ‘rules’ => [ ‘GET /’ => ‘site/index’, ],

You should be able to open: https://api.yourdomain.com/

or locally: http://localhost:8080/

and see: { “status”: “ok”, “app”: “api” }

URL rules are added inside the urlManager component in api/config/main.php: ‘components’ => [ ‘urlManager’ => [ ‘enablePrettyUrl’ => true, ‘showScriptName’ => false, ‘rules’ => [ ‘GET /’ => ‘site/index’, ], ], ],

The rules array belongs inside: components.urlManager

not at the top level of the config. No. Yii2 REST URL rules can generate standard REST endpoints automatically. For example: [ ‘class’ => yii\rest\UrlRule::class, ‘controller’ => ‘user’, ]

generates standard REST routes like: GET /users GET /users/123 POST /users PUT /users/123 PATCH /users/123 DELETE /users/123

Yii2 pluralizes REST controller names by default: user -> /users product -> /products order -> /orders

For multiple controllers, you can group them: [ ‘class’ => yii\rest\UrlRule::class, ‘controller’ => [ ‘user’, ‘product’, ‘order’, ‘payment’, ‘notification’, ], ],

This gives each controller its standard REST URLs. For non-standard endpoints, use extraPatterns. Example: [ ‘class’ => yii\rest\UrlRule::class, ‘controller’ => ‘auth’, ‘extraPatterns’ => [ ‘POST login’ => ‘login’, ‘POST logout’ => ‘logout’, ‘POST refresh-token’ => ‘refresh-token’, ], ],

This creates: POST /auth/login POST /auth/logout POST /auth/refresh-token

So even with many endpoints, you usually do not list all of them manually. You define REST controllers and add only custom routes where needed. The complete URL depends on your API base URL. If your API is hosted at: https://api.yourdomain.com

then the routes become: GET https://api.yourdomain.com/users GET https://api.yourdomain.com/users/123 POST https://api.yourdomain.com/users PUT https://api.yourdomain.com/users/123 PATCH https://api.yourdomain.com/users/123 DELETE https://api.yourdomain.com/users/123

For custom auth routes: POST https://api.yourdomain.com/auth/login POST https://api.yourdomain.com/auth/logout POST https://api.yourdomain.com/auth/refresh-token

If running locally: http://localhost:8080/users http://localhost:8080/auth/login

If pretty URLs are not configured correctly, URLs may include index.php: http://localhost:8080/index.php/users http://localhost:8080/index.php/auth/login

For versioned API URLs like: https://api.yourdomain.com/v1/users https://api.yourdomain.com/v2/users

the recommended Yii2 approach is to use modules. Create this structure: api/ modules/ v1/ Module.php controllers/ UserController.php v2/ Module.php controllers/ UserController.php

Create api/modules/v1/Module.php: [ ‘v1’ => [ ‘class’ => api\modules\v1\Module::class, ], ‘v2’ => [ ‘class’ => api\modules\v2\Module::class, ], ],

Your config now includes the versioned modules. Inside components.urlManager.rules, add versioned REST rules: ‘rules’ => [ [ ‘class’ => yii\rest\UrlRule::class, ‘controller’ => [ ‘v1/user’, ‘v1/product’, ‘v1/order’, ], ], [ ‘class’ => yii\rest\UrlRule::class, ‘controller’ => [ ‘v2/user’, ‘v2/product’, ‘v2/order’, ], ], ],

Now Yii2 maps these controllers: api/modules/v1/controllers/UserController.php api/modules/v2/controllers/UserController.php

to these URLs: /v1/users /v2/users

Create api/modules/v1/controllers/UserController.php: yii\rest\UrlRule::class, ‘controller’ => ‘v1/auth’, ‘extraPatterns’ => [ ‘POST login’ => ‘login’, ‘POST logout’ => ‘logout’, ‘POST refresh-token’ => ‘refresh-token’, ], ],

This creates: POST /v1/auth/login POST /v1/auth/logout POST /v1/auth/refresh-token

Your controller would live at: api/modules/v1/controllers/AuthController.php

Yii2 supports bearer token authentication with yii\filters\auth\HttpBearerAuth. In a REST controller, add: use yii\filters\auth\HttpBearerAuth;

public function behaviors() { $behaviors = parent::behaviors();

$behaviors['authenticator'] = [
    'class' => HttpBearerAuth::class,
];

return $behaviors;

}

Example: HttpBearerAuth::class, ];

    return $behaviors;
}

}

Requests must include an Authorization header: Authorization: Bearer your-token-here

Your common\models\User model should implement: public static function findIdentityByAccessToken($token, $type = null) { return static::findOne([‘access_token’ => $token]); }

For this to work, your user table needs an access_token column, or you need a separate token table. For production APIs, avoid storing permanent plain tokens. A better approach is usually: short-lived access tokens refresh tokens hashed token storage JWT OAuth2

The simple access_token example is useful for learning, but production authentication should be designed more carefully. A versioned API app may look like this: api/ config/ main.php main-local.php params.php modules/ v1/ Module.php controllers/ AuthController.php UserController.php ProductController.php v2/ Module.php controllers/ AuthController.php UserController.php ProductController.php runtime/ web/ index.php backend/ common/ console/ frontend/

In Yii2 Advanced, an API is simply another application beside frontend and backend. You create the api folder manually, give it its own config and web entry point, then use REST URL rules and modules to keep the code organized. The most common pattern is: api/modules/v1/controllers/UserController.php -> /v1/users api/modules/v2/controllers/UserController.php -> /v2/users

This keeps your API versions cleanly separated in both the URL and the codebase.

0 views
Back to Blog

Related posts

Read more »