import { test, expect } from '@playwright/test'; test('OAuth Flow for tenant-admin-app', async ({ page }) => { const code_challenge = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'; const code_verifier = 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM'; const redirect_uri = 'http://localhost:8000/auth/callback'; const state = 'teststate'; const scope = 'tenant:read tenant:write tenant:admin'; const authorizeUrl = `/api/v1/oauth/authorize?response_type=code&client_id=tenant-admin-app&redirect_uri=${encodeURIComponent(redirect_uri)}&scope=${encodeURIComponent(scope)}&code_challenge=${code_challenge}&code_challenge_method=S256&state=${state}`; // Navigate to authorize - should immediately redirect to callback await page.goto(authorizeUrl); await page.waitForLoadState('networkidle'); // Log response if no redirect const currentUrl = page.url(); if (currentUrl.includes('/authorize')) { const response = await page.content(); console.log('No redirect, response:', response.substring(0, 500)); // First 500 chars } // Wait for redirect to callback and parse params await expect(page).toHaveURL(new RegExp(`${redirect_uri}\\?.*`)); const urlObj = new URL(currentUrl); const code = urlObj.searchParams.get('code') || ''; const receivedState = urlObj.searchParams.get('state') || ''; expect(receivedState).toBe(state); expect(code).not.toBeNull(); console.log('Authorization code:', code); // Token exchange via fetch const tokenParams = { code: code!, redirect_uri, code_verifier }; const tokenResponse = await page.evaluate(async (params) => { const response = await fetch('/api/v1/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ grant_type: 'authorization_code', client_id: 'tenant-admin-app', code: params.code, redirect_uri: params.redirect_uri, code_verifier: params.code_verifier, }).toString(), }); return await response.json(); }, tokenParams); console.log('Token response:', tokenResponse); expect(tokenResponse.access_token).toBeTruthy(); const accessToken = tokenResponse.access_token; // Call /tenant/me with token const meResponse = await page.evaluate(async (token) => { const response = await fetch('/api/v1/tenant/me', { headers: { 'Authorization': `Bearer ${token}`, 'Accept': 'application/json', }, }); return await response.json(); }, accessToken); console.log('/tenant/me response:', meResponse); expect(meResponse).toHaveProperty('id'); expect(meResponse.email).toBe('demo@example.com'); });