Skip to content

Auth Route Browser Smoke

Scope

This opt-in Playwright smoke proves the login page can observe the non-default auth-native gateway route table from a real browser context. It opens /auth/login, clicks the Google Auth entry, and verifies the browser response for GET /api/auth/google/config came through iam-service.

It also fetches unauthenticated /api/auth/me from the page context and checks the IAM AUTH_UNAUTHORIZED envelope. The legacy sibling route guard remains enabled by default so /api/auth/me/profile must stay legacy-proxied. Because the login page sends X-Request-Id, live browser mode also proves the gateway can answer CORS preflight locally before the browser sends the real auth request.

Required Runtime

Start these processes before live browser mode:

  • Web app, default WEB_BASE_URL=http://localhost:3000
  • API gateway, default GATEWAY_BASE_URL=http://localhost:8085
  • iam-service, default target from deploy/gateway/routes.auth-native-localhost-example.json
  • gateway route table: GATEWAY_ROUTE_TABLE=deploy/gateway/routes.auth-native-localhost-example.json

The web app must be started with VITE_API_BASE_URL pointing at the gateway base URL. If the frontend points at a legacy API process, the smoke fails because browser responses will not include gateway route headers.

Run

Static self-test:

bash
cd go-platform
AUTH_ROUTE_BROWSER_SELF_TEST=1 make test-auth-routes-browser

Confirmed browser run:

bash
cd go-platform
AUTH_ROUTE_BROWSER_CONFIRM=auth-native \
WEB_BASE_URL=http://localhost:3000 \
GATEWAY_BASE_URL=http://localhost:8085 \
make test-auth-routes-browser

Session lifecycle browser run:

bash
cd go-platform
AUTH_SESSION_BROWSER_CONFIRM=auth-session \
WEB_BASE_URL=http://localhost:3000 \
GATEWAY_BASE_URL=http://localhost:8085 \
make test-auth-routes-session-browser

Useful optional variables:

  • AUTH_ROUTE_BROWSER_HEADLESS=0 to see Chromium.
  • AUTH_ROUTE_BROWSER_PATH=/auth/login to override the page path.
  • AUTH_ROUTE_BROWSER_GOOGLE_BUTTON_SELECTOR=.htz-google-button to override the Google entry selector.
  • AUTH_ROUTE_BROWSER_EXPECT_ROUTE_SET=candidate-readonly with AUTH_ROUTE_BROWSER_CONFIRM=auth-candidate for the IAM/Profile default candidate proof. This narrower mode only allows auth-google-config and auth-me to be native while blocked auth/profile/KYC routes remain inactive.
  • AUTH_ROUTE_BROWSER_SKIP_LEGACY_GUARD=1 only when the isolated smoke environment cannot reach the broad legacy sibling route.
  • AUTH_ROUTE_BROWSER_ARTIFACT_DIR=output/playwright/<name> to control artifact output.

Assertions

The smoke fails unless:

  • the route table has exact native auth carve-outs before the broad /api/auth route
  • auth-google-config, auth-me, auth-login, and auth-register target iam-service
  • broad /api/auth, broad /api/admin, and fallback stay legacy_proxy
  • the browser observes X-Hoctapaz-Gateway-Route: auth-google-config for GET /api/auth/google/config
  • the browser observes X-Hoctapaz-Gateway-Route-State: native_read
  • browser-originated auth requests receive gateway CORS headers for X-Request-Id and credentialed requests
  • unauthenticated /api/auth/me returns 401 with AUTH_UNAUTHORIZED
  • the sibling profile route remains on the broad legacy auth route unless explicitly skipped

Live artifacts are written under output/playwright/ and include response headers, response bodies, a summary file, and a login page screenshot. The session lifecycle smoke writes redacted response artifacts only; raw passwords, access tokens, and refresh tokens are not persisted.

Latest Local Proof

On 2026-07-09, browser mode passed against local public-web, iam-service, and api-gateway:

bash
VITE_API_BASE_URL=http://localhost:18087 pnpm --filter @hoctapaz/public-web dev
bash
HTTP_ADDR=:8081 \
AUTH_JWT_SECRET=local-hoctapaz-development-secret-change-before-deploy \
GOTOOLCHAIN=go1.25.11 \
go run ./services/iam-service/cmd/server
bash
HTTP_ADDR=:18087 \
LEGACY_API_BASE_URL=http://127.0.0.1:9 \
GATEWAY_ROUTE_TABLE=deploy/gateway/routes.auth-native-localhost-example.json \
AUTH_JWT_SECRET=local-hoctapaz-development-secret-change-before-deploy \
GOTOOLCHAIN=go1.25.11 \
go run ./services/api-gateway/cmd/server

Then:

bash
AUTH_ROUTE_BROWSER_CONFIRM=auth-native \
AUTH_ROUTE_BROWSER_ARTIFACT_DIR=output/playwright/auth-route-browser-smoke-20260709-115940 \
AUTH_ROUTE_BROWSER_HEADLESS=1 \
WEB_BASE_URL=http://localhost:5205 \
GATEWAY_BASE_URL=http://localhost:18087 \
make test-auth-routes-browser

Artifacts were written under:

txt
output/playwright/auth-route-browser-smoke-20260709-115940/

Observed route evidence:

  • /api/auth/google/config: status 200, route auth-google-config, state native_read, Access-Control-Allow-Origin: http://localhost:5205, and Access-Control-Allow-Credentials: true.
  • /api/auth/me: status 401, route auth-me, state native_read, and IAM error code AUTH_UNAUTHORIZED.
  • /api/auth/me/profile?source=auth-browser-smoke: status 502, route auth, state legacy_proxy. The 502 is expected because the legacy target was a deliberate dummy endpoint.

The local processes were stopped after the run.

Latest Session Lifecycle Proof

On 2026-07-09, session lifecycle browser mode passed against local public-web, iam-service, and api-gateway:

bash
VITE_API_BASE_URL=http://localhost:18095 pnpm --filter @hoctapaz/public-web dev --host 127.0.0.1 --port 5207
bash
HTTP_ADDR=:8081 \
AUTH_JWT_SECRET=local-hoctapaz-development-secret-change-before-deploy \
GOTOOLCHAIN=go1.25.11 \
go run ./services/iam-service/cmd/server
bash
HTTP_ADDR=:18095 \
LEGACY_API_BASE_URL=http://127.0.0.1:9 \
GATEWAY_ROUTE_TABLE=deploy/gateway/routes.auth-native-localhost-example.json \
AUTH_JWT_SECRET=local-hoctapaz-development-secret-change-before-deploy \
GOTOOLCHAIN=go1.25.11 \
go run ./services/api-gateway/cmd/server

Then:

bash
AUTH_SESSION_BROWSER_CONFIRM=auth-session \
AUTH_SESSION_BROWSER_ARTIFACT_DIR=output/playwright/auth-route-session-browser-smoke-20260709-100744 \
AUTH_SESSION_BROWSER_HEADLESS=1 \
WEB_BASE_URL=http://127.0.0.1:5207 \
GATEWAY_BASE_URL=http://localhost:18095 \
make test-auth-routes-session-browser

Artifacts were written under:

txt
output/playwright/auth-route-session-browser-smoke-20260709-100744/

Observed route evidence:

  • POST /api/auth/register: status 201, route auth-register, state native_write.
  • POST /api/auth/login: status 200, route auth-login, state native_write.
  • authenticated GET /api/auth/me: status 200, route auth-me, state native_read.
  • POST /api/auth/refresh: status 200, route auth-refresh, state native_write, and the refresh token rotated.
  • old refresh token reuse: status 401, route auth-refresh, state native_write.
  • refreshed-session GET /api/auth/me: status 200, route auth-me, state native_read.
  • POST /api/auth/logout: status 200, route auth-logout, state native_write.
  • refresh after logout: status 401, route auth-refresh, state native_write.

The response artifacts redact access tokens, refresh tokens, token type fields, and passwords. The local processes were stopped after the run.

Rollback

Switch GATEWAY_ROUTE_TABLE back to deploy/gateway/routes.json, remove the native auth route-table entries, or set the exact auth carve-outs back to legacy_proxy. This smoke writes no IAM/Profile data.

Go-platform documentation is generated from repository Markdown.