// smoke: public auth endpoints (no Bearer) // // Covers: // POST /api/v1/auth/register (happy → challenge_id) // POST /api/v1/auth/register/resend (happy → new challenge_id) // POST /api/v1/auth/login (negative → invalid credentials) // POST /api/v1/auth/token/refresh (negative → invalid refresh token) // POST /api/v1/auth/register/social/start (happy → oauth_url) // POST /api/v1/auth/login/social/start (happy → oauth_url) // GET /api/v1/auth/register/social/callback (negative → invalid state) // GET /api/v1/auth/login/social/callback (negative → invalid state) // // Note: social callback happy path requires browser redirect (skipped — see README). import { sleep } from 'k6'; import { get, post, checkEnvelope, checkError, checkErrorOneOf } from '../lib/http.js'; import { cfg, unique } from '../lib/config.js'; import { registerEmail, resendRegister } from '../lib/auth.js'; export const options = { vus: 1, iterations: 1, thresholds: { checks: ['rate==1.0'] }, }; export default function () { // 1. register happy const email = `${unique('smoke-pub')}@k6.local`; const reg = registerEmail({ email, password: 'K6-StrongPass-1!', displayName: 'smoke-pub' }); // 2. register resend happy (new challenge issued). Respect the resend // cooldown (etc/gateway.k6.yaml → Member.OTP.ResendCooldownSeconds=1) plus // a small safety margin so we don't hit 29604000. sleep(1.2); resendRegister({ challengeId: reg.challenge_id }); // 3. login negative — wrong password against a non-existent user. // Accepted outcomes: // 401+28501000 → invalid credentials path (full OAuth client wired) // 502+28802000 → zitadel request failed (default k6 env: no OAuth client, // and modern ZITADEL v2 disables password grant anyway). // Either outcome proves the endpoint is reachable + returns an error envelope. const loginRes = post('/api/v1/auth/login', { tenant_slug: cfg.tenantSlug, email: 'no-such-user@k6.local', password: 'wrongPassword1!', }); checkErrorOneOf(loginRes, 'POST /auth/login (negative)', [ [401, 28501000], [502, 28802000], ]); // 4. token/refresh negative — bogus refresh token. Same dual-outcome reason. const refreshRes = post('/api/v1/auth/token/refresh', { refresh_token: 'not-a-token' }); checkErrorOneOf(refreshRes, 'POST /auth/token/refresh (negative)', [ [401, 28501000], [502, 28802000], ]); // 5. register/social/start — requires Google IdP wired in ZITADEL. // Accepted outcomes: // 200+102000 → oauth_url returned (full Google IdP wired) // 502+28802000 → zitadel request failed (default k6 env: no GoogleIdPID). // We verify the endpoint accepts the request and returns either path. const regSocialRes = post('/api/v1/auth/register/social/start', { tenant_slug: cfg.tenantSlug, invite_code: cfg.inviteCode, provider: 'google', accept_terms_version: '2025-01-01', language: 'zh-TW', redirect_uri: 'http://localhost:8888/api/v1/auth/register/social/callback', }); checkErrorOneOf(regSocialRes, 'POST /auth/register/social/start', [ [200, 102000], [502, 28802000], ]); // 6. login/social/start — same dual-outcome reason. const loginSocialRes = post('/api/v1/auth/login/social/start', { tenant_slug: cfg.tenantSlug, provider: 'google', redirect_uri: 'http://localhost:8888/api/v1/auth/login/social/callback', }); checkErrorOneOf(loginSocialRes, 'POST /auth/login/social/start', [ [200, 102000], [502, 28802000], ]); // 7. register/social/callback negative — invalid state const cbReg = get('/api/v1/auth/register/social/callback?code=fake&state=invalid'); // 400 with 28101000 (oauth state invalid) checkError(cbReg, 'GET /auth/register/social/callback (invalid state)', 400, 28101000); // 8. login/social/callback negative — invalid state const cbLogin = get('/api/v1/auth/login/social/callback?code=fake&state=invalid'); checkError(cbLogin, 'GET /auth/login/social/callback (invalid state)', 400, 28101000); }