craftcms / docs

Documentation for Craft CMS, Craft Commerce, and other official products.
https://craftcms.com/docs
39 stars 150 forks source link

Authorizing users in headless mode with React #129

Closed mark-wff closed 2 years ago

mark-wff commented 3 years ago

Description

Is there a best practice how a user management with a SPA (Single Page Application) can/should be implemented? Does Craft have to be provided in the same domain or is it also possible to run Craft in a subdomain?

My current solution is to provide Craft in a subfolder. (Frontend: example.com/ Craft: example.com/craft) It would be nicer to have a subdomain. (Frontend: example.com/ Craft: craft.example.com)

Important is the possibility to log in and out in the SPA to access certain content.

daltonrooney commented 3 years ago

@mark-wff Take a look at the GraphQL Authentication plugin.

My front-end and my CMS are on separate domains. I'm still working through some CORS and cross-site cookie issues, but this will handle the authentication piece for you.

brandonkelly commented 3 years ago

Definitely possible to run Craft from a subdomain. See craftcms/cms#5303 for a discussion on handling headless authentication.

mark-wff commented 3 years ago

If I understand it correctly, there is no mention of a logged in user in ticket craftcms/cms#5303 .

Your statement was:

The user will only actually be “logged in” for the duration of that one request. They won’t get an actual user session this way.

In my case I need a user session. It would be great if we could open this ticket again.

brandonkelly commented 3 years ago

Ah, alright.

Anubarak commented 3 years ago

@mark-wff Just my opinion but I always relied to Yii2 for such things https://www.yiiframework.com/doc/guide/2.0/en/rest-authentication

I really love Yii2 Rest Service and used it in several projects without regret. You can use it with a session too. Even on different domains if you allow auth cookies in your JS library of choice (eg: in Axios you need to define it, others do it automatically)

mark-wff commented 3 years ago

Okay I played around a bit with my configuration.

Current working Solution

Domains: Craft: craft.localhost React: web.craft.localhost:3000

.htaccess

<IfModule mod_headers.c>
    Header always set Access-Control-Allow-Origin "http://web.craft.localhost:3000"
    Header always set Access-Control-Allow-Credentials true
</IfModule>

My Craft-Config (general.php):

'enableCsrfProtection' => true,
'enableCsrfCookie' => true,

'defaultCookieDomain' => '.craft.localhost',

Get CSRF-Token in React

const getCsrfToken = () => {
        axios.get('http://craft.localhost/actions/users/session-info', {withCredentials: true}).then((response) => {
            console.log(response.data.csrfTokenValue);
            window.csrf = response.data.csrfTokenValue;
        });
    }

Login-Function in React

const login = () => {
        const bodyFormData = new FormData();

        bodyFormData.append('CRAFT_CSRF_TOKEN', window.csrf);
        bodyFormData.append('action', 'users/login');
        bodyFormData.append('loginName', 'mark.wolff');
        bodyFormData.append('password', 'TestTest');

        axios.post('http://craft.localhost/actions', bodyFormData, {withCredentials: true});
    }

Nice To Have

This is how the login works for me. However, I can't activate the HeadlessMode like this, because the HeadlessMode disables the routes for some actions:

The loginPath, logoutPath, setPasswordPath, and verifyEmailPath settings will be ignored. (https://craftcms.com/docs/3.x/config/config-settings.html#headlessmode)

Also, it would be nice if the login (and the other User-Actions from: https://craftcms.com/docs/3.x/dev/controller-actions.html#post-entries-save-entry) would also work via a JSON request. Something like:

{
  "csrfToken": "<csrftoken>"
  "loginName": "<loginName>",
  "password": "<password>"
}

I'm also not sure if it's a good way to retrieve the CSRF token via a get request. At the same time there is also the CRAFT_CSRF_TOKEN cookie. But this one is not readable for JS, because it is set to httpOnly. Is it maybe a good way to make the CSRF cookie accessible for JS?

brandonkelly commented 3 years ago

Transferred this over to our docs repo, since this seems mostly like an opportunity to improve headless documentation.

mark-wff commented 3 years ago

Would be good if the documentation for headlessMode was more detailed at this point. But I also think that the headless mode for authentication could be improved to talk with Frontend-Frameworks like React and so on.

AugustMiller commented 2 years ago

Closing now that #428 is merged!

https://craftcms.com/docs/4.x/dev/controller-actions.html