Closed mark-wff closed 2 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.
Definitely possible to run Craft from a subdomain. See craftcms/cms#5303 for a discussion on handling headless authentication.
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.
Ah, alright.
@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)
Okay I played around a bit with my configuration.
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});
}
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?
Transferred this over to our docs repo, since this seems mostly like an opportunity to improve headless documentation.
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.
Closing now that #428 is merged!
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.