@motion-key/react
v0.1.0
Published
React components for Motion Key 2FA — EnrollmentPanel, WaitingApproval, KeyholeAnimation.
Downloads
93
Maintainers
Readme
@motion-key/react
React components for Motion Key 2FA — drop-in UI for enrollment and the PC-side "iPhone, please approve" waiting screen.
Pair with @motion-key/server for the backend.
What's in here
<EnrollmentPanel>— shows the user's currently-registered iPhones, lets them generate a fresh enrollment QR (with optional "email it to me" toggle), and polls until enrollment completes.<WaitingApproval>— connects to your WebSocket bridge (or falls back to HTTP polling on/challenges/statusif WS is unavailable, e.g. behind a single ngrok tunnel) and renders the keyhole animation while waiting for the iPhone to approve.<KeyholeAnimation>— the standalone keyhole SVG (progress + unlocked states).
All three are "use client" components and assume you've mounted @motion-key/server somewhere — pass the mount point as apiPath (default /api/motion-key).
Install
pnpm add @motion-key/react @motion-key/coreReact 18+ peer dep.
Usage
// settings/2fa/page.tsx — server component
import { EnrollmentPanel } from "@motion-key/react";
export default async function Page() {
const accounts = await loadAccountsFor(currentUserId); // your DB call
return <EnrollmentPanel apiPath="/api/motion-key" initialAccounts={accounts} />;
}
// waiting/page.tsx
"use client";
import { WaitingApproval } from "@motion-key/react";
import { useRouter, useSearchParams } from "next/navigation";
export default function Page() {
const router = useRouter();
const cid = useSearchParams().get("cid")!;
return (
<WaitingApproval
challengeId={cid}
apiPath="/api/motion-key"
wsUrl={process.env.NEXT_PUBLIC_WS_URL}
onApproved={async () => {
await fetch("/api/auth/login/complete", {
method: "POST",
body: JSON.stringify({ challengeId: cid }),
});
router.push("/dashboard");
}}
/>
);
}License
MIT
