By default, the yii\rest\UrlRule will apply these patterns to any endpoint:
'patterns' => [ 'PUT,PATCH {id}' => 'update', 'DELETE {id}' => 'delete', 'GET,HEAD {id}' => 'view', 'POST' => 'create', 'GET,HEAD' => 'index', '{id}' => 'options', '' => 'options', ]
This means that any request containing OPTIONS commands will be redirected to yii\rest\OptionsAction if your loginAction written inside a class that extends ActiveController .
I suggest redefining patterns , leaving only the verbs used, since your login action does not require any other CRUD actions. this should work with your case:
'rules' => [ [ 'class' => 'yii\rest\UrlRule', 'controller' => ['v1/users'], 'pluralize' => false, 'tokens' => [ '{id}' => '<id:\\w+>' ] ], [ 'class' => 'yii\rest\UrlRule', 'controller' => ['v1/login' => '/v1/users/login'], 'patterns' => [ 'POST' => 'login', '' => 'options', ] ] ],
NOTE. @CreatoR's solution is also a requirement here, and just like it, without defining keys. otherwise, OPTIONS arguments will be rejected if they are not authenticated.
If your login action is defined in a class that extends yii\rest\Controller directly, and not through yii\rest\ActiveController (which should be suitable for authentication actions, since CRUD is not required here), then the same rules should work fine , but you need to manually add actionOptions to your code:
// grabbed from yii\rest\OptionsAction with a little work around private $_verbs = ['POST','OPTIONS']; public function actionOptions () { if (Yii::$app->getRequest()->getMethod() !== 'OPTIONS') { Yii::$app->getResponse()->setStatusCode(405); } $options = $this->_verbs; Yii::$app->getResponse()->getHeaders()->set('Allow', implode(', ', $options)); }