Appearance
Email OTP
Email OTP is a server-verified channel challenge and worker-owned secret flow.
Role in the model
Email OTP can:
- prove control of a verified email channel;
- authorize worker-owned Email OTP secret reconstruction;
- create or restore signing capabilities under Wallet Session policy;
- step up exhausted or expired Email OTP Wallet Session quotas;
- authorize export or recovery only through fresh operation-specific policy.
Secret-bearing Email OTP material belongs in the dedicated Email OTP worker or encrypted storage. App-origin code should not receive recovered Email OTP secrets or derived signing shares.
Start a login
Exchange a Google ID token for a typed login flow, then submit the code entered by the user. The registration branch is handled separately because it carries its own wallet selection and recovery-code backup ceremony.
Runnable TypeScript example
ts
import type {
GoogleEmailOtpWalletAuthLoginFlow,
GoogleEmailOtpWalletAuthSubmitSuccess,
SeamsWeb,
} from '@seams/wallet';
export async function startGoogleEmailOtpLogin(
seams: SeamsWeb,
googleIdToken: string,
): Promise<GoogleEmailOtpWalletAuthLoginFlow> {
const started = await seams.auth.beginGoogleEmailOtpWalletAuth({
idToken: googleIdToken,
mode: 'login',
loginTarget: { kind: 'discoverable' },
});
if (!started.ok) {
throw new Error(started.error.message);
}
if (started.value.mode !== 'login') {
await started.value.cancel();
throw new Error('This Google account needs wallet registration');
}
return started.value;
}
export async function submitGoogleEmailOtp(
flow: GoogleEmailOtpWalletAuthLoginFlow,
otpCode: string,
): Promise<GoogleEmailOtpWalletAuthSubmitSuccess> {
const submitted = await flow.submit({ otpCode });
if (!submitted.ok) {
throw new Error(submitted.error.message);
}
return submitted.value;
}