Closed aaronbushnell closed 3 years ago
FWIW Laravel’s Airlock add-on does a really good job of handling SPA authentication while still using sessions. https://github.com/laravel/airlock
Wanted to drop that here in case it’s relevant as this progresses!
I am looking for the same functionality. It has so far been a pleasure using Craft and graphQL with nuxtJS for building a PWA with separate back and front ends, however, craft falls short when trying to implement user auth with this stack. In some cases, I really don't even need a user to be able to edit or do anything with the craft entries/assets etc, I just want an endpoint that I can POST data to from a frontend login form that will check that the credentials match a user in the craft DB and return me ok so I can show certain vue routes if the user login is correct.
As a long time user of craft and also of react/vue it would be so awesome if you guys could make craft play nice in this regard. I've always loved Craft and our clients do too but this is pushing me a bit towards using something like Strapi.
Thanks guys!
I just want an endpoint that I can POST data to from a frontend login form that will check that the credentials match a user in the craft DB and return me ok so I can show certain vue routes if the user login is correct.
@steveDL Well that’s super easy for us to do. I just added basic authentication support for web requests, for Craft 3.5.
You can send a request to the users/session-info
action to get some basic info about a user account.
curl "http://example.test/actions/users/session-info" \
-H 'Accept: application/json' \
-u 'admin:password'
Example response:
{
"isGuest": false,
"timeout": 0,
"id": 1,
"uid": "b66b2bfe-badb-478a-81ff-1fceb638a019",
"username": "admin",
"email": "admin@happylager.dev"
}
Or if the username/password are incorrect, you will get a 401 response:
{
"error": "Your request was made with invalid credentials."
}
Note that that Accept: application/json
header is required for the users/session-info
controller action.
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.
If you want to test this out now, change your craftcms/cms
requirement in composer.json
to "3.5.x-dev"
, and then run composer update
.
(I’d still like to add access tokens to user accounts, similar to Laravel Sanctum, at some point, so leaving this open.)
I’ve decided to make basic HTTP auth something you have to opt into, as it was conflicting with server authorization (#6421). So if you want to use it going forward, you will need to add this to config/general.php
:
'enableBasicHttpAuth' => true,
@steveDL working for me w/o a CSRF token
@brandonkelly Thanks for this I am calling this endpoint ok in my project now but I seem to be getting a 200 ok with isGuest: true instead of a 401 or the response with the user details.
That being said it seems to work as you describe in postman.
@steveDL you should be getting a 401 response if both username & password are passed, but don’t match. Maybe you tested without passing any password at all? If so, the whole authentication logic would be skipped.
@brandonkelly @steveDL I am struggling with the same thing. I would like routes within my vue app to be protected using the craft cms user managment, But I have no clue where to start... at first I thought I needed to get a csrf token as described in https://nystudio107.com/blog/using-the-craft-cms-graphql-api-on-the-frontend#controller-of-fury and then use that csrf to post to the user login endpoint but this does not seem to pass cors errors..
So now I am trying this new basic auth functionality When I submit this:
axios.get('http://domain.test/actions/users/session-info', {}, {
auth: {
username: 'admin',
password: 'password',
},
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
}
}).then(response => {
let data = response.data;
console.log(data);
})
The data returned is
csrfTokenValue: "MkpESOtwj38KfcOxdXXo5eECUlWnj7NMASYtgeOwVzcDYHo9PWdPQx8zKy-sMt4OZilxgCYmppKpUwdkkcblDzd_f-WC7xlWVDQtCRAVPAA="
isGuest: true
timeout: 0
even when I post the correct admin user cred. @steveDL did this return the userdata and isGuest: false for you? Also when I go to the backend CP and I login here the login spinner under the login button and the chrome refresh indicator keep spinning without redirecting me to the CP, if I refresh the page I am logged in and inside the CP.. I added these to my config:
'enableBasicHttpAuth' => true,
'enableCsrfProtection' => true,
I also tried this to pass the basic auth in the axios headers:
const token = Buffer.from(`${username}:${password}`, 'utf8').toString('base64')
axios.get('http://domain.test/actions/users/session-info', {}, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Basic ' + token
}
}).then(response => {
console.log(response);
})
But that also never returns the correct info for this user. Passing invalid passwords or even no Auth object at all results in the same response (isGuest: true etc)
If I use postman and add the username/pw under Basic Auth it does return the isGuest false and userinfo
With the axios post I noticed the XMLHttpRequest.withCredentials is false, is this the problem? I'm rather new to cross domain requests
(using Craft CMS 3.5.0-RC1.1 )
@brandonkelly @pieter-janDB - We are experiencing the same thing expect I am able to login to the control panel fine.
At the moment, with my axios setup I posted above, with any user details I am getting the response I posted above which has only isGuest: true, the csrf and timeout: 0. If I use postman then it works exactly as you describe so I am wondering if this is possibly to do with the axios request.
From my understanding using the auth param with axios will add the Authorization header.
@steveDL I think we need the following config with axios..
On the backend server add these headers (for me this was inside /usr/local/etc/nginx/valet/valet.conf for valet, I should make this a different config file for that domain only but have not done this before)
add_header Access-Control-Allow-Origin http://vueappdomain.test;
add_header Access-Control-Allow-Credentials true;
In the vue app add this to the axios instance:
window.axios.defaults.withCredentials = true;
It now returns the user data but only if I am logged into the backend CMS in another tab. When I log out from the backend cms and then send the session-info request I just get isGuest true no matter what auth data I pass
I have been trying many things without success.. I only get returned the userdata when there is an active session (login on the backend via CP login form so there is an active session) no matter what username or password I pass.. It seems like it is skipping the basic auth check..
Also I added the get-csrf function in a module as described here : https://nystudio107.com/blog/using-the-craft-cms-graphql-api-on-the-frontend#controller-of-fury When I pass this token inside the X-CSRF-TOKEN header within the session-info call I get errors on CORS Access to XMLHttpRequest at 'http://domain.test/actions/users/session-info' from origin 'http://vueapp.test' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
But when I remove the X-CSRF-TOKEN header the Access-Control-Allow-Origin is set as should.
I started up xDebug to debug /src/web/Application.php within the authenticate function on line 390 list($username, $password) = $this->getRequest()->getAuthCredentials();
returns null for both username and password. When I use postman these params indeed included my user and password.. So I'm guessing it is still a problem with axios ? I am not sure how postman handles these requests, does it send request from the same domain so cors is not an issue ?
@timkelty Please could you shed some light on how you have this working? Are you using axios?
@steveDL I was just testing via curl
(with 'enableBasicHttpAuth' => true,
):
❯ curl "http://localhost:8089/actions/users/session-info" \
-H 'Accept: application/json' \
-u 'myusername:mypassword'
{"isGuest":false,"timeout":0,"csrfTokenValue":"xxxx","id":2,"uid":"xxxx","myusername":"username","email":"myusername@foo.com"}
You're using Axios' auth
option?
Ah thank you, I have tried using the axios auth option and also with setting the Authorization basic header manually and passing it a base64 string. Curl is working absolutely fine for me and so is postman. I have a feeling that axios could be omitting the auth credentials and so the whole authentication logic is being skipped altogether but I am not sure why it would be omitting them.
I know that using Access-Control-Allow-Origin with the wildcard * means doesn't allow the use of credentials so I have tried changing it to localhost but to no avail
Ok, I did more axios tests.. Using no config at all and posting with :
axios.get('http://xxx.test/actions/users/session-info', {
}).then(response => {
console.log(response);
})
Returns:
With these headers:
And I think this is what @steveDL is posting aswell, looking at your axios.get you pass an url and then an empty object which should be the options object.
But now when I use the options within the axios call like this:
let username = 'admin';
let password = 'adminpw';
axios.get('http://xxx.test/actions/users/session-info', {
headers: {
'Content-Type': 'application/json',
},
auth: {
username: username,
password: password
},
}).then(response => {
console.log(response);
})
It will now do 2 calls (which I understand is needed for basic auth? it will first fire an OPTIONS call?) but they will fail with a CORS error:
1st call:
2nd:
Maybe someone has a little more experience with request/response headers and can spot the mistake..
@pieter-janDB Axios is doing a preflight CORS request because you are (presumably) requesting across different domains. See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests
To configure CORS, you're going to need to add a header, e.g.
Craft::$app->getResponse()->getHeaders()->add('Access-Control-Allow-Origin', '*');
…ideally replacing *
with your other domain.
@timkelty Thanks for the response but I think I am already doing this. I have these headers setup in my valet nginx config:
add_header Access-Control-Allow-Origin http://vueappdomain.test;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Accept, Authorization, Cache-Control, Content-Type, DNT, If-Modified-Since, Keep-Alive, Origin, User-Agent, X-Requested-With";
And if you take a look at the response from the server without options it says: Access-Control-Allow-Origin: http//vueappdomain.test ... (but this doesn't seem to be included when using the Basic Auth options?) Also I read that '*' doesn't work when using Basic Auth thats why I hardcoded the frontend domain.. Also this session-info is inside craft app code so I can't really add that line anyway..
I am also using nginx, currently reading through this https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/
Ah that is no help to be honest.
I have noticed that in safari I get no response headers
@pieter-janDB @steveDL Shot in the dark, but can you try just adding the auth to the url instead of via the auth option?
let username = 'admin';
let password = 'adminpw';
axios.get(`http://${username}:${password}@xxx.test/actions/users/session-info`, {
headers: {
'Content-Type': 'application/json',
},
}).then(response => {
console.log(response);
})
Assuming that doesn't do anything, I'll spin something up and try via Axios and get back to you.
Also, you should be setting a Accept: application/json
header. Content-Type
isn't necessary here since we arent passing any data:
headers: {
'Accept': 'application/json',
},
Oh yes I see I copied the axios call without Accept
header in my example.. But I tried it with Accept, both, in quotes, not in quotes.. The response stays the same as in the screenshot. I changed it in above post to show Accept
instead of Content-Type
doing the call with username:pw@ in front returns the same as when I use no config (1 call and csrf, guest true, timeout 0)
I did notice that when using the configs with headers & auth:L
The first request (that tests the auth?) shows request header 'Accept: application/json'
but the second one shows Accept: */*
Have you guys managed to solve this issue?
@brandonkelly Have you successfully gotten the right response when fetching from JS, if so mind sharing the code?
I can only get curl and postman working..
If I send the request without any Authorization
I get the csrf, isGuest:true,timeout:0
(and when I am logged into the cms in another tab I also get the user info)
But if I add the Authorization
data it gives CORS errors..
Access to XMLHttpRequest at 'http://cmsdomain.test/actions/users/session-info' from origin 'http://vueappdomain.test' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
So it only gets blocked when I pass the Auth and the browser does an extra preflight request.. When I try it from another domain it also gives CORS errors on the first request without auth.. so this makes me think my server nginx config is ok.. you can see screenshots above with my config and the responses I get
@pieter-janDB sounds like you need to add an Access-Control-Allow-Origin
header to the responses. You’ll likely need to send an Access-Control-Allow-Credentials
header as well. You can do that from your nginx config:
add_header Access-Control-Allow-Origin <JS-origin>;
add_header Access-Control-Allow-Credentials true;
There are a number of things that cause browsers to become more strict with CORS requirements, and sending an Authorization
header is one of those.
@brandonkelly This is my nginx config (via Valet) If I change the domain to * it gives me errors saying I need to specify one, and since it is not giving me cors errors when I try to fetch without auth I think everything is set up allright?
Both the vue app and craft cms run via valet now. if I run the app on localhost:8080 it gives me cors errors because it is not the http://vueappdomain.test
so that seems ok.
server {
listen 127.0.0.1:80 default_server;
root /;
charset utf-8;
client_max_body_size 128M;
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
# CORS Rules
add_header Access-Control-Allow-Origin http://vueappdomain.test;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods "GET, POST, PATCH, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Accept, Authorization, Cache-Control, Content-Type, DNT, If-Modified-Since, Keep-Alive, Origin, User-Agent, X-Requested-With, X-Auth-Token, Content-Range, X-CustomHeader, Range,Authorization";
# END of CORS Rules #
internal;
alias /;
try_files $uri $uri/;
}
location / {
# CORS Rules
add_header Access-Control-Allow-Origin http://vueappdomain.test;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Accept, Authorization, Cache-Control, Content-Type, DNT, If-Modified-Since, Keep-Alive, Origin, User-Agent, X-Requested-With, X-Auth-Token, Content-Range, X-CustomHeader, Range,Authorization";
# END of CORS Rules #
rewrite ^ "/Users/pieterjandb/.composer/vendor/laravel/valet/server.php" last;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log "/Users/pieterjandb/.config/valet/Log/nginx-error.log";
error_page 404 "/Users/pieterjandb/.composer/vendor/laravel/valet/server.php";
location ~ [^/]\.php(/|$) {
# CORS Rules
add_header Access-Control-Allow-Origin http://vueappdomain.test;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Accept, Authorization, Cache-Control, Content-Type, DNT, If-Modified-Since, Keep-Alive, Origin, User-Agent, X-Requested-With, X-Auth-Token, Content-Range, X-CustomHeader, Range,Authorization";
# END of CORS Rules #
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass "unix:/Users/pieterjandb/.config/valet/valet.sock";
fastcgi_index "/Users/pieterjandb/.composer/vendor/laravel/valet/server.php";
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME "/Users/pieterjandb/.composer/vendor/laravel/valet/server.php";
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
}
js:
window.axios.get('http://ibccms.test/actions/users/session-info', {
headers: {
'Accept': 'application/json',
},
auth: {
username: username,
password: password
},
}).then(response => {
console.log(response);
})
Above works as long as I do not pass the auth (same with fetch and Authorization
header
Is there anything special about the preflight requests ? I feel like those don't get the right headers but I have no experience with them.
since it is not giving me cors errors when I try to fetch without auth I think everything is set up allright
As said, things get more strict when you pass an Authorization
header. So the fact that it works without one doesn’t help.
I’m not sure what’s going wrong exactly with your nginx config, but you can trust the error the browser is giving you. If it’s saying a header needs to be set, then it’s not getting set properly, at least for the OPTIONS (preflight) request.
I did a test with Axios with a same-origin request, and all worked fine.
However, there are some issues with cross-origin…
As already mentioned, you need to have Access-Control-Allow-Origin "mydomain" and Access-Control-Allow-Header: Authorization set.
@brandonkelly The problem is coming from requireAcceptsJson
in the controller. When the request is cross-origin, it dies here with the OPTIONS request, (Response to preflight request doesn't pass access control check: It does not have HTTP ok status.)
This seems like this might be a problem with any controllers with OPTIONS preflights and requireAcceptsJson
or similar methods.
If I comment that out and ensure proper CORS headers, it works cross-origin as expected.
@timkelty Just updated that function to stop throwing an exception for preflight requests.
That was it !!! got it working aswel after upgrading to aa7d700 commit, Thanks for the help @timkelty @brandonkelly . Hope it works for you too @steveDL , if it doesn't try using the config 4 posts up.(or pieces of it, my nginx setup is with valet) Cheers!
Great work guys, it sounds like this is resolved. Which craft version has this updated controller?
@steveDL Not released yet, but will be part of 3.5.0-RC5.
For anyone else looking for this, I just PR'd to allow for email or usernames in the creds: https://github.com/craftcms/cms/pull/6487
@brandonkelly not a huge deal, but with an invalid login, i'm not seeing the asErrorJson
response you show here: https://github.com/craftcms/cms/issues/5303#issuecomment-657918281 – it just throws UnauthorizedHttpException
and you always get back html.
@timkelty merged!
Ah yeah, I ended up changing the location of the authentication logic in 1e736e893b0b8801f60b47596fa50260d08c1f73, and now it happens before we’ve had a chance to worry about returning error info in the right format. The response code will still be 401 though, and that’s the most important thing.
Yup no biggie since the 401 is really what matters. Thanks!
After completing this request I get some warning in chrome:
A cookie associated with a cross-site resource at http://cmsdomain.test/ was set without the 'SameSite' attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with 'SameSite=None' and 'Secure'. You can review cookies in developer tools under Application>Storage>Cookies
Even though the warning says was set
I don't see any of them when I inspect in applications>cookies..
Craft uses PHP session cookies to maintain sessions across web requests so looking at the changes from chrome cookies ( https://blog.chromium.org/2020/02/samesite-cookie-changes-in-february.html ) I think there needs to be a SameSite=None; Secure
attached to the craftSessionId cookie in order to maintain the php session so I do not have to keep passing basic auth data ?
This is what the cookies I receive from that request look like now.
Firefox says something simular that attribute sameSite
is misused becuase it has the value none
without secure
Is this something I can do, making sure those get attached to the cookie ? or is it inside the craft code? or is it because I am serving test domains over http?
Also maybe this new basic auth functionality is a perfect topic for a new CraftQuest livestream so it gets a bit documented how to do user management with craft as headless CMS
Ok I found that we can set secure and samesite from the config. but this requires php 7.3 so I will need to upgrade first before I can use this I guess. ( sameSiteCookieValue -> This setting requires PHP 7.3 or later. )
@pieter-janDB that’s probably only happening for you, because you have been directly visiting that domain on your browser. If your end users will never login to Craft directly (not including these authenticated Ajax requests), then they will never get any cookies sent for that domain.
But still, you could resolve this by creating a subdomain that is responsible for handling the Ajax requests. It can share the same webroot as your main Craft site – so just talking about adding a new vhost/server record on your web server. Then as long as you never login from that subdomain directly in your browser, you won’t get these warnings either.
@brandonkelly I tried alot of things today but couldn't get this to work... some endusers will also login to the CP so I will need to use the subdomain to query my api requests.
I started with switching to php7.4 local. I then got the vue app and craft cms install working on a secure valet domain (both served over https) For the cms I created a new domainname in valet (this is the same as a new vhost/server record right?) and I never visited this domain in my browser ( https://chapi.test ).
I added these configs :
'enableBasicHttpAuth' => true,
'enableCsrfProtection' => true,
'sameSiteCookieValue' => null,
'useSecureCookies' => true
I get the right user info returned and validated but still no cookies I still get the error:
A cookie associated with a cross-site resource at https://chapi.test/ was set without the `SameSite` attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with `SameSite=None` and `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.
But when I inspect the network request I see Secure is checked
But under application>Cookies>https://vueappdomain.test there is not 1 cookie
I also tried changing some samesite config @ chrome://flags/ but nothing seems to be doing the trick to place these cookies
Could this have something to do with the 'httponly' cookie config?
@timkelty & @steveDL are you experiencing something similar?
@brandonkelly @timkelty @steveDL Did any of you get this to work with CORS ?
I am still struggling.. I also tried hosting them online without any success. I made a new sub-domain A-record to make sure I have not yet logged in from the craft cms api domainname via CP (as mentioned by @brandonkelly ).
I have ssl certificates active for my api domain and vue app domain
I use apache online so I added this to my craft cms domains public folder .htaccess file:
<IfModule mod_headers.c>
Header always set Access-Control-Allow-Origin https://[frontenddomain].com
Header always set Access-Control-Allow-Credentials true
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT, PATCH"
Header always set Access-Control-Allow-Headers "X-CSRF-TOKEN, Accept, Authorization, Cache-Control, Content-Type, DNT, If-Modified-Since, Keep-Alive, Origin, User-Agent, X-Requested-With, X-Auth-Token, Content-Range, X-CustomHeader, Range"
</IfModule>
I am not sure if these allow-methods and headers are needed but I tested it without them as well without success.
I added these configs to craft config:
'enableBasicHttpAuth' => true,
'enableCsrfProtection' => true,
Using postman with basicauth + header ['Accept'] = application/json it does not return the data for the auth passed:
{
"isGuest": true,
"timeout": 0,
"csrfTokenValue": "j4rCbxXR1iQEGDixH62t7r6NvgA4EyryAmILvGQG-pMQkskhO4N37ezmqh9yt5pNcm9t1kD-6vrh69puUF4au24HYY0-T5TKe6SvTAjMJrI="
}
I get the same responses with axios but I am 100% sure the auth data passed is right and it is not a guest..
Hi,
A little follow-up on the issues above. @pieter-janDB and I debugged further and came to the conclusion that the Apache webserver did not support the necessary allowed methods e.g. OPTIONS. After changing the config and allowing the OPTIONS method everything is working fine.
Case closed!
@pieter-janDB I did manage to get this working, however adding headers for this basic auth caused another issue, that @brandonkelly might be able to shed some light on, as I am using graphql. Adding the headers for basic auth broke my graphql API as the headers were then duplicated becasue, I believe, craft already adds the headers for graphql. So I got login working but no graphql queries are able to execute. We've been looking into our nginx config and locking down headers to specific calls like /actions/users/session-info but as soon as I let it serve the php file the headers inside of location gets overridden.
By adding the following to the NGINX Server level block we got the login working
# CORS SOLUTION
add_header Access-Control-Allow-Origin ttps://my-api.staging.mycompany.com;
add_header Access-Control-Allow-Credentials true;
But when we try to make these headers apply only to a specific URI path it fails and it seems that Craft Overrides
# CORS SOLUTION
location '/actions/users/session-info' {
add_header Access-Control-Allow-Origin ttps://my-api.staging.mycompany.com;
add_header Access-Control-Allow-Credentials true;
try_files $uri $uri/ /index.php$is_args$args;
}
@steveDL The graphql/api
action is only concerned with the GraphQL token; it’s not affected by whether someone is logged in. So for now probably best to just stop sending the user auth header for those requests.
@brandonkelly It's not so much that it is affected by someone being logged in. Adding headers to the NGINX Server level block fixes the CORS issue so I can make a call to the /actions/users/session-info route and get the repsonse back perfectly however adding these headers also causes duplicate headers whenever a gql call is made.
So we tried using our nginx config to make these headers (for the login) apply only to a specific URI path (location '/actions/users/session-info' ) but it seems these headers get overridden by craft and they are not added for that specific route. This one is becoming quite critical for us with a go live date approaching. 😬
@steveDL Sorry, I read your comment too quickly and assumed you were referring to the Authentication
request header, rather than the CORS response headers.
Craft will only set Access-Control-Allow-Origin
and Access-Control-Allow-Credentials
headers in two cases: GraphQL API requests and Live Preview requests. It won’t set them for the users/session-info
action. So I suspect this is just an issue with your Nginx config.
Maybe this is just a typo from posting on GitHub, but your example Access-Control-Allow-Origin
header has an invalid URL (missing the h
in https://
).
If that wasn’t the culprit, try creating a test.json
file in your webroot (contents set to {}
) , and change your try_files
line to:
try_files /test.json;
Then test the /actions/users/session-info
request and see if you’re getting the expected response headers back. If you are, then you may be right that Craft is somehow at fault here, and we can look into it further.
@brandonkelly My apologies you are correct it was nginx config related turns out we have to conditionally wrap the method of the request and apply headers for each also like so. Thank you for your time!
location '/actions/users/session-info' {
add_header Access-Control-Allow-Origin https://sanroque-fe.staging.doodle.je;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Headers Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modifi$
add_header Access-Control-Allow-Methods GET,POST,OPTIONS,PUT,DELETE,PATCH;
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin https://sanroque-fe.staging.doodle.je;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS,PUT,DELETE,PATCH;
add_header Access-Control-Allow-Headers Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,I$
return 204;
}
if ($request_method = 'GET') {
add_header Access-Control-Allow-Origin https://sanroque-fe.staging.doodle.je;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS,PUT,DELETE,PATCH;
add_header Access-Control-Allow-Headers Authorization,Accept,Origin;
return 200;
}
try_files $uri $uri/ /index.php$is_args$args;
}
on a side note I am trying to now submit contact forms with this setup, are there any easier ways to do this? I think I may have to use the element API to get a csrf token and sumbit the form?
@steveDL You can get the CSRF token via that /actions/users/session-info
endpoint. Element API won’t help you with that.
For anyone still looking for a GraphQL authentication solution, I've just released a plugin which (hopefully!) handles everything you need: https://plugins.craftcms.com/graphql-authentication
I was wondering if anyone could provide insight on how this works in the case of Commerce. When sending requests to things like the Cart, Addresses, Payments, Add to Cart, etc. This was previously handled via cookies and I believe the controllers for these respective actions used the "currentUser" helper function to determine who to associate those requests with via the cookies.
Are these cookies still being set when accessing the "/actions/users/session-info" with the appropriate credentials or do we now need to include the userId
that is returned when making requests to Commerce? Conditionally, if the cookies are not being set, does Commerce even accept a userId param out of the box on the normal routes that Commerce uses?
Description
Now that Craft has fantastic support for running in a headless mode I’d love to have a built-in way to authenticate users when the front end is disconnected from Craft. For instance, if I’m running the front end on something like Next.js, Nuxt.js or create-react-app.
Additional info