The Bug That Looked Like Authentication Failure But Was Actually the Browser Protecting Me

작성자

카테고리:

← 피드로
DEV Community · Parsun kumar Patel · 2026-07-24 개발(SW)

This is a submission for DEV’s Summer Bug Smash: Smash Stories powered by Sentry.

TL;DR

My Angular frontend and ASP.NET Core backend (both mine, both working independently) refused to stay authenticated together. No CORS error, no exception, no stack trace — just a browser silently dropping my auth cookie on every cross-origin request. Root cause: a missing AllowCredentials, a default SameSite=Lax cookie policy, and Angular not sending credentials. Fixed all three, and 5 hours of debugging collapsed into about 10 lines of config.

The Setup

I was wiring up a School ERP frontend (Angular) to HOS, a multi-tenant SaaS backend I built in ASP.NET Core. Two of my own projects — I expected the integration to take minutes. Instead it became the kind of bug that makes you doubt your own code.

The Symptom

Every API request after login returned 401 Unauthorized — even though:

The same endpoint worked perfectly in Postman
Login succeeded and the auth cookie was issued by the backend
The very next request from the browser behaved as if the user had never logged in
Refreshing the page instantly logged the user out

It only broke when frontend and backend were on different origins (localhost:4200 → API on another port). Same-origin, it worked fine.

The Investigation

First assumption: CORS. Standard suspect for cross-origin bugs.

Chrome DevTools disagreed — the preflight returned 200 OK, headers looked correct, no CORS error in the console. That’s what made it dangerous: everything looked fine.

Digging into the Network tab, the actual signal showed up:

The backend did return the auth cookie
The browser never sent it back on the next request

Authentication wasn’t failing. The browser was silently discarding the cookie. Two things were causing that:

The cookie was set with the default SameSite=Lax — which blocks cookies on cross-origin requests in modern browsers.
My CORS policy allowed the origin, but not credentials — so even a compliant cookie would’ve been stripped.
The Fix

  1. CORS policy — allow credentials explicitly:
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAngularClient", policy =>
    {
        policy.WithOrigins("http://localhost:4200")
              .AllowAnyHeader()
              .AllowAnyMethod()
              .AllowCredentials();
    });
});

app.UseCors("AllowAngularClient");

Enter fullscreen mode Exit fullscreen mode

  1. Cookie policy — allow cross-site, force secure:
builder.Services.ConfigureApplicationCookie(options =>
{
    options.Cookie.HttpOnly = true;
    options.Cookie.SameSite = SameSiteMode.None;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});

Enter fullscreen mode Exit fullscreen mode

  1. Angular — actually send credentials:
this.http.get(apiUrl, {
  withCredentials: true
});

Enter fullscreen mode Exit fullscreen mode

Any one of these alone wasn’t enough — all three had to line up before the session persisted correctly.

The Impact

This single misconfiguration silently broke authentication across every protected route in the School ERP: student dashboard, teacher portal, attendance, fees, exams, user management — the entire application depended on it.

Left unfixed, this isn’t a cosmetic bug — it’s a shipped SaaS product where every tenant appears to get randomly logged out on refresh. For a multi-tenant platform, that’s not a bug report, that’s churn.

~5 hours of debugging → 3 config changes, roughly 10 lines of code. The gap between “looks broken beyond repair” and “one missing keyword” is exactly why this bug was worth writing up.

What I Learned

Cross-origin auth bugs don’t throw exceptions — they fail silently, by design, because the browser is enforcing a security boundary, not malfunctioning. The debugging shift that mattered: stop trusting Postman (same-origin-friendly, cookie-permissive) and test from the actual browser instead.

Now, every time I connect a new frontend to HOS, this is non-negotiable upfront:

CORS policy explicitly allows the exact origin + credentials
Cookie policy set to SameSite=None + Secure for cross-origin auth
Frontend HTTP client explicitly sends withCredentials: true
Verified in the Network tab — cookie present on both the response and the next request

If Postman works and the browser doesn’t, the browser isn’t broken. It’s protecting you from exactly the mistake I’d made.

Built while developing HOS, a multi-tenant ASP.NET Core SaaS backend, and its Angular-based School ERP frontend.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다