I am building a simple web app using React.js for the frontend and Django for the server side.
Thus frontend.herokuapp.com and backend.herokuapp.com.
When I attempt to make calls to my API through the react app the cookie that was received from the API is not sent with the requests.
I had expected that I would be able to support this configuration without having to do anything special since all server-side requests would (I thought) be made by the JS client app directly to the backend process with their authentication cookies attached.
In an attempt to find a solution that I thought would work I attempted to set
SESSION_COOKIE_DOMAIN = "herokuapp.com"
Which while less than ideal (as herokuapp.com is a vast domain) in Production would seem to be quite safe as they would then be on api.myapp.com and www.myapp.com.
However, with this value set in settings.py I get an AuthStateMissing when hitting my /oauth/complete/linkedin-oauth2/ endpoint.
Searching google for AuthStateMissing SESSION_COOKIE_DOMAIN yields one solitary result which implies that the issue was reported as a bug in Django social auth and has since been closed without further commentary.
Any light anyone could throw would be very much appreciated.
I ran into the exact same problem while using herokuapp.com.
I even posted a question on SO here.
According to Heroku documentation:
In other words, in browsers that support the functionality, applications in the herokuapp.com domain are prevented from setting cookies for *.herokuapp.com
Heroku blocks cookies from frontend.herokuapp.com and backend.herokuapp.com
You need to add a custom domain to frontend.herokuapp.com and backend.herokuapp.com
The entire answer https://stackoverflow.com/a/54513216/1501643
Related
I have an Angular app using Electron as the desktop wrapper. And there's a separate Django backend which provides HTTP APIs to the Electron client.
So normally when I call the login API the response header will have a Set-Cookie field containing the sessionId. And I can clearly see that sessionId in Postman, however, I can't see this cookie in my Angular app (Dev tools of Electron).
After some further debugging I noticed a warning sign beside my Set-Cookie in dev tools. It said that the cookie is blocked due to the SameSite being set to Lax. So I found a way to modify the server code to return a None samesite (together with a Secure property; I'm using HTTP):
# settings.py
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_SAMESITE = 'None'
which did work (and the warning sign is gone) but the cookie is still not visible.
So what's the problem here? Why can't (and How can) I see that cookie so as to make sure that the login works in the actual client, not just Postman?
(btw, now both ends are being developed in localhost.)
There's no need to worry. A good way to check if it works is to actually make a request that requires login (after the API has been Postman tested) and see if the desired data are returned. If so, you are good to go (especially when the warning is gone).
If the sessionId cookie is saved it should automatically be included in the request. Unless there's something wrong with the cookie's path; but a / path would be fine.
Why is the cookie not visible: it's probably due to the separation of front and back ends. In Electron, the pages are typically some local HTML files, as one common step during configuration is to probably modify loadURL or something like that in main.js, for instance:
mainWindow.loadURL(`file://${__dirname}/dist/your-project/index.html`);
So the "site" you are accessing from Electron can be considered as local filesystem (which has no domain and hence no cookie at all), and you should see an empty file:// entry in dev tools -> application -> storage -> cookie. It doesn't mean a local path containing all cookies of the Electron app. Although your backend may be on the same local machine, you are accessing as http:// instead of file:// so the browser (Electron) will treat it as an actual web server.
Therefore, your cookies should be stored in another entry like http(s)://localhost and you can't see it in Electron. (Note that the same cookie will work in both HTTP and HTTPS)
If you use Chrome instead to test, you may be able to see it in all cookies. In some cases where the frontend and backend are deployed to the same host you may see the cookie in dev tools. But I guess there're always some reasons why you need Electron to create a desktop app (e.g. Python scripts).
Further reading
Using HTTPS
Although moving to HTTPS does not necessarily solve the original problem, it may be worth doing in order to prevent potential problems and get ready for the publish.
In your case, for the backend, you can use django-sslserver as a temporary solution before getting your SSL, but it uses a self-signed certificate and may make your frontend complain.
To fix this, consider adding the following code to the main process:
# const { app } = require('electron');
if (!app.isPackaged) {
app.commandLine.appendSwitch('ignore-certificate-errors');
}
Now it provides a good way to distinguish between development (unpacked) and production (packed) and only disables certificate check in development in order to make the code work.
Assuming that SESSION_COOKIE_SECURE in your config refers to cookie's secure flag, You ll have to set
SESSION_COOKIE_SECURE = False
because if this flag is set to True the browser will allow this cookie to be set only if you are using an https connection.
PS: This is just for your localhost. Hopefully you ll be using an Https connection in other environments.
I've just finished creating a Django-React app and have pushed the changes to Heroku. The frontend (JS and CSS) appear on the website no problem, but requests to the backend result in the following error:
[blocked] The page at https://lyrics-chords.herokuapp.com/ was not allowed to display insecure content from http://localhost:8000/auth/user
I've consulted the Internet but no one seems to be getting the same error message. Consulting a friend, it seems as if I have to https secure my backend, and futher researching the subject, it seems that there is no free way to upload a SSL/TSL certificate (reference: heroku: set SSL certificates on Free Plan?). Is there a solution to this?
Silly me, really. Turns out, localhost:8000 refers to the computer of the user. https://lyrics-chords.herokuapp.com/ is the server for both the backend and frontend, so updating the backend end URL calls sufficed.
I've developed a web app that includes the functionality for users to log in and signup. I've done everything as per documentation and tutorials, and everything works fine with the flask server.
The issue is: I use gunicorn and start a web server, open the address (localhost:8000) on few different browsers (Brave and Firefox on Linux, and Brave on Android), I can only log in (Single or multiple different users) from only one client. When I try to do so from another one, it throws 400 Bad Request (CSRF Session token missing or CSRF Session tokens do no match).
Now, this doesn't happen when using Flasks Server. It only happens while using gunicorn.
I've deployed the application to Heroku (Using the Free plan), and I want multiple users to sign in at the same time. This happens on all of the other forms my app has.
All environment variables, secret keys are correctly configured, everything works as intended when using Flask Server. Using Gunicorn doesn't cause any other issues except this. Sometimes, logging in from a single client doesn't work too.
Any help would be appreciated. I've already looked at other threads/questions that were related, but they didn't mention the problem I have
Sorry for the late reply (Maybe it can help someone in the future)
The short answer :
use :
with app.app_context():
your code
instead of :
app.app_context().push()
which is never closed
The long answer :
I guess you use Flask-WTF for managing CSRF,
If yes, there is an if bloc (https://github.com/wtforms/flask-wtf/blob/0.15.x/src/flask_wtf/csrf.py#L53) in the generate_csrf function, which check the flask g variable before generating a new CSRF token. It works perfectly, but when the g variable doesn't reinitilize on each new request (see below for the cause) it creates a conflict between the different users trying to log in.
The principal cause of not reinitilizing the flask g variable is an app context which is pushed manually (usually by : app.app_context().push()) but not closed, in this case the app context is never torn down see : Flask app.teardown_appcontext not being called when DEBUG is false
Finally, i think there is something in the flask DEBUG mode, which force tearing down the app context and reinitilize the g variable.
My Durandal SPA app performs BASIC authentication to acquire a session token which it then presents in headers to access Web API controller methods. This works fine.
On successful authentication I cache the access_token in localStorage so I can re-acquire it from local storage to preserve the session in the event of browser closure or refresh. The token is re-acquired but it is rejected by the server with an Unauthorized message.
This question starts by saying that the OP has successfully done what I am trying to do, so it's certainly possible, but the code he shows is a sample of (unsuccessfully) trying to do cookie mapping and I can't divine the nature of my problem from it.
One of the answers to this question says
Fortunately, WIF has a way to mitigate [replay attacks]. By configuring:
<identityConfiguration>
.......
<tokenReplayDetection enabled="true" />
.....
</identityConfiguration>
I do in fact have WIF installed on my development workstation, but I wouldn't know where to start looking for this setting. A search of my HDD found "tokenReplayDetection" in 17 System.IdentityModel related DLLs, but not in any config files.
Does anyone think this is in fact the problem and if so where does it live? Any other thoughts also gratefully received.
I am developing an app, which I will deploy on Heroku. The app is only used within an iframe on another site, so I don't care about the domain name. I plan to deploy my app on example.herokuapp.com instead of using a custom domain on example.com.
My app uses cookies, and I want to be sure that others cannot manipulate my cookies to protect my app against session fixation and similar attacks. If attacker.herokuapp.com is able to set a cookie for herokuapp.com, browsers will not be able to protect me, since herokuapp.com is not a public suffix. See http://w2spconf.com/2011/papers/session-integrity.pdf for a detailed description of the issue.
My question is: When browsers can't protect my users, will Heroku do it by blocking cookies for herokuapp.com?
Just wanted to post an update for anyone who ran across this question as I did. I was working on a similar problem, except that I wanted to purposefully allow access to the same cookie from two different heroku apps.
"herokuapp.com" and "herokussl.com" are now on the Public Suffix List, so your cookies should be safe if they are set for one of those domains. I ended up having to use custom domains in order to share cookies across both apps.
Heroku also released an article on the topic: https://devcenter.heroku.com/articles/cookies-and-herokuapp-com
I just tried to add a cookie from my Heroku app with the response header Set-Cookie: name=value;Path=/;Domain=.herokuapp.com, and to my disappointment, I could see the header intact in my browser. So the Heroku infrastructure does not detect and remove this cross-app supercookie.
I see three possible ways to protect a Heroku app against cross-app supercookies:
Don't use cookies at all.
Use a custom domain.
Verify that each cookie was actually set by your app, and restrict it to the client's IP address by checking the X-Forwarded-For header.
My feature request to Heroku would be that they should filter HTTP responses that goes through their HTTP routing, such that applications hosted on their infrastructure cannot set cookies with Domain=herokuapp.com.
It seems to me that, as long as you set the cookie for example.herokuapp.com, then the cookie is safe from manipulation. The cookie will only be presented to the app running on example.herokuapp.com and to herokuapp.com (where no app runs).