跳至主要内容

认证

ONE SDK 支持两种认证流程:

流程适用场景所需 Provider
邮件 OTP移动应用、非加密货币用户OneProvider
钱包签名已连接钱包的 Web3 原生用户OneProvider + OneThirdwebProvider

两种流程都会生成一个会话令牌,存储在 SDK 上下文中。后续所有 API 调用将自动携带认证信息。

邮件 OTP 流程

1. 发送 OTP

SendOtp.tsx
import { useOneAuth } from "@one_deploy/sdk/hooks";

export function SendOtp() {
const { sendEmailOtp, isLoading, error } = useOneAuth();
const [email, setEmail] = React.useState("");

const handleSend = async () => {
const result = await sendEmailOtp({ email });
if (result.success) {
// Navigate to the verification screen
console.log("OTP sent to", email);
}
};

return (
<div>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
/>
<button onClick={handleSend} disabled={isLoading}>
{isLoading ? "Sending..." : "Send Code"}
</button>
{error && <p style={{ color: "red" }}>{error.message}</p>}
</div>
);
}

2. 验证 OTP

VerifyOtp.tsx
import { useOneAuth } from "@one_deploy/sdk/hooks";

export function VerifyOtp({ email }: { email: string }) {
const { verifyEmailOtp, isLoading, error } = useOneAuth();
const [code, setCode] = React.useState("");

const handleVerify = async () => {
const result = await verifyEmailOtp({ email, code });

if (result.success) {
console.log("Authenticated as:", result.user.email);
console.log("Access token:", result.accessToken);
// The SDK context is now authenticated.
// All hook calls and engine requests carry the token automatically.
}
};

return (
<div>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder="6-digit code"
maxLength={6}
/>
<button onClick={handleVerify} disabled={isLoading}>
{isLoading ? "Verifying..." : "Verify"}
</button>
{error && <p style={{ color: "red" }}>{error.message}</p>}
</div>
);
}

完整邮件 OTP 示例

EmailLogin.tsx
import React, { useState } from "react";
import { useOneAuth } from "@one_deploy/sdk/hooks";

type Step = "email" | "otp" | "done";

export function EmailLogin() {
const { sendEmailOtp, verifyEmailOtp, isLoading, error } = useOneAuth();
const [step, setStep] = useState<Step>("email");
const [email, setEmail] = useState("");
const [code, setCode] = useState("");

const handleSendOtp = async () => {
const result = await sendEmailOtp({ email });
if (result.success) setStep("otp");
};

const handleVerifyOtp = async () => {
const result = await verifyEmailOtp({ email, code });
if (result.success) setStep("done");
};

if (step === "done") {
return <p>Signed in as {email}</p>;
}

return (
<div>
{step === "email" && (
<>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
/>
<button onClick={handleSendOtp} disabled={isLoading}>
Send OTP
</button>
</>
)}

{step === "otp" && (
<>
<p>Enter the code sent to {email}</p>
<input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder="6-digit code"
maxLength={6}
/>
<button onClick={handleVerifyOtp} disabled={isLoading}>
Verify
</button>
</>
)}

{error && <p style={{ color: "red" }}>{error.message}</p>}
</div>
);
}

钱包签名流程

如果用户已通过 OneThirdwebProvider 连接了钱包,你可以通过请求消息签名来认证用户,无需邮箱。

WalletLogin.tsx
import { useOneAuth, useOneWallet } from "@one_deploy/sdk/hooks";

export function WalletLogin() {
const { authWithWallet, isLoading, error } = useOneAuth();
const { address, isConnected } = useOneWallet();

const handleAuth = async () => {
if (!address) return;

const result = await authWithWallet({
address,
// The SDK generates a SIWE (Sign-In with Ethereum) message and
// prompts the connected wallet to sign it.
});

if (result.success) {
console.log("Authenticated wallet:", result.user.walletAddress);
console.log("Access token:", result.accessToken);
}
};

if (!isConnected) {
return <p>Connect your wallet first.</p>;
}

return (
<div>
<p>Connected: {address}</p>
<button onClick={handleAuth} disabled={isLoading}>
{isLoading ? "Signing..." : "Sign In with Wallet"}
</button>
{error && <p style={{ color: "red" }}>{error.message}</p>}
</div>
);
}

令牌管理

认证完成后,SDK 会将访问令牌刷新令牌存储在内存中(Web)或配置的 StorageAdapter 中(React Native)。SDK 会在令牌过期前自动刷新,但你也可以手动管理。

刷新令牌

import { useOneAuth } from "@one_deploy/sdk/hooks";

function TokenManager() {
const { refreshToken } = useOneAuth();

const handleRefresh = async () => {
const result = await refreshToken();
if (result.success) {
console.log("New access token:", result.accessToken);
console.log("Expires at:", new Date(result.expiresAt).toISOString());
}
};

return <button onClick={handleRefresh}>Refresh Token</button>;
}

获取当前用户

import { useOneAuth } from "@one_deploy/sdk/hooks";

function UserProfile() {
const { getCurrentUser } = useOneAuth();
const [user, setUser] = React.useState<OneUser | null>(null);

React.useEffect(() => {
getCurrentUser().then(setUser);
}, [getCurrentUser]);

if (!user) return <p>Not signed in.</p>;

return (
<div>
<p>Email: {user.email ?? "N/A"}</p>
<p>Wallet: {user.walletAddress ?? "N/A"}</p>
<p>User ID: {user.id}</p>
<p>Created: {new Date(user.createdAt).toLocaleDateString()}</p>
</div>
);
}

登出

import { useOneAuth } from "@one_deploy/sdk/hooks";

function SignOutButton() {
const { signOut } = useOneAuth();

const handleSignOut = async () => {
await signOut();
// Auth state is cleared. Hooks that depend on auth will reset.
console.log("Signed out");
};

return <button onClick={handleSignOut}>Sign Out</button>;
}

会话管理

SDK 支持多个并发会话(例如用户同时在手机和笔记本电脑上登录)。你可以列出和撤销会话。

列出活跃会话

import { useOneAuth } from "@one_deploy/sdk/hooks";

function ActiveSessions() {
const { getActiveSessions } = useOneAuth();
const [sessions, setSessions] = React.useState<OneSession[]>([]);

React.useEffect(() => {
getActiveSessions().then(setSessions);
}, [getActiveSessions]);

return (
<ul>
{sessions.map((session) => (
<li key={session.id}>
{session.deviceName ?? "Unknown device"} --{" "}
{session.isCurrent ? "This device" : session.lastActiveAt}
</li>
))}
</ul>
);
}

撤销会话

import { useOneAuth } from "@one_deploy/sdk/hooks";

function RevokeSession({ sessionId }: { sessionId: string }) {
const { revokeSession } = useOneAuth();

const handleRevoke = async () => {
const result = await revokeSession({ sessionId });
if (result.success) {
console.log("Session revoked:", sessionId);
}
};

return <button onClick={handleRevoke}>Revoke</button>;
}

直接使用 Engine 客户端

所有认证方法也可以通过 OneEngineClient 在服务端或无界面场景中使用:

server/auth.ts
import { OneEngineClient } from "@one_deploy/sdk/services";

const engine = new OneEngineClient({
baseUrl: process.env.ONE_ENGINE_URL!,
clientId: process.env.ONE_CLIENT_ID!,
secretKey: process.env.ONE_SECRET_KEY!, // server only
});

// Send OTP
await engine.sendEmailOtp({ email: "user@example.com" });

// Verify OTP
const authResult = await engine.verifyEmailOtp({
email: "user@example.com",
code: "123456",
});

// Use the token for subsequent calls
engine.setAccessToken(authResult.accessToken);

// Get user
const user = await engine.getCurrentUser();

// List sessions
const sessions = await engine.getActiveSessions();

// Revoke a session
await engine.revokeSession({ sessionId: "sess_abc123" });

// Sign out (invalidates current token)
await engine.signOut();

类型参考

import type { OneUser, OneSession, AuthResult } from "@one_deploy/sdk/types";

interface OneUser {
id: string;
email?: string;
walletAddress?: string;
createdAt: string;
updatedAt: string;
}

interface OneSession {
id: string;
userId: string;
deviceName?: string;
ipAddress?: string;
lastActiveAt: string;
createdAt: string;
isCurrent: boolean;
}

interface AuthResult {
success: boolean;
user: OneUser;
accessToken: string;
refreshToken: string;
expiresAt: number; // Unix ms
}

下一步

  • 钱包 -- 连接钱包并显示余额。
  • 支付 -- 入金、出金和兑换组件。
  • AI 交易 -- 创建 AI 驱动的交易订单。