Alexander Garcia
Part 1: The Problem with OAuth Security. A 3-part series in building an open-source OAuth 2.0 security auditor from real-world government experience.
Alexander Garcia is an effective JavaScript Engineer who crafts stunning web experiences.
Alexander Garcia is a meticulous Web Architect who creates scalable, maintainable web solutions.
Alexander Garcia is a passionate Software Consultant who develops extendable, fault-tolerant code.
Alexander Garcia is a detail-oriented Web Developer who builds user-friendly websites.
Alexander Garcia is a passionate Lead Software Engineer who builds user-friendly experiences.
Alexander Garcia is a trailblazing UI Engineer who develops pixel-perfect code and design.
A three-part series on building an open-source OAuth 2.0 security auditor from real-world government experience
For five years, I served as Lead Frontend Engineer on the Identity team at VA.gov, where I architected and built authentication systems processing over 200 million sign-ins for Veterans and their families. During that time, I hand-wrote custom OAuth 2.0 implementations, built cryptographic libraries from scratch (because we couldn't use external dependencies), and witnessed firsthand how easy it is to misconfigure OAuth even when you deeply understand the specifications.
If a team at the Department of Veterans Affairs with security experts, compliance officers, and rigorous review processes struggles with OAuth configuration complexity, what chance do smaller teams have?
That question led me to build OAuth Guardian a CLI tool and npm package that audits OAuth 2.0 implementations against OWASP, NIST, and RFC specifications.
OAuth 2.0 has become the de facto standard for authentication and authorization on the web. It powers sign-in for:
But OAuth's flexibility is both its strength and weakness. The spec provides a framework, not a prescription, leaving critical security decisions up to implementers. The result? A minefield of potential vulnerabilities.
The Problem: PKCE (Proof Key for Code Exchange) is a security extension that protects against authorization code interception attacks. It's essential for public clients like mobile apps and single-page applications.
Real-World Impact: At VA.gov, we couldn't use any existing OAuth libraries because of security constraints. I had to hand-write PKCE implementation, including the cryptographic utilities for:
Working with Node v14 meant no modern crypto conveniences I built everything from primitives. This deep dive showed me how easy it is to get PKCE wrong: incorrect challenge generation, improper validation timing, or state parameter mismatches can all compromise security.
Why It's Missed: Many OAuth servers don't require PKCE for backward compatibility, so developers skip it without realizing the risk.
The Problem: Where you store tokens matters as much as how you obtain them.
What I've Seen:
localStorage (vulnerable to XSS)The Right Way: At VA.gov, we implemented:
The Problem: If your OAuth server doesn't strictly validate redirect URIs, attackers can steal authorization codes.
Real-World Attack:
Attacker registers: https://evil.com
Legitimate app uses: https://myapp.com
Weak validation accepts: https://myapp.com.evil.com
OR: https://myapp.com@evil.com
OR: https://myapp.com?next=https://evil.com
The Fix: Exact match validation only. No wildcards, no subdomain matching, no query parameter appending.
The Problem: The state parameter protects against Cross-Site Request Forgery (CSRF) attacks during the OAuth flow.
How Attacks Work:
Why It's Critical: I built state parameter generation and validation into VA.gov's OAuth implementation. We generate cryptographically random state values, tie them to user sessions, and validate on callback. Without this, account takeover attacks become trivial.
The Problem: Government systems and regulated industries must meet NIST 800-63B compliance for authentication assurance levels (AAL1, AAL2, AAL3).
What I Learned at VA.gov:
We had to ensure our OAuth implementation met AAL2 requirements:
Most OAuth implementations ignore NIST requirements entirely, even when they're legally required.
When I started building OAuth Guardian, choosing TypeScript wasn't just about personal preference it was strategic:
OAuth implementations deal with:
One typo in a security check can create vulnerabilities. TypeScript catches these at compile time:
// TypeScript catches this before it becomes a security bug interface CheckResult { status: CheckStatus; // Enum: PASS | FAIL | WARNING | SKIPPED | ERROR severity?: Severity; // Only present when status is FAIL or WARNING } // This fails at compile time: const result: CheckResult = { status: CheckStatus.PASS, severity: Severity.CRITICAL, // ❌ Type error: PASS shouldn't have severity };
OAuth Guardian implements dozens of security checks. TypeScript makes the intent crystal clear:
export interface CheckContext { targetUrl: string; httpClient: HttpClient; logger?: Logger; config?: Record<string, unknown>; } export abstract class BaseCheck { abstract readonly id: string; abstract readonly name: string; abstract readonly category: CheckCategory; abstract readonly defaultSeverity: Severity; abstract readonly description: string; abstract execute(context: CheckContext): Promise<CheckResult>; }
Anyone extending this system knows exactly what's required. No ambiguity.
OAuth Guardian's target users are security engineers, DevOps teams, and compliance officers. They need:
TypeScript delivers all of this. When someone writes a custom security check, they get full autocomplete and type checking.
OAuth Guardian started as a CLI tool, but the TypeScript architecture makes it easy to extend:
TypeScript ensures consistency across all these interfaces.
Choosing TypeScript + Node.js gave me:
Building this tool from government-scale experience gives it unique advantages:
I've seen OAuth misconfigurations cause:
OAuth Guardian checks for real vulnerabilities, not theoretical ones.
Most security tools focus on OWASP Top 10. OAuth Guardian also validates:
This makes it invaluable for government contractors, healthcare, finance, and regulated industries.
Every failed check includes:
I learned at VA.gov that security tools that only report "FAIL" are useless. Engineers need to know how to fix it.
OAuth Guardian is built for automation:
# Fail builds on critical security issues oauth-guardian $AUTH_SERVER --format json --fail-on critical
This prevents OAuth misconfigurations from reaching production.
In Part 2, I'll walk through the architecture of OAuth Guardian: how the check system works, why I chose specific design patterns, and how TypeScript enabled rapid development without sacrificing security.
In Part 3, I'll share the implementation journey: building the PKCE detection check, implementing the report system, adding YAML configuration with Zod validation, and generating beautiful HTML reports with Handlebars. Plus: the lessons learned shipping an open-source security tool.
# Install globally npm install -g oauth-guardian # Or use with npx (no installation) npx oauth-guardian https://your-oauth-server.com # Generate HTML report oauth-guardian https://accounts.google.com --format html --output report.html
GitHub: github.com/asg5704/oauth-guardian npm: npmjs.com/package/oauth-guardian
Alexander Garcia is a Lead Frontend Engineer who spent 5+ years building authentication infrastructure at VA.gov, processing 200M+ authentications for Veterans and their families. He hand-wrote OAuth 2.0 implementations, built custom cryptographic libraries, and architected systems serving millions of users.
Connect: alexandergarcia.dev | GitHub | LinkedIn
This is Part 1 of a 3-part series. Read Part 2: Architecture & Design →