Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Windows Tipps & SecurityNighthawk M7 Pro im Test: Flexibler, aber teurer 5G-Router(21.09.2026 um 10:30 Uhr)
Sichere ProgrammierungNeue Gmail-Funktion: So sparst du jetzt Zeit bei Einmalcodes(21.09.2026 um 10:00 Uhr)
Sichere ProgrammierungYour GIF exporter is fine — the container is the problem(21.09.2026 um 10:01 Uhr)
Sichere ProgrammierungCSS, Motion, or GSAP? I Choose by Who Owns the Animation(21.09.2026 um 10:12 Uhr)
Windows Tipps & SecurityNighthawk M7 Pro im Test: Flexibler, aber teurer 5G-Router(21.09.2026 um 10:30 Uhr)
Sichere ProgrammierungNeue Gmail-Funktion: So sparst du jetzt Zeit bei Einmalcodes(21.09.2026 um 10:00 Uhr)
Sichere ProgrammierungYour GIF exporter is fine — the container is the problem(21.09.2026 um 10:01 Uhr)
Sichere ProgrammierungCSS, Motion, or GSAP? I Choose by Who Owns the Animation(21.09.2026 um 10:12 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

From a Broken Side Project OAuth Bug to Enterprise SSO Token Exchange

A Google OAuth bug in my side project accidentally allowed citizens to access an admin dashboard. Three months later, that same debugging experience helped me contribute to designing a secure cross-application authentication flow at…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

A Google OAuth bug in my side project accidentally allowed citizens to access an admin dashboard.



Three months later, that same debugging experience helped me contribute to designing a secure cross-application authentication flow at work.



This post walks through the bug, how I fixed it, and how those same ideas translated into an enterprise SSO architecture.









Table of Contents




  • The Side Project

  • The Bug

  • How I Fixed It

  • The Enterprise Challenge

  • Designing the Handoff Token Flow

  • Security Considerations

  • Lessons Learned









The Side Project



My emergency management platform, CrisisOps, has a fairly straightforward architecture.




  • Node.js + Express

  • PostgreSQL + Prisma

  • Two frontend applications


    • Citizen Portal

    • Admin Dashboard





Both applications shared the same authentication backend.



Google OAuth handled authentication.



Everything worked...



Until it didn't.









The Bug



During testing, I discovered something worrying.



A citizen could:




  1. Sign in normally.

  2. Open the Admin Dashboard URL.

  3. Be treated as authenticated.



The backend correctly verified that the session existed.



What it never verified was whether that session belonged to the application requesting access.



Instead, the same authentication state leaked across application boundaries.




Architecture Diagram Here




Architecture-Diagram



The problem wasn't broken authentication.



It was cross-application session bleeding.



The backend answered:




"Is this session valid?"




But never asked:




"Is this session valid for this application?"










How I Fixed It



Rather than relying solely on authentication, I added multiple authorization layers.






1. Scope Sessions to Their Origin



Instead of issuing one generic session cookie, the backend first determines which frontend initiated the request.




const getAppSource = (req: Request): 'admin' | 'user' => {
const headerSource = (req.headers['x-app-source'] as string | undefined)?.toLowerCase();

if (headerSource === 'admin' || headerSource === 'user')
return headerSource;

const cookieSource = req.cookies?.oauth_from?.toLowerCase();

if (cookieSource === 'admin' || cookieSource === 'user')
return cookieSource;

const referer = (req.headers.referer || '').toLowerCase();

if (referer.includes('admin'))
return 'admin';

return 'user';
};






Based on that context, the backend issues application-specific cookies.




  • admin_accessToken

  • admin_refreshToken

  • user_accessToken

  • user_refreshToken



Now each frontend only accepts sessions intended for it.




Note



The Referer header is only a fallback.



In production, the frontend always sends a custom X-App-Source header, making the origin explicit instead of relying on browser behavior.










2. Reject Unauthorized OAuth Requests Early



Instead of issuing tokens first and checking permissions later, the OAuth callback validates the destination before authentication completes.




const from =
req.cookies?.oauth_from === 'admin'
? 'admin'
: 'user';

if (from === 'admin' && googleUser.role === 'CITIZEN') {
return res.redirect(
`${fallbackUrl}/auth/error?message=${encodeURIComponent(
'Access denied'
)}`
);
}






If a citizen attempts to authenticate into the Admin Portal, the login ends immediately.



No admin cookies are ever created.









3. Protect Every Endpoint



Authentication tells the system who you are.



Authorization determines what you're allowed to do.



The backend enforces a role hierarchy.




const ROLE_HIERARCHY: Record<UserRole, number> = {
CITIZEN: 0,
RESPONDER: 1,
DISPATCHER: 2,
ORG_ADMIN: 3,
GOV_ADMIN: 4,
SUPER_ADMIN: 5,
};






Beyond role checks, routes can also require individual permissions such as:




  • incidents:assign

  • resources:deploy

  • audit:read



That keeps authorization flexible without creating dozens of specialized roles.









The Enterprise Challenge



A few months later, our engineering team faced a similar—but much larger—problem.



Users needed to move between multiple internal applications with one click.



No login screen.



No password prompt.



Just seamless authentication.



Immediately we started asking questions.




  • How do we prevent JWT leakage?

  • How do we stop replay attacks?

  • How do we defend against XSS?

  • How do we protect against CSRF?



Our backend engineer proposed using a Handoff Token, inspired by OAuth 2.0 Token Exchange (RFC 8693).



Because I had already spent time solving authentication boundaries in CrisisOps, the architecture immediately made sense.









Designing the Handoff Token Flow



Instead of passing a user's JWT directly between applications, we issue a short-lived, single-use transition token.




Architecture Diagram Here




Architecture-Diagram-2



The destination application exchanges that token for its own session.



The original JWT never crosses trust boundaries.









Security Considerations



Every design decision addressed a specific attack surface.






Preventing Token Leakage



Rather than storing sessions in local storage, the exchanged session is returned as an HttpOnly, Secure, SameSite=Strict cookie.



Even if an attacker successfully executes JavaScript through an XSS vulnerability, the session cookie remains inaccessible.









Preventing Replay Attacks



The handoff token is:




  • Single-use

  • Valid for only a few seconds

  • Immediately invalidated after exchange



Even if intercepted, it becomes practically useless.









Preventing CSRF



Every transition includes a nonce (or state parameter) generated by the originating application.



The Identity Provider validates this value before issuing a handoff token, preventing unauthorized cross-site transitions.









Lessons Learned



Looking back, the OAuth bug wasn't just a bug.



It was my introduction to trust boundaries.



Three lessons stuck with me.




  • Verify at application boundaries—not just user identity.

  • Never pass long-lived tokens between applications.

  • Side projects teach production architecture in unexpected ways.



The debugging session that once felt like an annoying weekend problem eventually became the mental model I relied on during an enterprise authentication design discussion.



Sometimes the bugs that frustrate us the most become the ideas we build systems around.









Final Thoughts



One of the biggest reasons I continue building side projects is that they let me fail in places where failure is inexpensive.



Those failures often become experience long before they're needed professionally.



Have you ever had a side project teach you something that later became useful at work?



I'd love to hear your story.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten From a Broken Side Project OAuth Bug to Enterprise SSO Token Exchange

Thematisch verwandte Begriffe: From, Broken, Side, Project · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-94030 | A security vulnerability has been detected in SerenityOS up to 3d83e4509…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick