110 lines
4.0 KiB
JavaScript
110 lines
4.0 KiB
JavaScript
// Auth flow helpers — register / confirm / login / refresh / logout.
|
|
// All requests go through lib/http.js; OTP comes from lib/otp.js.
|
|
import { post } from './http.js';
|
|
import { checkEnvelope } from './http.js';
|
|
import { cfg, unique } from './config.js';
|
|
import { fetchEmailOTP } from './otp.js';
|
|
|
|
// makeIdentity returns a unique (email, password, display_name) tuple for the
|
|
// current VU iteration. Use to avoid collisions in concurrent runs.
|
|
export function makeIdentity(prefix = 'k6') {
|
|
const slug = unique(prefix);
|
|
return {
|
|
email: `${slug}@k6.local`,
|
|
password: 'K6-StrongPass-1!',
|
|
displayName: `K6 ${slug}`,
|
|
};
|
|
}
|
|
|
|
// registerEmail calls POST /api/v1/auth/register and returns the parsed
|
|
// RegisterData (challenge_id, expires_in, uid).
|
|
export function registerEmail({ tenantSlug = cfg.tenantSlug, inviteCode = cfg.inviteCode, email, password, displayName, language = 'zh-TW', termsVersion = '2025-01-01', marketingOptIn = false } = {}) {
|
|
const res = post('/api/v1/auth/register', {
|
|
tenant_slug: tenantSlug,
|
|
invite_code: inviteCode,
|
|
email,
|
|
password,
|
|
display_name: displayName,
|
|
language,
|
|
accept_terms_version: termsVersion,
|
|
marketing_opt_in: marketingOptIn,
|
|
});
|
|
const body = checkEnvelope(res, 'POST /auth/register');
|
|
if (!body.data || !body.data.challenge_id) {
|
|
throw new Error(`register: missing challenge_id in ${res.body}`);
|
|
}
|
|
return body.data;
|
|
}
|
|
|
|
// confirmRegister fetches the OTP from MailHog then calls
|
|
// POST /api/v1/auth/register/confirm. Returns AuthTokenData.
|
|
export function confirmRegister({ tenantSlug = cfg.tenantSlug, email, challengeId }) {
|
|
const code = fetchEmailOTP(email);
|
|
const res = post('/api/v1/auth/register/confirm', {
|
|
tenant_slug: tenantSlug,
|
|
challenge_id: challengeId,
|
|
code,
|
|
});
|
|
const body = checkEnvelope(res, 'POST /auth/register/confirm');
|
|
if (!body.data || !body.data.access_token) {
|
|
throw new Error(`register/confirm: missing access_token in ${res.body}`);
|
|
}
|
|
return body.data;
|
|
}
|
|
|
|
// resendRegister calls POST /api/v1/auth/register/resend.
|
|
// Returns RegisterData (challenge_id, expires_in, uid).
|
|
export function resendRegister({ tenantSlug = cfg.tenantSlug, challengeId }) {
|
|
const res = post('/api/v1/auth/register/resend', {
|
|
tenant_slug: tenantSlug,
|
|
challenge_id: challengeId,
|
|
});
|
|
return checkEnvelope(res, 'POST /auth/register/resend').data;
|
|
}
|
|
|
|
// login calls POST /api/v1/auth/login. Returns AuthTokenData.
|
|
export function login({ tenantSlug = cfg.tenantSlug, email, password }) {
|
|
const res = post('/api/v1/auth/login', {
|
|
tenant_slug: tenantSlug,
|
|
email,
|
|
password,
|
|
});
|
|
const body = checkEnvelope(res, 'POST /auth/login');
|
|
if (!body.data || !body.data.access_token) {
|
|
throw new Error(`login: missing access_token in ${res.body}`);
|
|
}
|
|
return body.data;
|
|
}
|
|
|
|
// refreshToken calls POST /api/v1/auth/token/refresh.
|
|
export function refreshToken({ refreshToken }) {
|
|
const res = post('/api/v1/auth/token/refresh', { refresh_token: refreshToken });
|
|
const body = checkEnvelope(res, 'POST /auth/token/refresh');
|
|
if (!body.data || !body.data.access_token) {
|
|
throw new Error(`token/refresh: missing access_token in ${res.body}`);
|
|
}
|
|
return body.data;
|
|
}
|
|
|
|
// logout calls POST /api/v1/auth/logout (requires Bearer access_token).
|
|
export function logout({ accessToken }) {
|
|
const res = post('/api/v1/auth/logout', null, { Authorization: `Bearer ${accessToken}` });
|
|
const body = checkEnvelope(res, 'POST /auth/logout');
|
|
return body.data;
|
|
}
|
|
|
|
// registerAndConfirm is the most common building block: makes an identity,
|
|
// runs register → confirm, returns { identity, tokens, registerData }.
|
|
export function registerAndConfirm({ tenantSlug = cfg.tenantSlug, inviteCode = cfg.inviteCode } = {}) {
|
|
const identity = makeIdentity();
|
|
const reg = registerEmail({
|
|
tenantSlug,
|
|
inviteCode,
|
|
email: identity.email,
|
|
password: identity.password,
|
|
displayName: identity.displayName,
|
|
});
|
|
const tokens = confirmRegister({ tenantSlug, email: identity.email, challengeId: reg.challenge_id });
|
|
return { identity, tokens, registerData: reg };
|
|
}
|