import assert from "node:assert/strict"; import { chromium } from "playwright-core"; const keycloakUrl = process.env.KEYCLOAK_URL ?? "http://localhost:8080"; const adminUsername = process.env.KC_BOOTSTRAP_ADMIN_USERNAME; const adminPassword = process.env.KC_BOOTSTRAP_ADMIN_PASSWORD; const mockPassword = process.env.MOCK_GOOGLE_USER_PASSWORD; assert.ok(adminUsername && adminPassword && mockPassword); async function adminToken() { const response = await fetch( `${keycloakUrl}/realms/master/protocol/openid-connect/token`, { method: "POST", body: new URLSearchParams({ client_id: "admin-cli", grant_type: "password", username: adminUsername, password: adminPassword, }), }, ); assert.equal(response.status, 200); return (await response.json()).access_token; } async function usersByEmail(token) { const response = await fetch( `${keycloakUrl}/admin/realms/keycloak-patterns/users?email=${encodeURIComponent( "broker-new-user@example.test", )}&exact=true`, { headers: { Authorization: `Bearer ${token}` } }, ); assert.equal(response.status, 200); return response.json(); } async function userById(token, userId) { const response = await fetch( `${keycloakUrl}/admin/realms/keycloak-patterns/users/${userId}`, { headers: { Authorization: `Bearer ${token}` } }, ); assert.equal(response.status, 200); return response.json(); } async function removePreviousUser(token) { for (const user of await usersByEmail(token)) { const response = await fetch( `${keycloakUrl}/admin/realms/keycloak-patterns/users/${user.id}`, { method: "DELETE", headers: { Authorization: `Bearer ${token}` }, }, ); assert.equal(response.status, 204); } } async function brokerLogin(page) { const url = new URL( `${keycloakUrl}/realms/keycloak-patterns/protocol/openid-connect/auth`, ); url.search = new URLSearchParams({ client_id: "spa-public", redirect_uri: "http://localhost:8088/", response_type: "code", scope: "openid profile email", state: crypto.randomUUID(), nonce: crypto.randomUUID(), code_challenge: "K2qUEfBl-nQvF2gB4dNxC2zYVwZc1CVnZb5CsX2L7fI", code_challenge_method: "S256", kc_idp_hint: "mock-google", prompt: "login", }); await page.goto(url.toString()); await page.waitForURL(/\/realms\/mock-google\//u); await page.locator("#username").fill("mock-new-user"); await page.locator("#password").fill(mockPassword); await page.locator("#kc-login").click(); await page.waitForURL(/localhost:8088\/\?.*code=/u); } const token = await adminToken(); await removePreviousUser(token); const browser = await chromium.launch({ executablePath: process.env.CHROME_BIN ?? "/usr/bin/google-chrome", headless: true, args: ["--no-sandbox"], }); try { const page = await browser.newPage(); await brokerLogin(page); const users = await usersByEmail(token); assert.equal(users.length, 1); const user = await userById(token, users[0].id); assert.match(user.username, /^mock-google\.[0-9a-f-]+$/u); assert.equal(user.firstName, "Broker"); assert.equal(user.lastName, "New"); assert.deepEqual(user.attributes.picture, [ "https://images.example.test/mock-user.png", ]); assert.deepEqual(user.attributes.hd, ["example.test"]); const identitiesResponse = await fetch( `${keycloakUrl}/admin/realms/keycloak-patterns/users/${user.id}/federated-identity`, { headers: { Authorization: `Bearer ${token}` } }, ); assert.equal(identitiesResponse.status, 200); const identities = await identitiesResponse.json(); assert.equal(identities.length, 1); assert.equal(identities[0].identityProvider, "mock-google"); assert.ok(identities[0].userId); console.log( "Google claim mapping verified: stable sub username, profile attributes, federated identity", ); } finally { await browser.close(); }