feat(identity): add gated self-hosted otp login

This commit is contained in:
Jesse_Chen
2026-07-21 17:40:57 +08:00
parent cf42430244
commit dfcc718fa7
4 changed files with 355 additions and 115 deletions
+58
View File
@@ -0,0 +1,58 @@
import { createAuthClient } from "better-auth/react";
import { emailOTPClient } from "better-auth/client/plugins";
interface OtpClientResult {
data: unknown;
error: unknown;
}
export interface SelfHostedOtpClient {
emailOtp: {
sendVerificationOtp(input: {
email: string;
type: "sign-in";
}): Promise<OtpClientResult>;
};
signIn: {
emailOtp(input: {
email: string;
otp: string;
}): Promise<OtpClientResult>;
};
}
export interface SelfHostedOtpActions {
send(email: string): Promise<void>;
verify(email: string, otp: string): Promise<void>;
}
export function createSelfHostedOtpActions(
client: SelfHostedOtpClient,
): SelfHostedOtpActions {
return {
async send(email) {
const result = await client.emailOtp.sendVerificationOtp({
email: email.trim().toLowerCase(),
type: "sign-in",
});
if (result.error) {
throw new Error("暂时无法发送验证码,请稍后再试");
}
},
async verify(email, otp) {
const result = await client.signIn.emailOtp({
email: email.trim().toLowerCase(),
otp,
});
if (result.error) {
throw new Error("验证码错误或已过期,请重新获取");
}
},
};
}
const authClient = createAuthClient({ plugins: [emailOTPClient()] });
export const selfHostedOtpActions = createSelfHostedOtpActions(
authClient as SelfHostedOtpClient,
);