My authentication method sends a HTTP-only cookie to handle sessions. This works fine using Postman and visiting the "login" URL, but as soon as I attempt this on my Ember.js app I get 401 errors when I refresh the app, meaning that cookies aren't saved. Nor do they appear in chrome inspector... Am I missing a parameter that I have to specify?
HttpOnly cookies are not meant to be used by javascript.
Related
I have application written in asp.net MVC (NetFramework 4.7.2).
When I enter my credential and click Login button
POST to login page return 302 (with auth cookie)
REDIRECT to action returning dashboard (with auth cookie)
Everything works over HTTP, I can use my application.
But over HTTPS after dashboard is loaded auth cookie dissapears (there is no code on JS, maybe browser do it). Cookie has enabled flags HttpOnly and Secure. I use the newest Chrome to browser my app.
It's probably related with console error
Clear-Site-Data" header on '': Unrecognized type "*"
I don't why it is added, I never have such header in code. Is it possible to browser do it?
If the browser drops the cookie it will usually write a message to the dev console about why it is dropping it. Most browsers are very specific about the reason for dropping cookies.
In your case, there seems like the response contains this header: Clear-Site-Data. It's a standard header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data The backend must be returning this header for some reason. Then the browser correctly drops the cookie as instructed.
It's interesting though, why the browser complains about the asterisk value. According to the docs this is one of allowed values for this header.
I have APIs deployed in 2 separate namespaces, admin.abc.com (original) and api.admin.abc.com (new). Upon completing login, a jwt cookie is set by the admin.abc.com site for .admin.abc.com. The cookie is for the Session, Secure and HttpOnly and it does not have any SameSite restrictions set. This cookie works well for all API calls to admin.abc.com.
Due to some new changes requiring some services to deployed separately, there are now services also deployed in the namespace api.admin.abc.com. I have a status page that gives me information about the services, memory, etc. and it works fine for the original namespace. But when I add in a status call to the second namespace, no cookies are passed along and the call fails authentication. However, if I open the URL in another tab in my browser, the cookies are passed to the backend and the call succeeds.
I've looked into setting my own cookies in the header during the request after retrieving the jwt's value. This fails for 2 reasons: 1) I don't believe I can access the jwt's value as the cookie is HttpOnly, and 2) I can't set a cookie in the HttpHeader options. I get a "Refused to Set Unsafe Header" error in the console if I try. If I turn on 'withAuthorization:true', it does set it (but still prints the error) and then actually gets a CORS error.
If I manually disable the HttpOnly flag on the cookie using EditThisCookie extension, the calls work successfully. I don't really think it's an option for me with my company's security, but it technically works.
I know some suggest sending the jwt as an Authorization: Bearer token, which I would do, but because the cookie is HttpOnly, I can't retrieve the value and programmatically set it. Additionally there is another site-wide cookie I'd like to send over at times that I can't really switch to some custom header.
Thoughts on what I can do? Is it not possible? My only other option is that all requests to the new namespace have to be routed through an API built in the old namespace.
I am doing web app using Angular and Node.js (Express) and I have a problem with cookies - they are set into my backend domain instead of my frontend.
When I make a POST request to /auth endpoint, server will return HttpOnly cookies - one is JWT and the second is refresh token. When I inspect network tab in chrome, I can see that server sent these cookies back, but when I inspect Application > Storage > Cookies, nothing is here.
I find out, that cookies are set on my backend domain. (app-backend.com instead of app.com) They are just simply associated with my backend domain.
Wierd thing is, that my app is working just fine on my computer, but when I switch to my phone, cookies are not sent from there (I am using iPhone with Safari or Chrome). Also, when I ran my app on localhost dev server, everything worked aswell.
I tried to set domain in cookie config to my frontend domain, it is not working at all.
Also, Chrome warns me with this message, I don't know if it has anything to do with my problem
A cookie associated with a cross-site resource at "my-domain" 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.
Here is my code on github:
Frontend: https://github.com/TenPetr/dashboard
Backend: https://github.com/TenPetr/dashboard_backend
Thanks for your advices.
You are setting the SameSite=None; Secure attributes in your production.json which is correct. However, depending on your version of iOS / Safari you may be hitting an incompatibility issue where the cookies are incorrectly treated as SameSite=Strict.
In your development set-up you are both: not setting SameSite=None; Secure, and might be using URLs that count as the same site anyway, e.g. serving on localhost can lead to some weird cookie behaviour.
I would try testing your production configuration without the SameSite=None attribute. If this then starts to work on Safari, then you are hitting that bug. You can mitigate this by either setting two versions of the cookie, or adding useragent sniffing. There are more details on https://web.dev/samesite-cookie-recipes
Alternatively, you may be hitting Safari cookie policy issues if you are attempting to set cookies from the back-end server when it's not a site the user actually visits.
I am doing development in reactjs on my localhost. I have an api written in nodejs deployed at https://bianca-service-dev0.cfapps.io
Using react i am calling an auth endpoint in the api to login my user. The auth endpoint returns a token to me in response body and a cookie name CSRF-TOKEN. When i try to view document.cookie i only see the cookies set by my localhost and dont see cookies set by the api.
Can I access cookies set by a different domain?
Not directly.
JavaScript running in the browser can only read cookies associated with the page that the JS is running on.
Requests to other origins (if sent withCredentials) will include the cookies transparently though so you can still use them to access content on the origin that set them.
I have a page loading up in MobileSafari which communicated with another server via CORS.
In desktop browsers (tested Chrome and Safari), I am able to log in, get a session cookie, and have that session cookie be sent back for subsequent requests so that I may be authenticated with all API calls.
However, when I login via Mobile Safari, the cookie does not get sent back on subsequent requests.
I'm using Charles Proxy to spy on what's going on, and it tells me:
POST https://myremoteserver.com/sessions.json passes up my login info
It succeeds and response is received with a valid Set-Cookie header.
GET https://myremoteserver.com/checkout.json is requested, without a Cookie request header.
Server responds as if I am not logged in.
I'm using this snippet with Zepto.js to ensure that the withCredentials: true is properly setup on the XHR object. (pardon the coffeescript)
# Add withCredentials:true to the xhr object to send the remote server our cookies.
xhrFactory = $.ajaxSettings.xhr
$.ajaxSettings.xhr = ->
xhr = xhrFactory.apply(this, arguments)
xhr.withCredentials = yes
xhr
And that snippet works great in desktop browsers, and before I added it I was not able to preserve the session cookies in those desktop browsers.
Is there some quirk in MobileSafari that prevents this from working like desktop browsers? Why does it not work in the same way?
Edit!
here is my CORS headers setup in my rails 2.3 app, fairly standard stuff I believe
def add_cors_headers
if valid_cors_domain
headers['Access-Control-Allow-Origin'] = request.headers['HTTP_ORIGIN']
headers['Access-Control-Expose-Headers'] = 'ETag'
headers['Access-Control-Allow-Methods'] = 'GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD'
headers['Access-Control-Allow-Headers'] = '*,x-requested-with,Content-Type,If-Modified-Since,If-None-Match'
headers['Access-Control-Allow-Credentials'] = 'true'
headers['Access-Control-Max-Age'] = '86400'
end
end
Also today desktop Safari on Mountain Lion started not to send the cookie, behaving just like MobileSafari. I'm not entirely sure if my assessment yesterday was inaccurate, or perhaps Apple is just trolling me...
Also could this be affected by using https:// at the remote url?
I don't know if this solution will work or is acceptable to you but I had the same problem with mobile Safari and a JSONP app. It seemed that Safari was not set to accept third party cookies. I went to Settings > Safari > Accept Cookies and set 'Always' and the problem evaporated. Good luck.
Can I set cookies in a response from a jsonp request?
I believe you are experiencing what I have been seeing in my app. My issue, was caused because iOS Safari, comes with a default option "Prevent Cross-Site Tracking" enabled by default that is causing the browser to block ALL third party cookies, even cookies that are issued by your back-end server from a different domain and CORS is configured correctly.
The only solution to this problem I found was to use a proxy in production like I did in dev. I accomplished this in Azure with Azure Functions and making all request go through a proxy. At that point iOS Safari did not block my cookies everything was set as expected.
I wrote about it in my blog https://medium.com/#omikolaj1/complete-guide-to-deploying-angular-and-asp-net-33a0976d0ec1
You didn't mention whether the remote server is under a different domain or just a different subdomain. I assume is under a different domain.
As #schellsan pointed out you can't set/write cookies to a different domain even if the CORS policy allows it due the 3rd party cookies restriction on safari. It's the latest safari restriction. I guess Firefox is about to do the same.
Workarounds I'm currently evaluating:
Use a redirect on the remote server so that when the client is redirected (the remote URL is in the browser bar) you can set the cookie
Use a custom header
I was running into the same problem.
My setup was:
AngularJS (Ionic) App on Server A with domain a.com
NodeJS with Passport JS as Backend on Server B with domain b.com
The login with the cookie went well on every browser, except Mobile Safari on iOS. Also the change of the mobile cookie (Do not track) settings in iOS did not had any impact on the issue.
Solution was to set a CNAME DNS Record
backend.a.com CNAME b.com
Open an address that sets the cookie via an iFrame - this will set the cookie.