CORS and authentication: worked on-premises, failed in production

Does your authentication work on-premises but fails in production? Find out why CORS, SameSite, and credentials are causing this error and how to fix it.

lunes, 13 de julio de 2026 • 6 min read • Q2BSTUDIO Team

Three Causes of Authentication Failures in Production

One of the most frustrating moments in web application development occurs when everything is working perfectly in localhost and, when deployed to production, authenticated requests begin to fail without showing clear errors. This scenario, more common than it seems, is usually due to incorrect management of security mechanisms between different sources. The root cause is not in an obvious bug, but in the difference in behavior between environments: localhost treats requests between ports as 'same origin' loosely, while in production, with different domains or subdomains, the browser applies strict Cross-Origin Resource Sharing (CORS) and cross-site cookie policies.

The problem typically manifests itself in applications that separate the frontend (React, Angular, Vue) from the backend (Express, Node, Django). Locally, both run on localhost with different ports: for example, frontend at :3000 and backend at :4000. Although technically they are different origins (by port), browsers are usually more permissive during development, allowing cookies to be sent without the need for additional settings. However, in production, when the frontend is served from a CDN or a proprietary domain (e.g., app.misitio.com) and the backend from api.misitio.com or an entirely different domain, the browser blocks credentials from being sent unless three key conditions are met: the server's CORS configuration must allow an explicit origin (never a wildcard) and accept credentials; the cookie must have the SameSite=None and Secure attributes to be sent in cross-site contexts; and the frontend must explicitly include the Credentials:'include' option in fetch or withCredentials:true in Axios.

The first point, the CORS configuration, is where many developers are tempted to use origin:'*' during local development. Although it works locally because there is no restriction of credentials, in production the browser ignores that header when the request includes cookies or authentication headers. The server must respond with a specific origin (for example, Access-Control-Allow-Origin: https://app.misitio.com) and also include Access-Control-Allow-Credentials: true. This is a deliberate security limitation of the protocol: a wildcard source cannot be combined with credentials because it would allow any malicious website to read authentication cookies.

The second critical element is the session cookie or token. Historically, cookies were sent to any domain that was on the same site, but with the advent of SameSite (Lax, Strict, None) modern browsers restrict the automatic sending of cookies across sources. For a cookie to be sent from one source to another, it must have SameSite=None (sent in all contexts) and Secure (over HTTPS only). Without these attributes, the browser simply won't include the cookie in the cross-origin request, even if the frontend explicitly requests it. Many server frameworks, such as Express with cookie-parser, do not define these attributes by default, so it is the developer's responsibility to configure them when creating the cookie. Also, in local development environments with HTTP (localhost), the Secure flag cannot be enforced, which reinforces the false sense that everything works.

The third factor, and perhaps the easiest to overlook, is that the frontend must explicitly indicate that it wants to include credentials in the request. In REST APIs, fetch requests with default options do not send cookies or authorization headers unless credentials: 'include' is specified. In axios, the equivalent is withCredentials: true. In local, sometimes the browser sends cookies anyway because both applications are on the same host (localhost), but in production it is mandatory to declare this. Forgetting this detail causes the server to receive a request without a session, and the failure manifests itself as a 401 or a redirect that the frontend does not handle properly.

The solution, therefore, is not to apply just one of these measures, but to align all three: configure CORS with a specific origin and credentials:true; set the cookie with SameSite=None; Secure; and send credentials from the frontend. When these three pieces fit together, authenticated requests flow smoothly into production. However, true learning goes beyond the simple patch: it involves adopting a development mindset geared towards real environments from day one. In Q2BSTUDIO, when we develop custom software or custom applications, we integrate these practices systematically from the design phase, avoiding surprises in the deployment. For example, in our cybersecurity projects, we check that session cookies meet CSRF and XSS attack protection standards, and that the CORS configuration does not expose vulnerabilities. In addition, when we deploy solutions on AWS and Azure cloud services, we ensure that load balancers and SSL certificates are properly configured to enable the Secure attribute in cookies.

This problem also reveals an opportunity to modernize the authentication architecture. Many teams choose to use JWT tokens instead of cookies to avoid the CORS and SameSite messes, although that introduces other challenges such as secure token storage on the frontend. At Q2BSTUDIO we offer business intelligence services with Power BI and we also develop AI agents that are integrated using secure APIs, where authentication is usually based on tokens with authorization headers, which avoids cross-origin cookie problems. However, for applications that inherit systems with cookie-based sessions, the triple alignment described above is indispensable.

Experience shows that trusting that 'on-premises works' is a trap. The differences between development and production environments are not only in configuration, but in execution context. That's why we Q2BSTUDIO recommend including tests in continuous integration pipelines that verify cross-origin behavior, for example using tools such as corsproxy or simulating a deployment in a staging environment with real domains. In addition, our engineering teams apply best practices in the use of AWS and Azure cloud services to ensure that security policies don't accidentally lock credentials. We also develop artificial intelligence solutions for companies, such as virtual assistants or recommendation systems, which require a strong authentication layer; in those cases, we combine AI agents with APIs protected by OAuth2 or JWT tokens, avoiding the problems inherent in cookies.

In short, the silent failure of authenticated requests when moving from local to production is a classic that is solved by reviewing three key points: CORS with explicit origin and credentials, SameSite and Secure cookie, and explicit sending of credentials from the frontend. But beyond the patch, this incident invites us to reflect on the importance of a comprehensive approach to application development, where security and compatibility between environments are considered from the start. At Q2BSTUDIO, as a company specializing in custom application development and business intelligence services, we understand that every detail counts to deliver reliable solutions. That's why, if your team faces similar challenges, we can help you design an authentication architecture that works seamlessly both on-premises and in production, leveraging our expertise in AWS and Azure cloud services, cybersecurity, artificial intelligence, and Power BI. In the end, the goal is for your app to not only work, but to do so securely, scalably, and consistently in any environment.

OUR SERVICES

How we can help you

Do you have a project in mind?

Tell us your vision and we'll turn it into a software solution. Whatever the scope, we make your idea real.