Skip to main content

Authentication

The ONE SDK supports two authentication flows:

FlowBest forProvider required
Email OTPMobile apps, non-crypto usersOneProvider
Wallet SignatureWeb3-native users who already have a wallet connectedOneProvider + OneThirdwebProvider

Both flows produce a session token stored in the SDK context. All subsequent API calls are automatically authenticated.

Email OTP Flow

1. Send the 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. Verify the 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>
);
}

Full Email OTP Example

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>
);
}

Wallet Signature Flow

If the user already has a wallet connected through OneThirdwebProvider, you can authenticate them by requesting a message signature. No email is needed.

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>
);
}

Token Management

After authentication, the SDK stores an access token and a refresh token in memory (web) or in the configured StorageAdapter (React Native). The SDK refreshes tokens automatically before expiry, but you can manage them manually if needed.

Refresh the Token

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>;
}

Get the Current User

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>
);
}

Sign Out

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>;
}

Session Management

The SDK supports multiple concurrent sessions (e.g. a user signed in on both a phone and a laptop). You can list and revoke sessions.

List Active Sessions

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>
);
}

Revoke a Session

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>;
}

Using the Engine Client Directly

All auth methods are also available on OneEngineClient for server-side or headless usage:

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();

Type Reference

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
}

Next Steps

  • Wallet -- connect wallets and display balances.
  • Payments -- onramp, offramp, and swap widgets.
  • AI Trading -- create AI-powered trading orders.