Email OTP
Email OTP uses a one-time password to check access to an email address. The server verifies the challenge. A dedicated worker handles the secret material.
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 the user entered. 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.startGoogleSignIn({
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;
}