React and Next.js
A client component that gets a token on submit, verified in a Server Action or a Route Handler.
On this page
Server helper #
Keep verification in a server-only module, so the secret never reaches a client bundle:
import "server-only";
export async function verifyBlockAlt(token: string, action: string, remoteip?: string) {
try {
const response = await fetch("https://blockalt.click/v1/siteverify", {
method: "POST",
cache: "no-store",
redirect: "error",
headers: {
Authorization: `Bearer ${process.env.BLOCKALT_SECRET}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ token, hostname: "example.com", action, ...(remoteip ? { remoteip } : {}) }),
signal: AbortSignal.timeout(3000),
});
const result = await response.json();
return response.ok && result.success === true;
} catch {
return false;
}
}Client component #
"use client";
import Script from "next/script";
import { useRef } from "react";
import { signup } from "./actions";
declare global {
interface Window { BlockAlt: any }
}
export function SignupForm() {
const protection = useRef<any>(null);
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
protection.current ??= window.BlockAlt.create({
siteKey: process.env.NEXT_PUBLIC_BLOCKALT_SITE_KEY!,
apiUrl: "https://blockalt.click",
configPublicKeys: process.env.NEXT_PUBLIC_BLOCKALT_CONFIG_KEYS!.split(","),
});
const data = new FormData(event.currentTarget);
data.set("blockalt-token", await protection.current.execute("signup"));
await signup(data);
}
return (
<>
<Script
src="https://blockalt.click/v1/assets/blockalt.c8b2d9539dbbc932999adb0f51a36bddd4e99899f543e1505818841878cf9813.js"
integrity="sha384-pblByFDqcJxRfhDh18GH3gRsWy9ZaS4AjDc6OpozzQqvkuYvyin+4BWcKXxA+bN8"
crossOrigin="anonymous"
strategy="afterInteractive"
/>
<form onSubmit={onSubmit}>
<input name="email" type="email" required />
<button>Create account</button>
</form>
</>
);
}Server Action #
"use server";
import { verifyBlockAlt } from "@/lib/blockalt";
export async function signup(data: FormData) {
const token = data.get("blockalt-token");
if (!(await verifyBlockAlt(typeof token === "string" ? token : "", "signup"))) {
return { error: "Please try again." };
}
// …create the account
}Route Handler #
For a JSON API called with fetch:
import { verifyBlockAlt } from "@/lib/blockalt";
export async function POST(request: Request) {
const body = await request.json().catch(() => ({}));
if (!(await verifyBlockAlt(typeof body.token === "string" ? body.token : "", "signup"))) {
return Response.json({ error: "verification_failed" }, { status: 403 });
}
// …create the account
return Response.json({ ok: true });
}With a Content-Security-Policy in middleware.ts, add the CSP entries; next/script passes your nonce to the script tag.
Something unclear or missing on this page? Write to support@blockalt.click.