Cookie does not persist across redirect in production - http

I'm building a web application that uses cookies to track the user session. These cookies work flawlessly in development on localhost but they aren't working correctly in production. I suspect this is because I have some cookie settings misconfigured but I'm not sure which.
One thing to note is that the webapp runs at app.goldsky.com and the api runs at api.goldsky.io (note the different TLDs).
The application I'm building uses a tool called WorkOS for user authentication.
The authentication flow is as follows:
User visits website, enters their email and presses the login button
Request is sent to backend (api.goldsky.io)
Backend generates an authentication URL using the WorkOS SDK (of the form api.workos/...) and sends this to the frontend
the frontend navigates to this WorkOS authentication URL and proceeds through the auth flow
If successful, WorkOS redirects the user to my backend (api.goldsky.io/auth/workos/callback)
My backend generates a session token, sets a secure, httpOnly, path=/ cookie with the session token (goldsky_session=...) and redirects the user back to the webapp (app.goldsky.com)
In localhost this all works flawlessly. However, in production I don't see the cookie persist after step 6 completes.
In production, the response to step 5 contains the cookie
however after the redirect back to the webapp, the cookie seems to disappear. Here's the request to app.goldsky.com (the redirect from step 6) and it doesn't have the cookie header.
and just for completeness, here's a screenshot of the cookies for app.goldsky.com - it's empty:
By comparison, the final redirect on localhost contains the cookie:
How come my cookie does not persist after redirecting from api.goldsky.io to app.goldsky.com? Do I need to set the Domain attribute for the cookie? If so, what should I set it to? Maybe this is a SameSite problem?

Turns out I had an nginx misconfiguration issue which was rejecting requests to specific paths. Nginx was only allowing requests to /auth and a few others. My login logic was under /auth but the user query was at /user which nginx was rejecting.

Related

Handle OAuth2 authentication failure using Apigee proxy

I've written my own login app to protect my api following the oauth-login-app example.
I've implemented the web server flow and everything works great.
My question is: how should I handle an authentication failure at step 3? How do I tell he client app that the authentication failed? The user could either press the cancel button, or refuse permission or just enter the wrong details.
When you initiate OAuth 2.0 (dance) with
/authorize
the user-agent land on /login page (created/hosted by you),
post redirect.
enduser(user-agent) submits the username/password
to the page hosted by you. Here you collect the credentials and
submit to Apigee, and if authentication fails, send a HTTP 401
response. Now your application should be in position to re-render
the login page and with a flash "invalid credential".
Now coming to if user is authenticated but rejects the authorization request in
consent page, you should redirect to the "redirect_uri" provided
by client, with error code.
How do I tell he client app that the authentication failed?
The login app will redirect the control back to the application redirect URI - with added error code/description in the URL as hash parameters. In case of success the URL is appended with code or token.
You can do this redirect from your login app directly but I would suggest to make the redirect call first to an Apigee Proxy and let Apigee Proxy send the redirect back to app. Both in case of success and failure. In this way you will have the benefit of using Apigee analytics that helps your understand how many OAuths failed for what reason etc.
EDIT:
You can use the same GenerateAuthorizationCode proxy you have built for the success flow. When login fails or succeeds, in either case you need to pass that information to this proxy. Generally the login app and this proxy should share this information using a common session store. You can not pass this information just using a redirect parameter because that can be changed by the client user agent. When you redirect to the GenerateAuthorizationCode redirect proxy, do so by appending a random session ID in the URL. That id can be used by the GenerateAuthorizationCode proxy to look up the login status from the session store. Then you can either send back a redirect with error or a proper oauth code based on if the login was successful. An easy implementation of the session store can be done using a distributed caching resource in the apigee gateway. Login app can put/get the session using an internal API. While the proxy can use policies to retrieve the session information.

Nancy basic auth password change causes authentication to fail

I have created a self-hosting site using Nancy and Owin. I used Nancy.BasicAuthentication for authentication. Everything works fine until I change the current logged in user's password.
Once the password is changed, if the user creates a request then they are redirected to the 404 error page and the window pops up asking for a username and password.
How can I update the user's credentials after a password change to stop them from losing authentication?
Thanks!
a) Basic auth is very easy to listen in on - consider digest auth instead.
b) Both basic auth and digest auth work on a page by page basis - every request is authenticated individually (the browser just automates the authentication if it already has the credentials)
c) Hopefully a 401 Authentication Required, not a 404 Not Found is returned?
d) I suspect doing anything to allow a previously authenticated user to continue using a site after the password is changed (e.g. cookies) would require code changes to the authentication handler. You could for example set a cookie (crypto required) when a page is successfully authenticated, then not require authentication for further pages if the cookie is available (with a timeout on the cookie).

MVC3 Cookie not included in request until after refresh or visiting a second page

BACKGROUND:
I'm using two MVC3 websites for mixed mode authentication. I'm authenticating a person using windows authentication in Site1, and then forwarding that person onto Site2 which uses Forms authentication. My solution was to gather user information in site1 once the user is authenticated via windows auth. I would then write this info to a cookie, and then redirect to Site 2. Site 2 would then use the info found in the cookie to automatically log in the user using Forms Auth. Both applications are in the same domain and should be able to share cookies, however the cookie isn't available after the redirect until the page is refreshed or by clicking on a link in the site (visiting a 2nd page).
Anyway, here's my problem. I create the cookie and then forward the user to Site2 from Site1.
...{cookie created here and added to response}...
HttpContext.Response.Redirect("http://site2.mydomain.com")
When I do this, there isn't a cookie in the request. However, once on the home page of Site2, I can hit refresh, and then my cookie is part of the request and my authentication works.
I need my Response to write the cookie to the client, then get that cookie added in the request, but it seems to skip that when using Response.Redirect...
UPDATE:
I've read that the request will only have cookies included when the cookie exists before the request is made. Since I'm writing the cookie into the response for the request, only subsequent requests will contain the cookie. So, what I need is a way to force a second request, once they get my response from the initial request. So...
User sends request ---> response returns with cookie ---> force another request (should contain cookie) ---> return requested page.
Can I do this using javascript? Can the javascript check the response for a cookie of a certain name, and when found, cause a redirect to the current page?
If you have to force the refresh to get a second request, you could perhaps append a Query String parameter from Site1's redirect HttpContext.Response.Redirect("http://site2.mydomain.com?refresh=1"), then in Site2, cause a redirect to the same page sans query string parameter.
That's not really ideal though. Could you put that cookie information into a query string for a one off authentication URL that then stores a new cookie and redirects to Site2's homepage?

Cookie is getting reset on AJAX requests

I have two virtual directories, one hosts an application the other hosts a web service layer running WCF with ASP.NET compatibility mode enabled.
The service project has an HTTP module that deals with authentication for incoming requests. The login service writes an authentication cookie to the client.
Subsequent requests are handled via AJAX (jQuery) to the services from the application project (another virtual directory on the same domain.)
Cookie domain is set correctly, the cookie path is "/", the cookie is set to HTTP ONLY so that scripts cannot interact with it.
My issue is the login service seems to be sending the SET-COOKIE header with the correct payload in the cookie, however the subsequent requests are not sending the cookie back to the server, in fact when inspecting the local store the cookie is not even there.
Potentially what could be my issues?
We tracked the issue down to Chrome. Apparently there was a prior bug that seems to be presenting itself again whereby expires cookies are not promoted to session and are instead discarded.

How to preserve authentication for ASP.NET Forms authentication cookie, Http to Https (different domains) and back?

We have a non-SSL ASP.NET web app that allows a user to login (ASP forms authentication, inproc).
Once authenticated, we redirect their browser to an external, SSL secured page on another web site / domain altogether that we do not control.
The client is redirected back to a pre-configured url on our original http web app when done.
However, the customer is then asked to "re-login" again on our side which is undesired...
It seems the forms authentication cookie is destroyed when transitioning between HTTP and HTTPS and back again.
How can I keep the forms authentication cookie alive so that the customer does not have to re-authenticate on the round trip?
It's not being destroyed; you're not authenticating on your domain, so the cookie's not being set on your domain, and thus requests on your domain will not contain said authentication cookie.
This is GOOD. If this didn't happen, then every cookie from every domain you ever visited would get sent with every request. Which is obviously 1) crazy and 2) a security hole. Setting a cookie on mydomain.com should never be visible to pages on myotherdomain.com.
If you're using a 3rd party authentication system, like google, facebook, etc, they'll all have some sort of callback token that you'll have to process and set your own cookies.
Consider to set cookie's domain property for your cookies with more specified can be found here or try this code:
Response.Cookies["your_cookie_name"].Domain = "yourdomain.com";
You're looking for a Single Sign On solution.
It might be a little overkill for your problem, for which you might just want to get the same domainname. But if that isn't an option you might want to take a look at:
Windows Identity Foundation

Resources