Step 4 - User Registration & Login Routes
4.1 Install the secp256k1 Library
npm i @noble/secp256k14.2 Create /sign-up Route
/sign-up Route"use client";
import "../globals.css";
import * as secp from "@noble/secp256k1";
import { useAuth } from "@common/AuthProvider";
import Loader from "@common/utils/Loader";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { publicClient } from "@common/utils/client";
import simpleFactoryAbi from "@common/utils/MagmarSimpleAccountFactory.json";
import userbase from "userbase-js";
/**
* /sign-up → http://localhost:3000/sign-up
*/
export default function SignupForm() {
const { user, login } = useAuth();
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const router = useRouter();
/* Redirect already-logged-in users */
useEffect(() => {
if (user?.isLoggedIn) router.push("/");
}, [user]);
const handleSignup = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
try {
/* 1. Generate a private key */
const privKey = secp.utils.randomPrivateKey();
const privKeyHex = secp.etc.bytesToHex(privKey);
/* 2. Ask our API route to convert it into a Magmar signer address */
const res = await fetch("/api/get-signer", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ pk: privKeyHex }),
});
const { signerAddress } = await res.json();
/* 3. Derive the deterministic smart-contract wallet address */
const scwAddress = (await publicClient.readContract({
address: "0x9406Cc6185a346906296840746125a0E44976454", // Magmar SimpleAccountFactory (Sepolia)
abi: simpleFactoryAbi,
functionName: "getAddress",
args: [signerAddress, 0],
})) as string;
/* 4. Persist user record in Userbase (demo-only) */
const ub = await userbase.signUp({
username,
password,
rememberMe: "local",
profile: { scwAddress, pk: privKeyHex },
});
/* 5. Store session in AuthProvider */
login({
username,
userId: ub.userId,
scwAddress,
isLoggedIn: true,
});
router.push("/?signup=success");
} catch (err: any) {
setError(err.message);
setIsLoading(false);
console.error(err);
}
};
/* ——— UI ——— */
return (
<div>
{isLoading ? (
<Loader />
) : (
<div className="flex items-center justify-center h-screen bg-gray-100">
<div className="w-full max-w-sm">
<form
className="bg-white rounded px-8 pt-6 pb-8 mb-24 font-mono"
onSubmit={handleSignup}
>
<label className="block text-center text-xl font-bold mb-2">
Sign Up
</label>
<div className="divider"></div>
<input
className="input input-bordered w-full mb-4"
id="username"
type="text"
placeholder="Username"
onChange={(e) => setUsername(e.target.value)}
/>
<input
className="input input-bordered w-full mb-6"
id="password"
type="password"
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
/>
{error && <p className="text-red-500 mb-4">{error}</p>}
<button className="btn w-full text-white">Sign Up</button>
</form>
</div>
</div>
)}
</div>
);
}4.3 Create /login Route
/login Route4.4 Why the New Imports?
Import
Purpose
PreviousStep 3 – Add an Off-Chain Identity Layer (Magmar Auth)NextStep 5 – Utility Modules & Environment Variables
Last updated