Getting Started
Client Setup
Start and follow orders from the browser.
Add the client plugin to your Better Auth client. The helpers wrap the server endpoints with typed methods and return { data, error } responses.
Quick Start
1. Register the client plugin
auth-client.ts
import { createAuthClient } from "better-auth/client"
import { crossDeviceClient } from "@onmax/better-auth-cross-device/client"
export const authClient = createAuthClient({
plugins: [crossDeviceClient()],
})
2. Start an order
The initiating device starts the order and shows the claimUrl to the approving device. Display it as a QR code, deep link, or copyable URL.
start-login.ts
const order = await authClient.crossDevice.start({
kind: "login",
returnTo: "/dashboard",
displayTitle: "Sign in to Console",
displaySummary: "Approve this sign-in on your trusted device.",
})
if (order.error) throw new Error(order.error.message)
showQrCode(order.data.claimUrl)
3. Subscribe to status
Subscribe with the eventToken from the start response. When the order is approved, finalize it with the desktopToken.
follow-order.ts
const source = authClient.crossDevice.subscribe({
orderId: order.data.orderId,
eventToken: order.data.eventToken,
onEvent: async (event) => {
if (event === "approved") {
await authClient.crossDevice.finalize({
orderId: order.data.orderId,
desktopToken: order.data.desktopToken,
})
}
},
})
Close the
EventSource when the page unmounts or the order reaches a terminal state.4. Build the approving-device route
The approving device claims the order, fetches the challenge, and submits the adapter proof.
claim-page.ts
await authClient.crossDevice.claim({ orderId, claimToken })
const challenge = await authClient.crossDevice.challenge({
orderId,
challengeToken,
})
await authClient.crossDevice.approve({
orderId,
challengeToken,
proof: await createProof(challenge.data),
})
Order kinds
| Kind | Finalize result |
|---|---|
login | Applies the resolved Better Auth session and may return token. |
sign | Returns the approved proofArtifact. |
transaction | Returns the approved proofArtifact. |
Error handling
Every helper returns a typed response:
client.ts
const result = await authClient.crossDevice.finalize({ orderId, desktopToken })
if (result.error) {
showError(result.error.message || "Approval failed")
return
}
navigateTo(result.data.redirectTo || "/")
Next Steps
- Cross-device flow: learn which token belongs to each device
- Endpoint reference: inspect request and response shapes
- Security: handle origins, TTLs, and proof failures