<p>First of all passing the password and username as query strings is one of the most insecure things you can do. It would highly suggest you to <strong>not</strong> do that unless you want to expose your accounts to everyone with minor knowledge.</p>

<p>Furthermore you are mixing Craft 2 with Craft 3. There is no <code>userSession</code> in Craft 3. I don't want to post a code snipped that would work with the way you are trying since would could eventually copy it without knowing the harm it might cause.</p>

<p>In the end: you should either create some kind of access token, don't pass the params via get request or do something similar. Globally passing sensitive data via url is not clever </p>

CC BY-SA 4.0
2018-10-13T18:01:26.617Z
Thanks for the answer. So essentially I would create a access tokens beforehand and hand them out to the users (or provide them in the frontend) that should be allowed to access the API and then check within the API if it was requested via one of the tokens?
Eternal Black
CC BY-SA 4.0
2018-10-14T08:37:24.920Z
Yes. That's correct. Otherwise everyone can see the login name and password of your users. When you do it via token, they can only see the token and are "just" able to take advantage of the api but not of the entire account. The easiest and most secure way is still to just let them login normally via Craft and check if a current user exists instead of making some kind of pseudo oAuth
Robin Schambach
CC BY-SA 4.0
2018-10-16T11:33:28.127Z
I understand. Unfortunately I try to use the Element-API as API for an app. So the actual device wont login itself and thus `Craft::$app->user->isGuest` will always fail as the device doing the request will always be a guest. So I'm required to have some sort of token generated by myself. Probably going to wait for the OAuth plugin if it comes available. Or is there any other build in, secure way inside Craft to easily archive this?
Eternal Black
CC BY-SA 4.0
2018-10-16T13:12:36.173Z
Your solution would be a login as well? I don't see the disadvantage of a normal login? The user needs to insert the login name and password anyway
Robin Schambach
CC BY-SA 4.0
2018-10-16T16:03:16.527Z
I actually want to get rid of the login completely (for now). I know this sounds strange but the goal is to have multiple mobile apps, each used by many people. Each mobile app should get the data from the API (so no user login for now as the data is not related to the end-user/person). I would like to include the "access-token" of a "craft-user" inside each app. So essentially the app is the "craft user". The apps can't login as there wont be any UI for that, neither should a normal person be able to register as a craft-user. I'm sorry, if this is confusing. It's just for data inside the apps
Eternal Black
CC BY-SA 4.0
2018-10-16T18:13:59.927Z
This ends up as a totally different question and has nothing to do with your original one because it's no login anymore. Please create a new one to keep things clean
Robin Schambach
CC BY-SA 4.0
2018-10-13T17:39:15.367Z
2018-10-13T17:49:21.453Z
2018-10-13T17:49:21.453Z
Robin Schambach
<p>First things first: This is quite similar to <a href="https://craftcms.stackexchange.com/questions/17817/how-to-use-the-element-api-plugin-only-when-logged-in">this</a>, yet different.</p>

<p>I'm trying to get authentication/login for Element-API for Craft 3 to work. Meaning I would like to restrict access to certain endpoints that require the client to be logged in and also (essentially, this is the question) have a way to login via the API (or a different way, but preferably over the API).</p>

<p>This is what I got so far:</p>

<pre><code>&lt;?php
use Craft;
use craft\elements\Entry;
use craft\helpers\UrlHelper;

function requireLogin(){
    header("Access-Control-Allow-Origin: *");
    header("Access-Control-Allow-Headers: X-Requested-With");

    if (!Craft::$app-&gt;user-&gt;isGuest) {
        // you are authenticated
    } else {
        // check params
        $loginName = Craft::$app-&gt;request-&gt;getQueryParam('loginName');
        $password = Craft::$app-&gt;request-&gt;getQueryParam('password');

        if (Craft::$app-&gt;user-&gt;login($loginName, $password)) {
            // login success
            $user = Craft::$app-&gt;userSession-&gt;getUser();
        } else {
            // login fails echo message
            $errorCode = Craft::$app-&gt;userSession-&gt;getLoginErrorCode();
            $errorMessage = Craft::$app-&gt;userSession-&gt;getLoginErrorMessage($errorCode, $loginName);
            Craft::$app-&gt;end(JsonHelper::encode(array('data' =&gt; array( ['status' =&gt; 'error','message' =&gt;'wrong login']  ))));
        }
    }

}

return [
...
</code></pre>

<p>using <code>requireLogin();</code> inside the <code>transformer</code> of the given endpoint.</p>

<p>Most of this is copied from the before mentioned, related link. But as I'm no PHP developer I kind of struggle getting it to work.
The error I get is the following with this code:</p>

<blockquote>
  <p>Argument 1 passed to yii\web\User::login() must be an instance of yii\web\IdentityInterface, null given
  as a result of <code>Craft::$app-&gt;user-&gt;login($loginName, $password)</code></p>
</blockquote>

<p>I do understand whats happening and am capable of reading the error, but I'm not very familiar with <code>yii</code>, nor PHP. If someone could point out what needs to be done, which problems also might occur of if I'm on the wrong track or even post a working solution, I would be very grateful.</p>

<craft3><plugin-elementapi><login><authentication><yii>
Craft 3 Element API Authentication/Login
# Craft 3 Element API Authentication/Login

(Asked by: username_0 on 2018-10-13)

First things first: This is quite similar to this, yet different.
I'm trying to get authentication/login for Element-API for Craft 3 to work. Meaning I would like to restrict access to certain endpoints that require the client to be logged in and also (essentially, this is the question) have a way to login via the API (or a different way, but preferably over the API).
This is what I got so far:
user->isGuest) {
        // you are authenticated
    } else {
        // check params
        $loginName = Craft::$app->request->getQueryParam('loginName');
        $password = Craft::$app->request->getQueryParam('password');

        if (Craft::$app->user->login($loginName, $password)) {
            // login success
            $user = Craft::$app->userSession->getUser();
        } else {
            // login fails echo message
            $errorCode = Craft::$app->userSession->getLoginErrorCode();
            $errorMessage = Craft::$app->userSession->getLoginErrorMessage($errorCode, $loginName);
            Craft::$app->end(JsonHelper::encode(array('data' => array( ['status' => 'error','message' =>'wrong login']  ))));
        }
    }

}

return [
...

using requireLogin(); inside the transformer of the given endpoint.
Most of this is copied from the before mentioned, related link. But as I'm no PHP developer I kind of struggle getting it to work.
The error I get is the following with this code:

Argument 1 passed to yii\web\User::login() must be an instance of yii\web\IdentityInterface, null given
  as a result of Craft::$app->user->login($loginName, $password)

I do understand whats happening and am capable of reading the error, but I'm not very familiar with yii, nor PHP. If someone could point out what needs to be done, which problems also might occur of if I'm on the wrong track or even post a working solution, I would be very grateful.

**Tags:** craft3, plugin-elementapi, login, authentication, yii

---

## 1 answers

### Answer by username_1 on 2018-10-13. Score: 1 | Accepted answer

First of all passing the password and username as query strings is one of the most insecure things you can do. It would highly suggest you to **not** do that unless you want to expose your accounts to everyone with minor knowledge.

Furthermore you are mixing Craft 2 with Craft 3. There is no `userSession` in Craft 3. I don't want to post a code snipped that would work with the way you are trying since would could eventually copy it without knowing the harm it might cause.

In the end: you should either create some kind of access token, don't pass the params via get request or do something similar. Globally passing sensitive data via url is not clever

> **Comments:**
> **username_0**: Thanks for the answer. So essentially I would create a access tokens beforehand and hand them out to the users (or provide them in the frontend) that should be allowed to access the API and then check within the API if it was requested via one of the tokens?  
> **username_1**: Yes. That's correct. Otherwise everyone can see the login name and password of your users. When you do it via token, they can only see the token and are "just" able to take advantage of the api but not of the entire account. The easiest and most secure way is still to just let them login normally via Craft and check if a current user exists instead of making some kind of pseudo oAuth  
> **username_0**: I understand. Unfortunately I try to use the Element-API as API for an app. So the actual device wont login itself and thus `Craft::$app->user->isGuest` will always fail as the device doing the request will always be a guest. So I'm required to have some sort of token generated by myself. Probably going to wait for the OAuth plugin if it comes available. Or is there any other build in, secure way inside Craft to easily archive this?  
> **username_1**: Your solution would be a login as well? I don't see the disadvantage of a normal login? The user needs to insert the login name and password anyway  
> **username_0**: I actually want to get rid of the login completely (for now). I know this sounds strange but the goal is to have multiple mobile apps, each used by many people. Each mobile app should get the data from the API (so no user login for now as the data is not related to the end-user/person). I would like to include the "access-token" of a "craft-user" inside each app. So essentially the app is the "craft user". The apps can't login as there wont be any UI for that, neither should a normal person be able to register as a craft-user. I'm sorry, if this is confusing. It's just for data inside the apps  
> **username_1**: This ends up as a totally different question and has nothing to do with your original one because it's no login anymore. Please create a new one to keep things clean  

---

