Back to blog
SecurityJanuary 1, 2024Β· 13 min read

OAuth and Authentication Flow Detection: Analyzing Login Security

A practical Fusebox guide to oauth and authentication flow detection.

OAuth and Authentication Flow Detection: Analyzing Login Security

Authentication is the gateway to your web application, and understanding how sites implement OAuth and other authentication methods is crucial for security assessment. This guide explores how to detect authentication flows, identify OAuth providers, and analyze authentication security implementations.

Run This Authentication Detector Now

// Copy and paste this into your browser console to analyze authentication flows

class AuthFlowDetector {
    constructor() {
        this.authProviders = {
            google: {
                domains: ['accounts.google.com', 'oauth2.googleapis.com'],
                endpoints: ['/o/oauth2/auth', '/o/oauth2/v2/auth'],
                params: ['client_id', 'redirect_uri', 'scope']
            },
            facebook: {
                domains: ['www.facebook.com', 'graph.facebook.com'],
                endpoints: ['/dialog/oauth', '/v2.0/dialog/oauth'],
                params: ['app_id', 'redirect_uri', 'scope']
            },
            github: {
                domains: ['github.com'],
                endpoints: ['/login/oauth/authorize'],
                params: ['client_id', 'redirect_uri', 'scope']
            },
            microsoft: {
                domains: ['login.microsoftonline.com', 'login.live.com'],
                endpoints: ['/oauth2/v2.0/authorize', '/oauth20_authorize.srf'],
                params: ['client_id', 'redirect_uri', 'scope']
            },
            twitter: {
                domains: ['api.twitter.com', 'twitter.com'],
                endpoints: ['/oauth/authenticate', '/oauth/authorize'],
                params: ['oauth_consumer_key', 'oauth_callback']
            },
            linkedin: {
                domains: ['www.linkedin.com'],
                endpoints: ['/oauth/v2/authorization'],
                params: ['client_id', 'redirect_uri', 'scope']
            }
        };
        
        this.detectedFlows = [];
        this.forms = [];
        this.socialLogins = [];
    }
    
    detectAuthenticationFlows() {
        console.log('πŸ” Detecting Authentication Flows...\n');
        
        // Detect login forms
        this.detectLoginForms();
        
        // Detect OAuth buttons and links
        this.detectOAuthProviders();
        
        // Analyze authentication endpoints
        this.analyzeAuthEndpoints();
        
        // Check for JWT usage
        this.detectJWTUsage();
        
        // Analyze session management
        this.analyzeSessionManagement();
        
        // Generate security report
        this.generateAuthReport();
    }
    
    detectLoginForms() {
        const forms = document.querySelectorAll('form');
        
        forms.forEach(form => {
            const hasPasswordField = form.querySelector('input[type="password"]');
            const hasEmailField = form.querySelector('input[type="email"], input[name*="email"], input[name*="username"]');
            
            if (hasPasswordField) {
                const authForm = {
                    action: form.action || 'same-origin',
                    method: form.method || 'GET',
                    hasCSRF: !!form.querySelector('input[name*="csrf"], input[name*="token"]'),
                    fields: [],
                    security: []
                };
                
                // Analyze form fields
                form.querySelectorAll('input').forEach(input => {
                    authForm.fields.push({
                        type: input.type,
                        name: input.name,
                        autocomplete: input.autocomplete,
                        required: input.required
                    });
                });
                
                // Check security features
                if (!form.action || form.action.startsWith('http://')) {
                    authForm.security.push('⚠️ Form uses insecure HTTP');
                }
                
                if (!authForm.hasCSRF) {
                    authForm.security.push('⚠️ No CSRF token detected');
                }
                
                if (form.method.toUpperCase() === 'GET') {
                    authForm.security.push('🚨 Form uses GET method (credentials in URL)');
                }
                
                this.forms.push(authForm);
            }
        });
    }
    
    detectOAuthProviders() {
        const links = document.querySelectorAll('a, button');
        
        links.forEach(element => {
            const text = element.textContent.toLowerCase();
            const href = element.href || element.onclick?.toString() || '';
            
            Object.entries(this.authProviders).forEach(([provider, config]) => {
                if (text.includes(provider) || 
                    config.domains.some(domain => href.includes(domain))) {
                    
                    this.socialLogins.push({
                        provider,
                        element: element.tagName,
                        text: element.textContent.trim(),
                        url: href,
                        detected: new Date().toISOString()
                    });
                }
            });
        });
    }
    
    analyzeAuthEndpoints() {
        // Check for common authentication endpoints
        const commonEndpoints = [
            '/login', '/signin', '/auth', '/authenticate',
            '/api/auth', '/api/login', '/oauth/authorize',
            '/saml/login', '/cas/login', '/sso'
        ];
        
        commonEndpoints.forEach(endpoint => {
            // Try to detect if endpoint exists
            fetch(window.location.origin + endpoint, { method: 'HEAD' })
                .then(response => {
                    if (response.ok || response.status === 405) {
                        this.detectedFlows.push({
                            type: 'endpoint',
                            path: endpoint,
                            status: response.status,
                            headers: Object.fromEntries(response.headers.entries())
                        });
                    }
                })
                .catch(() => {});
        });
    }
    
    detectJWTUsage() {
        const jwt = {
            inLocalStorage: false,
            inSessionStorage: false,
            inCookies: false,
            tokens: []
        };
        
        // Check localStorage
        for (let i = 0; i < localStorage.length; i++) {
            const key = localStorage.key(i);
            const value = localStorage.getItem(key);
            
            if (this.isJWT(value)) {
                jwt.inLocalStorage = true;
                jwt.tokens.push({
                    storage: 'localStorage',
                    key,
                    decoded: this.decodeJWT(value)
                });
            }
        }
        
        // Check sessionStorage
        for (let i = 0; i < sessionStorage.length; i++) {
            const key = sessionStorage.key(i);
            const value = sessionStorage.getItem(key);
            
            if (this.isJWT(value)) {
                jwt.inSessionStorage = true;
                jwt.tokens.push({
                    storage: 'sessionStorage',
                    key,
                    decoded: this.decodeJWT(value)
                });
            }
        }
        
        // Check cookies
        document.cookie.split(';').forEach(cookie => {
            const [name, value] = cookie.trim().split('=');
            if (value && this.isJWT(value)) {
                jwt.inCookies = true;
                jwt.tokens.push({
                    storage: 'cookie',
                    name,
                    decoded: this.decodeJWT(value)
                });
            }
        });
        
        this.jwt = jwt;
    }
    
    isJWT(str) {
        if (!str || typeof str !== 'string') return false;
        const parts = str.split('.');
        return parts.length === 3 && /^[A-Za-z0-9_-]+$/.test(parts[0]);
    }
    
    decodeJWT(token) {
        try {
            const parts = token.split('.');
            const header = JSON.parse(atob(parts[0]));
            const payload = JSON.parse(atob(parts[1]));
            
            return {
                header,
                payload,
                expiry: payload.exp ? new Date(payload.exp * 1000).toISOString() : null,
                issuer: payload.iss || null,
                audience: payload.aud || null
            };
        } catch (e) {
            return null;
        }
    }
    
    analyzeSessionManagement() {
        this.session = {
            cookies: [],
            security: []
        };
        
        // Analyze authentication-related cookies
        document.cookie.split(';').forEach(cookie => {
            const [name, value] = cookie.trim().split('=');
            if (name && (name.toLowerCase().includes('sess') || 
                        name.toLowerCase().includes('auth') ||
                        name.toLowerCase().includes('token'))) {
                
                this.session.cookies.push({
                    name,
                    length: value ? value.length : 0,
                    httpOnly: false, // Can't detect from JS
                    secure: window.location.protocol === 'https:',
                    sameSite: 'Unknown' // Can't detect from JS
                });
            }
        });
        
        // Check for session security issues
        if (window.location.protocol === 'http:') {
            this.session.security.push('🚨 Authentication over insecure HTTP');
        }
        
        if (this.jwt.inLocalStorage) {
            this.session.security.push('⚠️ JWT stored in localStorage (vulnerable to XSS)');
        }
    }
    
    generateAuthReport() {
        console.log('πŸ“Š Authentication Flow Analysis\n');
        
        // Login Forms
        if (this.forms.length > 0) {
            console.log('πŸ“ Login Forms Detected:');
            this.forms.forEach((form, index) => {
                console.log(`\nForm ${index + 1}:`);
                console.log(`  Action: ${form.action}`);
                console.log(`  Method: ${form.method}`);
                console.log(`  CSRF Protection: ${form.hasCSRF ? 'βœ…' : '❌'}`);
                console.log(`  Fields: ${form.fields.length}`);
                
                if (form.security.length > 0) {
                    console.log('  Security Issues:');
                    form.security.forEach(issue => console.log(`    ${issue}`));
                }
            });
        }
        
        // OAuth Providers
        if (this.socialLogins.length > 0) {
            console.log('\n🌐 OAuth Providers:');
            const providers = [...new Set(this.socialLogins.map(s => s.provider))];
            providers.forEach(provider => {
                console.log(`  βœ“ ${provider.charAt(0).toUpperCase() + provider.slice(1)}`);
            });
        }
        
        // JWT Usage
        if (this.jwt.tokens.length > 0) {
            console.log('\n🎫 JWT Token Usage:');
            console.log(`  localStorage: ${this.jwt.inLocalStorage ? 'βœ…' : '❌'}`);
            console.log(`  sessionStorage: ${this.jwt.inSessionStorage ? 'βœ…' : '❌'}`);
            console.log(`  Cookies: ${this.jwt.inCookies ? 'βœ…' : '❌'}`);
            
            this.jwt.tokens.forEach(token => {
                if (token.decoded) {
                    console.log(`\n  Token in ${token.storage}:`);
                    console.log(`    Algorithm: ${token.decoded.header.alg}`);
                    console.log(`    Issuer: ${token.decoded.issuer || 'Not specified'}`);
                    console.log(`    Expiry: ${token.decoded.expiry || 'No expiry'}`);
                }
            });
        }
        
        // Session Management
        if (this.session.cookies.length > 0) {
            console.log('\nπŸͺ Session Cookies:');
            this.session.cookies.forEach(cookie => {
                console.log(`  ${cookie.name}: ${cookie.length} chars`);
            });
        }
        
        // Security Recommendations
        console.log('\nπŸ”’ Security Recommendations:');
        const recommendations = this.generateRecommendations();
        recommendations.forEach(rec => console.log(`  ${rec}`));
        
        return {
            forms: this.forms,
            oauth: this.socialLogins,
            jwt: this.jwt,
            session: this.session,
            recommendations
        };
    }
    
    generateRecommendations() {
        const recommendations = [];
        
        if (window.location.protocol === 'http:') {
            recommendations.push('🚨 Enable HTTPS for all authentication');
        }
        
        if (this.forms.some(f => !f.hasCSRF)) {
            recommendations.push('⚠️ Implement CSRF protection on all forms');
        }
        
        if (this.jwt.inLocalStorage) {
            recommendations.push('⚠️ Store JWT in httpOnly cookies instead of localStorage');
        }
        
        if (this.forms.some(f => f.method.toUpperCase() === 'GET')) {
            recommendations.push('🚨 Use POST method for login forms');
        }
        
        if (!this.socialLogins.length && !this.forms.length) {
            recommendations.push('ℹ️ No authentication detected on current page');
        }
        
        return recommendations;
    }
}

// Run the detector
const authDetector = new AuthFlowDetector();
authDetector.detectAuthenticationFlows();

Understanding OAuth 2.0 Flow

OAuth 2.0 is the industry standard for authorization. Here's how the flow typically works:

  1. Authorization Request: User clicks "Login with Provider"
  2. User Consent: Provider asks user to approve access
  3. Authorization Code: Provider sends code to callback URL
  4. Token Exchange: Server exchanges code for access token
  5. API Access: Use token to access user data

Advanced OAuth Security Analyzer

// Copy and paste this enhanced OAuth analyzer

class OAuthAnalyzer {
    constructor() {
        this.providers = new Map();
        this.vulnerabilities = [];
        this.initializeProviders();
    }
    
    initializeProviders() {
        // Common OAuth providers and their configurations
        this.providers.set('google', {
            authEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth',
            tokenEndpoint: 'https://oauth2.googleapis.com/token',
            requiredParams: ['client_id', 'redirect_uri', 'response_type', 'scope'],
            recommendedParams: ['state', 'nonce', 'code_challenge'],
            scopes: {
                minimal: ['openid', 'email', 'profile'],
                extended: ['https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/calendar']
            }
        });
        
        this.providers.set('github', {
            authEndpoint: 'https://github.com/login/oauth/authorize',
            tokenEndpoint: 'https://github.com/login/oauth/access_token',
            requiredParams: ['client_id', 'redirect_uri'],
            recommendedParams: ['state', 'scope'],
            scopes: {
                minimal: ['read:user', 'user:email'],
                extended: ['repo', 'write:packages', 'admin:org']
            }
        });
    }
    
    analyzeOAuthImplementation() {
        console.log('πŸ” Analyzing OAuth Implementation...\n');
        
        // Check for OAuth links/buttons
        this.detectOAuthLinks();
        
        // Analyze redirect URLs
        this.analyzeRedirectURLs();
        
        // Check for state parameter usage
        this.checkStateParameter();
        
        // Analyze scope requests
        this.analyzeScopeRequests();
        
        // Check for PKCE implementation
        this.checkPKCE();
        
        // Generate security report
        this.generateSecurityReport();
    }
    
    detectOAuthLinks() {
        const links = document.querySelectorAll('a[href*="oauth"], a[href*="authorize"]');
        
        links.forEach(link => {
            const url = new URL(link.href);
            const params = new URLSearchParams(url.search);
            
            this.providers.forEach((config, provider) => {
                if (url.href.includes(config.authEndpoint)) {
                    console.log(`βœ“ Found ${provider} OAuth link`);
                    this.analyzeOAuthParams(provider, params);
                }
            });
        });
    }
    
    analyzeOAuthParams(provider, params) {
        const config = this.providers.get(provider);
        const analysis = {
            provider,
            params: Object.fromEntries(params),
            missing: [],
            security: []
        };
        
        // Check required parameters
        config.requiredParams.forEach(param => {
            if (!params.has(param)) {
                analysis.missing.push(param);
                this.vulnerabilities.push({
                    severity: 'high',
                    issue: `Missing required parameter: ${param}`,
                    provider
                });
            }
        });
        
        // Check security parameters
        if (!params.has('state')) {
            analysis.security.push('Missing state parameter (CSRF protection)');
            this.vulnerabilities.push({
                severity: 'high',
                issue: 'No CSRF protection (missing state parameter)',
                provider
            });
        }
        
        if (params.has('redirect_uri')) {
            const redirectUri = params.get('redirect_uri');
            if (redirectUri.startsWith('http://') && !redirectUri.includes('localhost')) {
                analysis.security.push('Insecure redirect URI (HTTP)');
                this.vulnerabilities.push({
                    severity: 'critical',
                    issue: 'Redirect URI uses insecure HTTP',
                    provider
                });
            }
        }
        
        return analysis;
    }
    
    analyzeRedirectURLs() {
        // Check current URL for OAuth callbacks
        const currentUrl = new URL(window.location.href);
        const params = new URLSearchParams(currentUrl.search);
        
        if (params.has('code') || params.has('access_token')) {
            console.log('⚠️ OAuth callback detected in URL');
            
            if (params.has('access_token')) {
                this.vulnerabilities.push({
                    severity: 'critical',
                    issue: 'Access token exposed in URL (use Authorization Code flow instead)',
                    details: 'Tokens in URLs can be logged and exposed'
                });
            }
            
            if (!params.has('state')) {
                this.vulnerabilities.push({
                    severity: 'high',
                    issue: 'OAuth callback without state validation',
                    details: 'Vulnerable to CSRF attacks'
                });
            }
        }
    }
    
    checkStateParameter() {
        // Look for state generation/validation in JavaScript
        const scripts = document.querySelectorAll('script');
        let hasStateGeneration = false;
        
        scripts.forEach(script => {
            const content = script.textContent || '';
            if (content.includes('crypto.getRandomValues') || 
                content.includes('Math.random') && content.includes('state')) {
                hasStateGeneration = true;
            }
        });
        
        if (!hasStateGeneration) {
            console.log('⚠️ No client-side state generation detected');
        }
    }
    
    analyzeScopeRequests() {
        const links = document.querySelectorAll('a[href*="scope="]');
        const scopeAnalysis = [];
        
        links.forEach(link => {
            const url = new URL(link.href);
            const scope = url.searchParams.get('scope');
            
            if (scope) {
                const scopes = scope.split(/[\s,+]+/);
                const analysis = {
                    url: link.href,
                    scopes,
                    risk: this.assessScopeRisk(scopes)
                };
                
                scopeAnalysis.push(analysis);
                
                if (analysis.risk === 'high') {
                    this.vulnerabilities.push({
                        severity: 'medium',
                        issue: 'Requesting high-risk OAuth scopes',
                        details: `Scopes: ${scopes.join(', ')}`
                    });
                }
            }
        });
        
        return scopeAnalysis;
    }
    
    assessScopeRisk(scopes) {
        const highRiskScopes = [
            'admin', 'write', 'delete', 'full_access',
            'repo', 'org', 'user:follow', 'payment'
        ];
        
        const hasHighRisk = scopes.some(scope => 
            highRiskScopes.some(risk => scope.includes(risk))
        );
        
        return hasHighRisk ? 'high' : 'normal';
    }
    
    checkPKCE() {
        // Check for PKCE (Proof Key for Code Exchange) implementation
        const links = document.querySelectorAll('a[href*="code_challenge"]');
        const hasPKCE = links.length > 0;
        
        if (!hasPKCE) {
            console.log('ℹ️ PKCE not detected (recommended for public clients)');
        } else {
            console.log('βœ… PKCE implementation detected');
        }
        
        return hasPKCE;
    }
    
    generateSecurityReport() {
        console.log('\nπŸ”’ OAuth Security Report\n');
        
        if (this.vulnerabilities.length === 0) {
            console.log('βœ… No critical OAuth vulnerabilities detected');
        } else {
            console.log(`Found ${this.vulnerabilities.length} security issues:\n`);
            
            this.vulnerabilities.sort((a, b) => {
                const severity = { critical: 3, high: 2, medium: 1, low: 0 };
                return severity[b.severity] - severity[a.severity];
            });
            
            this.vulnerabilities.forEach(vuln => {
                const icon = vuln.severity === 'critical' ? '🚨' : 
                            vuln.severity === 'high' ? '⚠️' : 'ℹ️';
                console.log(`${icon} [${vuln.severity.toUpperCase()}] ${vuln.issue}`);
                if (vuln.details) {
                    console.log(`   Details: ${vuln.details}`);
                }
                if (vuln.provider) {
                    console.log(`   Provider: ${vuln.provider}`);
                }
            });
        }
        
        console.log('\nπŸ“‹ Best Practices Checklist:');
        console.log('  βœ“ Use Authorization Code flow (not Implicit)');
        console.log('  βœ“ Implement state parameter for CSRF protection');
        console.log('  βœ“ Use PKCE for public clients');
        console.log('  βœ“ Request minimal necessary scopes');
        console.log('  βœ“ Use HTTPS for redirect URIs');
        console.log('  βœ“ Validate state parameter on callback');
        console.log('  βœ“ Store tokens securely (not in URLs or localStorage)');
    }
}

// Run the OAuth analyzer
const oauthAnalyzer = new OAuthAnalyzer();
oauthAnalyzer.analyzeOAuthImplementation();

Common Authentication Vulnerabilities

1. Session Fixation

When session IDs don't regenerate after login:

// Check for session fixation vulnerability
const checkSessionFixation = () => {
    const sessionBefore = document.cookie.match(/PHPSESSID=([^;]+)/);
    console.log('Current session ID:', sessionBefore ? sessionBefore[1] : 'None');
    console.log('⚠️ Monitor if session ID changes after login');
};

2. Credential Stuffing

Lack of rate limiting on login attempts:

// Test for rate limiting (careful - don't DOS the site!)
const testRateLimit = async () => {
    const attempts = [];
    for (let i = 0; i < 5; i++) {
        const start = Date.now();
        const response = await fetch('/login', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ 
                username: 'test', 
                password: 'wrong' 
            })
        }).catch(e => ({ error: true }));
        
        attempts.push({
            attempt: i + 1,
            time: Date.now() - start,
            status: response.status || 'error'
        });
    }
    
    console.log('Rate limit test:', attempts);
    const avgTime = attempts.reduce((a, b) => a + b.time, 0) / attempts.length;
    
    if (avgTime < 100) {
        console.log('⚠️ No rate limiting detected');
    }
};

3. Timing Attacks

Username enumeration through response time differences:

// Detect timing attack vulnerabilities
const timingAttackTest = async () => {
    const testUsers = [
        'admin', 'administrator', 'test', 
        'definitely_not_a_real_user_12345'
    ];
    
    const results = [];
    
    for (const username of testUsers) {
        const times = [];
        
        for (let i = 0; i < 3; i++) {
            const start = performance.now();
            
            await fetch('/login', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    username,
                    password: 'wrong_password'
                })
            }).catch(() => {});
            
            times.push(performance.now() - start);
        }
        
        results.push({
            username,
            avgTime: times.reduce((a, b) => a + b) / times.length
        });
    }
    
    console.log('Timing analysis:', results);
    
    const variance = Math.max(...results.map(r => r.avgTime)) - 
                    Math.min(...results.map(r => r.avgTime));
    
    if (variance > 50) {
        console.log('⚠️ Possible timing attack vulnerability');
    }
};

Authentication Security Testing Framework

// Comprehensive authentication security tester
class AuthSecurityTester {
    constructor() {
        this.tests = [];
        this.results = {
            passed: 0,
            failed: 0,
            warnings: 0
        };
    }
    
    async runAllTests() {
        console.log('πŸ” Running Authentication Security Tests...\n');
        
        await this.testHTTPS();
        await this.testPasswordPolicy();
        await this.testAccountLockout();
        await this.testSessionSecurity();
        await this.testCSRFProtection();
        await this.testClickjacking();
        
        this.generateReport();
    }
    
    async testHTTPS() {
        const test = {
            name: 'HTTPS Usage',
            status: window.location.protocol === 'https:' ? 'passed' : 'failed',
            message: window.location.protocol === 'https:' ? 
                     'Site uses HTTPS' : 
                     'Site not using HTTPS for authentication'
        };
        
        this.addTest(test);
    }
    
    async testPasswordPolicy() {
        const passwordFields = document.querySelectorAll('input[type="password"]');
        const test = {
            name: 'Password Policy',
            status: 'warning',
            message: 'Check password requirements manually'
        };
        
        passwordFields.forEach(field => {
            if (field.pattern) {
                test.status = 'passed';
                test.message = `Password pattern enforced: ${field.pattern}`;
            }
            
            if (field.minLength && field.minLength >= 8) {
                test.status = 'passed';
                test.message = `Minimum length: ${field.minLength}`;
            }
        });
        
        this.addTest(test);
    }
    
    async testAccountLockout() {
        const test = {
            name: 'Account Lockout',
            status: 'warning',
            message: 'Manual testing required for account lockout policy'
        };
        
        // Look for evidence of account lockout in client-side code
        const scripts = Array.from(document.scripts);
        const hasLockout = scripts.some(script => 
            script.textContent && (
                script.textContent.includes('lockout') ||
                script.textContent.includes('maxAttempts') ||
                script.textContent.includes('failedAttempts')
            )
        );
        
        if (hasLockout) {
            test.status = 'passed';
            test.message = 'Account lockout mechanism detected';
        }
        
        this.addTest(test);
    }
    
    async testSessionSecurity() {
        const cookies = document.cookie.split(';').map(c => c.trim());
        const sessionCookie = cookies.find(c => 
            c.toLowerCase().includes('session') || 
            c.toLowerCase().includes('auth')
        );
        
        const test = {
            name: 'Session Security',
            status: 'warning',
            message: 'Session cookie attributes cannot be fully verified from JavaScript'
        };
        
        if (sessionCookie && window.location.protocol === 'https:') {
            test.status = 'passed';
            test.message = 'Session cookie present over HTTPS';
        }
        
        this.addTest(test);
    }
    
    async testCSRFProtection() {
        const forms = document.querySelectorAll('form');
        let hasCSRF = false;
        
        forms.forEach(form => {
            const csrfInputs = form.querySelectorAll(
                'input[name*="csrf"], input[name*="token"], meta[name="csrf-token"]'
            );
            if (csrfInputs.length > 0) hasCSRF = true;
        });
        
        const test = {
            name: 'CSRF Protection',
            status: hasCSRF ? 'passed' : 'failed',
            message: hasCSRF ? 
                     'CSRF tokens detected' : 
                     'No CSRF protection found'
        };
        
        this.addTest(test);
    }
    
    async testClickjacking() {
        // Try to detect X-Frame-Options or CSP frame-ancestors
        const test = {
            name: 'Clickjacking Protection',
            status: 'warning',
            message: 'Cannot detect X-Frame-Options from JavaScript'
        };
        
        // Check if we're in an iframe
        if (window.self !== window.top) {
            test.status = 'failed';
            test.message = 'Page can be embedded in iframe';
        }
        
        this.addTest(test);
    }
    
    addTest(test) {
        this.tests.push(test);
        
        if (test.status === 'passed') this.results.passed++;
        else if (test.status === 'failed') this.results.failed++;
        else this.results.warnings++;
    }
    
    generateReport() {
        console.log('\nπŸ“Š Authentication Security Test Results\n');
        
        console.log(`βœ… Passed: ${this.results.passed}`);
        console.log(`❌ Failed: ${this.results.failed}`);
        console.log(`⚠️  Warnings: ${this.results.warnings}`);
        
        console.log('\nDetailed Results:');
        this.tests.forEach(test => {
            const icon = test.status === 'passed' ? 'βœ…' :
                        test.status === 'failed' ? '❌' : '⚠️';
            console.log(`\n${icon} ${test.name}`);
            console.log(`   ${test.message}`);
        });
        
        console.log('\nπŸ”’ Security Recommendations:');
        if (this.results.failed > 0) {
            console.log('  1. Address all failed tests immediately');
            console.log('  2. Implement multi-factor authentication');
            console.log('  3. Use secure session management');
            console.log('  4. Implement proper rate limiting');
            console.log('  5. Regular security audits');
        }
    }
}

// Run the security tester
const securityTester = new AuthSecurityTester();
securityTester.runAllTests();

Real-World OAuth Breach Examples

1. Facebook OAuth Vulnerability (2018)

Attackers could hijack OAuth tokens through malicious redirect URIs, affecting 50 million accounts.

2. GitHub OAuth App Attack (2022)

Malicious OAuth apps harvested tokens from popular repositories, accessing private code.

3. Microsoft OAuth Redirect Vulnerability (2023)

Open redirect in OAuth flow allowed attackers to steal authorization codes.

Best Practices Implementation Guide

Secure OAuth Implementation Checklist

// OAuth security configuration generator
const generateSecureOAuthConfig = () => {
    const config = {
        authorizationUrl: 'https://provider.com/oauth/authorize',
        tokenUrl: 'https://provider.com/oauth/token',
        clientId: process.env.OAUTH_CLIENT_ID,
        redirectUri: 'https://yourapp.com/callback',
        responseType: 'code', // Never use 'token' for SPA
        scope: 'openid email profile', // Minimal required scopes
        state: generateSecureState(),
        codeChallenge: generatePKCEChallenge(),
        codeChallengeMethod: 'S256'
    };
    
    return config;
};

const generateSecureState = () => {
    const array = new Uint8Array(32);
    crypto.getRandomValues(array);
    return btoa(String.fromCharCode.apply(null, array))
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=/g, '');
};

const generatePKCEChallenge = () => {
    const verifier = generateSecureState();
    // In real implementation, hash this with SHA256
    return {
        verifier,
        challenge: verifier // Should be SHA256(verifier)
    };
};

Session Security Headers

// Recommended security headers for authentication
const securityHeaders = {
    'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
    'X-Frame-Options': 'DENY',
    'X-Content-Type-Options': 'nosniff',
    'Referrer-Policy': 'strict-origin-when-cross-origin',
    'Permissions-Policy': 'geolocation=(), microphone=(), camera=()',
    'Content-Security-Policy': "default-src 'self'; script-src 'self' https://trusted-cdn.com"
};

Conclusion

Authentication is the front door to your application's security. Regular testing and monitoring of authentication flows, OAuth implementations, and session management is crucial for maintaining security. Use these tools to identify vulnerabilities before attackers do, and implement robust authentication mechanisms that protect user accounts without compromising usability.

Remember: Authentication security is not just about strong passwordsβ€”it's about the entire flow from login to logout, including session management, token storage, and protection against various attack vectors.