template-monorepo/test/k6/smoke/auth_public.js

97 lines
4.1 KiB
JavaScript
Raw Permalink Normal View History

2026-05-26 06:05:33 +00:00
// 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);
}