Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing the bearer token in yii2 rest returns an error of 401

Am using angular2 and yii2 restful services but it fails

This is my angular2 part

In the userservice
 constructor(private http:HttpClientService, private _domaindetails:Domaindetails) { }

profile(val:string="profile"):Observable<User>{
return this.http.get(this.getUserUrl(val))
  .map(this.extractData)

 }

This is the httpclientService

 createAuthorizationHeader(headers: Headers) {
  let token = JSON.parse(localStorage.getItem("currentUser")).token;
  if (token) {
    headers.append('Authorization', 'Bearer ' + token);
    headers.append('Content-Type', 'application/x-www-form-urlencoded');
    headers.append('Content-Type', 'application/json');
   }

  }

post(url, data) {
  let headers = new Headers();
  this.createAuthorizationHeader(headers);
 return this.http.post(url, data, {
    headers: headers
 });
}

This is my backend In Yii2

    public function behaviors()
{
    $behaviors = parent::behaviors();
     $behaviors['corsFilter'] = [
        'class' => \yii\filters\Cors::className(),
        'cors' => [
            // restrict access to
            'Origin' => ['http://localhost:4200'],
            'Access-Control-Request-Method' => ['POST', 'GET','PUT'],
            // Allow only POST and PUT methods
            'Access-Control-Request-Headers' => ['*'],
            // Allow only headers 'X-Wsse'
            // 'Access-Control-Allow-Credentials' => true,
            // Allow OPTIONS caching
            'Access-Control-Max-Age' => 3600,
            // Allow the X-Pagination-Current-Page header to be exposed to the browser.
            'Access-Control-Expose-Headers' => ['X-Pagination-Current-Page'],
        ],
    ];

    $auth = $behaviors['authenticator'] = [
        'class' => HttpBearerAuth::className(),
        'only' => ['can-access','profile'],  //access controller
    ];

   $behaviors['authenticator']['except'] = ['options'];
    return $behaviors;
}

And the yii2 action fails returning an error of unauthorized access

 public function actionProfile()
{

    $user = Yii::$app->user->identity;
    return ['data' => $user];
}

When i check Yii::$app->request->headers;

enter image description here

As you can see the bearer token is set

This is my usermodel

   public static function findIdentityByAccessToken($token, $type = null)
{
    return static::findOne(['auth_key' => $token]);  //auth_key is the value used in bearer token
}

Why does it keep on returning an error 401 unauthorized access and yet when i use the same value of authkey and set authorization bearer headers in postman it works

After a few research i found out that the whenever angular2 makes a request it sends an options request which fails

like image 484
Geoff Avatar asked Jan 23 '17 07:01

Geoff


2 Answers

For those who might face this problem i found out that this was caused by the HttpBearerAuth and when i changed to QueryParamAuth everything is now working i also made a few other changes as

ON THE CONTROLLER
1.Removed the cors filters

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

    $behaviors['authenticator'] = [
        'class' => CompositeAuth::className(),
        'authMethods' => [
            HttpBasicAuth::className(),
            HttpBearerAuth::className(),
            QueryParamAuth::className(),
        ],
    ];
    return $behaviors;

}

2,In my config main.php

     'response' => [
        'format' => yii\web\Response::FORMAT_JSON,
        'charset' => 'UTF-8',
        'on beforeSend' => function ($event) {
            header("Access-Control-Allow-Origin: *");
        }
    ],
        'urlManager' => [
        'class' => 'yii\web\UrlManager',
        'enablePrettyUrl' => true,
        'showScriptName' => false,
        'rules' => [
            ['class' => 'yii\rest\UrlRule', 'controller' => 'auth', 'pluralize'=>false],
            ...other controlers here
        ],

    ],

3.In the .htacess file in the project root i added

   Header set Access-Control-Allow-Origin "*"
   Header set Access-Control-Allow-Headers "Content-Type"

So my angular2 post request looks like

http://127.0.0.1/bcl/api/rest/v1/auth/logout?access-token=your access token

So the access token is always passed as a query parameter

The main reason is because i found out that if the browser sends any header apart from content type an options request is triggered

So now my headers look like

headers.append('Content-Type', 'application/x-www-form-urlencoded'); 
//i removed the bearer token
like image 199
Geoff Avatar answered Nov 01 '22 10:11

Geoff


I used a different approach:

Added

    public function beforeAction($action)
    {
        $this->enableCsrfValidation = false;
        parent::beforeAction($action);

        if (Yii::$app->getRequest()->getMethod() === 'OPTIONS') {
            // End it, otherwise a 401 will be shown.
            Yii::$app->end();
        }

        return true;
    }

in the controller.

Keep the behaviours function as at your question.

As you mentioned, the issue is that the browser sends a preflighted request.

My assumption is that you are making a cross browser request(localhost:4200), so the browser is making an OPTIONS request first to the server to find out the "Access-Control-Allow" settings, but without an access token in the header. So a 401 is thrown and the CORS process fails.

The difference is that this way, you can have the authorization token in a header.

like image 22
Jannes Botis Avatar answered Nov 01 '22 11:11

Jannes Botis