/** * QA360 OAuth Handler * * P0 Features: OAuth2/OIDC flow testing support * - Authorization Code flow with PKCE * - Implicit flow (legacy) - P1 * - Client Credentials flow * - Refresh Token flow * - Token storage and management * - OpenID Connect support - P1 * * Supports testing against: * - Real OAuth providers (Google, GitHub, Auth0, etc.) * - Mock OAuth servers for development */ import type { Page, BrowserContext } from '@playwright/test'; /** * OAuth configuration */ export interface OAuthConfig { /** * Authorization endpoint URL */ authEndpoint: string; /** * Token endpoint URL */ tokenEndpoint: string; /** * Client ID */ clientId: string; /** * Client secret (for confidential clients, not used in PKCE) */ clientSecret?: string; /** * Redirect URI */ redirectUri: string; /** * Scope(s) to request */ scope?: string | string[]; /** * Response type (code for Authorization Code, token for Implicit) */ responseType?: 'code' | 'token' | 'id_token' | 'id_token token'; /** * Use PKCE (Proof Key for Code Exchange) */ usePKCE?: boolean; /** * State parameter for CSRF protection */ state?: string; /** * OpenID Connect configuration */ oidc?: { /** Issuer URL for discovery */ issuer?: string; /** UserInfo endpoint */ userInfoEndpoint?: string; /** JWKS URI for token verification */ jwksUri?: string; /** Expected issuer for ID token validation */ expectedIssuer?: string; /** Expected audience for ID token validation */ expectedAudience?: string; }; } /** * OAuth token response */ export interface OAuthToken { access_token: string; token_type?: string; expires_in?: number; refresh_token?: string; scope?: string; id_token?: string; /** OpenID Connect: Issuer identifier */ issuer?: string; } /** * OpenID Connect ID Token claims */ export interface OIDCClaims { /** Issuer identifier */ iss: string; /** Subject identifier */ sub: string; /** Audience(s) */ aud: string | string[]; /** Expiration time */ exp: number; /** Issued at time */ iat: number; /** Authentication time */ auth_time?: number; /** nonce */ nonce?: string; /** Authentication context class reference */ acr?: string; /** Authentication methods references */ amr?: string[]; /** Authorized party */ azp?: string; /** Email address */ email?: string; /** Email verified status */ email_verified?: boolean; /** Phone number */ phone_number?: string; /** Phone verified status */ phone_number_verified?: boolean; /** Given name */ given_name?: string; /** Family name */ family_name?: string; /** Full name */ name?: string; /** Locale */ locale?: string; /** Picture URL */ picture?: string; /** Profile URL */ profile?: string; /** Website URL */ website?: string; /** Gender */ gender?: string; /** Birthdate */ birthdate?: string; /** Zone info */ zoneinfo?: string; /** Updated at time */ updated_at?: number; /** Address */ address?: OIDCAddress; } /** * OIDC Address claims */ export interface OIDCAddress { formatted?: string; street_address?: string; locality?: string; region?: string; postal_code?: string; country?: string; } /** * UserInfo endpoint response */ export interface OIDCUserInfo { sub: string; name?: string; given_name?: string; family_name?: string; middle_name?: string; nickname?: string; preferred_username?: string; profile?: string; picture?: string; website?: string; email?: string; email_verified?: boolean; gender?: string; birthdate?: string; zoneinfo?: string; locale?: string; phone_number?: string; phone_number_verified?: boolean; address?: OIDCAddress; updated_at?: number; } /** * Implicit flow result (token from URL fragment) */ export interface ImplicitFlowResult { success: boolean; accessToken?: string; idToken?: string; tokenType?: string; expires_in?: string; state?: string; error?: OAuthError; } /** * OAuth error response */ export interface OAuthError { error: string; error_description?: string; error_uri?: string; state?: string; } /** * Authorization result */ export interface AuthorizationResult { success: boolean; code?: string; error?: OAuthError; state?: string; } /** * OAuth Handler class */ export declare class OAuthHandler { private context; private config; private accessToken; private refreshToken; private codeVerifier; private generatedState; constructor(context: BrowserContext, config: OAuthConfig); /** * Generate random string for PKCE code verifier and state * Uses cryptographically secure random bytes */ private generateRandomString; /** * Generate code challenge for PKCE * Uses SHA256 to create challenge from verifier */ private generateCodeChallenge; /** * Build authorization URL * P0: Construct the OAuth authorization URL with all required parameters */ buildAuthorizationURL(options?: { state?: string; codeChallenge?: string; }): string; /** * Start Authorization Code flow with PKCE * P0: Begin OAuth login flow * * @returns Authorization URL to navigate user to */ startAuthorizationFlow(): Promise<{ authUrl: string; verifier: string; state: string; }>; /** * Wait for OAuth callback * P0: Wait for redirect to redirect_uri with code or error * * @returns Promise that resolves when callback is received */ waitForCallback(page: Page, timeout?: number): Promise; /** * Exchange authorization code for tokens * P0: Token exchange endpoint call */ exchangeCodeForToken(code: string): Promise; /** * Client Credentials flow * P1: Server-to-server authentication without user interaction * Used for machine-to-machine communication (service accounts, daemons, etc.) * * @returns OAuth token response (no refresh token in this flow) */ clientCredentials(): Promise; /** * Refresh access token * P0: Use refresh token to get new access token */ refreshAccessToken(): Promise; /** * Get current access token */ getAccessToken(): string | null; /** * Get refresh token */ getRefreshToken(): string | null; /** * Set tokens manually (useful for testing) */ setTokens(tokens: { accessToken: string; refreshToken?: string; }): void; /** * Clear all stored tokens */ clearTokens(): void; /** * Full Authorization Code flow with PKCE * P0: Complete OAuth flow from start to token exchange * * @param page - Playwright page instance * @param userInteraction - Optional function to handle user login * @returns OAuth token response */ completeFlow(page: Page, userInteraction?: (page: Page, authUrl: string) => Promise): Promise; /** * Set authorization header with Bearer token * P0: Helper to set Authorization header for API requests */ setAuthHeader(page: Page): Promise; /** * P1: Implicit Flow (legacy OAuth2) * Token is returned directly in URL fragment after redirect * * Note: Implicit flow is deprecated in OAuth 2.1. Use Authorization Code with PKCE instead. * This method is provided for testing legacy applications. * * @param page - Playwright page instance * @param userInteraction - Optional function to handle user login * @returns Implicit flow result with access token from URL fragment */ implicitFlow(page: Page, userInteraction?: (page: Page, authUrl: string) => Promise): Promise; /** * P1: Wait for Implicit Flow callback * Extracts token from URL fragment (hash) */ waitForImplicitCallback(page: Page, timeout?: number): Promise; /** * P1: OpenID Connect - Parse and validate ID token * * @param idToken - JWT ID token from OAuth response * @returns Parsed OIDC claims */ parseIDToken(idToken: string): Promise; /** * P1: OpenID Connect - Fetch UserInfo from endpoint * * @param accessToken - Access token for authorization * @returns UserInfo response */ fetchUserInfo(accessToken: string): Promise; /** * P1: OpenID Connect - Complete OIDC flow * Performs Authorization Code flow and fetches UserInfo * * @param page - Playwright page instance * @param userInteraction - Optional function to handle user login * @returns OAuth token + parsed ID token claims + UserInfo */ completeOIDCFlow(page: Page, userInteraction?: (page: Page, authUrl: string) => Promise): Promise<{ token: OAuthToken; idTokenClaims?: OIDCClaims; userInfo?: OIDCUserInfo; }>; /** * P1: Validate ID token signature (basic validation) * For full signature validation, you need the JWKS and crypto verification * * @param idToken - JWT ID token to validate * @returns Validation result with claims if valid */ validateIDToken(idToken: string): Promise<{ valid: boolean; claims?: OIDCClaims; error?: string; }>; } /** * Mock OAuth Server for testing * Simulates OAuth endpoints for development/testing */ export declare class MockOAuthServer { private baseUrl; private authorizedCodes; constructor(baseUrl?: string); /** * Get authorization endpoint URL */ getAuthEndpoint(): string; /** * Get token endpoint URL */ getTokenEndpoint(): string; /** * Generate a mock access token */ private generateMockToken; /** * Create a mock authorization code * Stores code-to-token mapping for later exchange */ createAuthorizationCode(): { code: string; token: OAuthToken; }; /** * Validate and redeem authorization code */ redeemCode(code: string): OAuthToken | null; /** * Get OAuth config for mock server */ getOAuthConfig(clientId?: string, redirectUri?: string): OAuthConfig; } /** * Convenience function to create OAuth handler */ export declare function createOAuthHandler(context: BrowserContext, config: OAuthConfig): OAuthHandler; /** * Convenience function to create mock OAuth server */ export declare function createMockOAuthServer(baseUrl?: string): MockOAuthServer;