restyii2yii2-apiyii2-authclient

Yii2 Api - Using Oauth to authenticate user and website?


I am building a service which handle content from different websites. Each website has their own users.

So I need to authenticate the website which is accessing my API and I need to authenticate the user who is logging in from that website.

Since Yii2 can not handle 2 parallel user identities and on this scenario I can not use roles. I decided to build it in the following way:

Handling Website

I have a table called "Website", website contains 2 fields access_token and expiration_token.

From the any of the websites (which are a Yii basic installations) they do:

        $data = array();
        $data['api_key'] = 'xxxxx';
        $data['api_secret'] = 'zzzzzz';

        $client = new Client(['baseUrl' => 'https://website.api/index.php?r=v1']);
        $response = $client->post('website/get-access-token', $data)->send();
        echo "<pre>";
        var_dump($response->content);
        echo "</pre>";

if token is expired they can do another request to entry point 'website/refresh-access-token'

Then every request GET or POST they have to send this access_token, which is saved in SESSION (Token right now expires every 7 days).

This is not handled through any HTTP validation, just straight forward request to api for token.

Handling Users

For this part when a user authenticate using email/password or social networks, I do a request to User Controller, where I have set Bearer Tokens:

public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors['authenticator'] = [
            'class' => CompositeAuth::className(),
            'authMethods' => [
                HttpBearerAuth::className()
            ]
        ];
        return $behaviors;
    }

This part is a work in process, so it is suppose Website will do a request to login entry point:

$client = new Client(['baseUrl' => 'https://website.api/index.php?r=v1']);
        $response = $client->post('user/login', $data)->send();
        echo "<pre>";
        var_dump($response->content);
        echo "</pre>";

This is suppose to get access_token and also check for token expiration date.

My questions are:

Is this a good idea to handle API Requests for my particular scenario? I think there are many calls to get simple data. Is it needed to use token for Getting data?

If I want to use Bearer Tokens for Handling content and User Access how I would do that?


Solution

  • Since Yii2 can not handle 2 parallel user identities

    I think no program or system should maintain parallel user sessions, atleast for those cases. You are building an API so make it stateless, don't use any session. Make it entirely a token based system. See more about it here:

    I'd suggest to use Yii2 RESTful API to map your entities and implement a complete OAuth 2.0 authentication, which is what Bearer tokens are usually used for. Here are 2 more great resources:

    A nice architecture I like and I usually use is by separating the authentication logic from the application, like if they where 2 applications:

    > auth
    > api
    

    The first one: auth receives user's login/password or signup form related inputs or handle third parties authentication, then on success, generates 2 tokens: a long living refresh_token and a short living access_token, as explained in the linked articles. The refresh_token should be then saved in the database as it will live for months or years or forever and will only be used to generate access tokens.

    access_token in the other side could be saved in memory as it will live for very short time and will be retrieved and compared on each request. I think Yii2 cache component is a perfect place to store it as it supports different storages and databases like REDIS or MemCache and also has an expiration attribute that you can set when adding a value so the token will be auto removed when outdated.

    The auth application's private actions, like the one to generate a new access token when it expires, should only use the refresh_token to recognize users, so it may have its own User class using that token to authenticate them.

    The api application, in the other hand, is the one that deliver data. It should know nothing about refresh tokens. The only shared thing between both apps is the cache component. It receives a request holding an access token, see to which user it is linked by searching the cache, if not found then it is either an unknown user or an expired token.

    The following is a working implementation for that logic which you may check: https://github.com/tunecino/yii2-app-builder