// Journey: ZITADEL id_token → CloudEP JWT exchange. // // Endpoint exercised: // POST /api/v1/auth/token/exchange (TokenExchangeReq) // // Happy path requires a valid ZITADEL id_token issued for the gateway's // configured OIDC client. The default `make k6-up` ZITADEL bootstrap only // creates a service-account PAT (no human-user OIDC client + password grant), // so we cover negative cases only and mark the happy path as TODO. // // To enable happy-path: configure a ZITADEL OIDC application with password // grant in deploy/zitadel/steps.yaml, export OAUTH_CLIENT_ID + secret + user // credentials, then call ZITADEL's /oauth/v2/token to obtain an id_token. import { post, checkErrorOneOf } from '../lib/http.js'; import { cfg } from '../lib/config.js'; export const options = { vus: 1, iterations: 1, thresholds: { checks: ['rate==1.0'] }, }; export default function () { // Negative 1: empty id_token → 400 missing/invalid input const r1 = post('/api/v1/auth/token/exchange', { tenant_slug: cfg.tenantSlug, id_token: '', }); // either 400 (validation) or 401 (id_token invalid) if (r1.status !== 400 && r1.status !== 401) { throw new Error(`empty id_token: unexpected status ${r1.status}: ${r1.body}`); } // Negative 2: bogus id_token. Two acceptable outcomes depending on whether // a JWKS URL is wired: // 401+28501000 → invalid id_token (JWKS wired; gateway verified locally) // 502+28802000 → zitadel request failed (default k6 env: no JWKS configured, // gateway falls through to a remote introspection call). // Either outcome proves the endpoint exists and refuses bad tokens. const r2 = post('/api/v1/auth/token/exchange', { tenant_slug: cfg.tenantSlug, id_token: 'not.a.real.jwt', }); checkErrorOneOf(r2, 'POST /auth/token/exchange (bogus id_token)', [ [401, 28501000], [502, 28802000], ]); // TODO: happy path — needs ZITADEL OAuth client + password grant configured. console.log('[token_exchange] happy path skipped (needs ZITADEL OIDC client; see file header)'); }