Guide · Auth0 + Next.js App Router
Bots never reach Auth0.
Verify humans first.
Auth0's Universal Login is hosted on Auth0's domain — you can't run your own verification there. So don't: verify the human on your page, where behavioral signals live, and only then reveal the signup redirect. Unverified sessions never even learn the route. Every snippet below was live-tested on Next.js 16 + @auth0/nextjs-auth0 v4 + usehuma 1.2.1.
01Install & environment
npm install @auth0/nextjs-auth0 usehumaCreate a Regular Web Application in your Auth0 dashboard and copy its values from the Settings tab. You need usehuma@1.2.1+.
# .env.local — values from your Auth0 application's Settings tab
AUTH0_DOMAIN=dev-YOUR-TENANT.us.auth0.com
AUTH0_CLIENT_ID=••••••••
AUTH0_CLIENT_SECRET=••••••••
AUTH0_SECRET=$(openssl rand -hex 32)
APP_BASE_URL=http://localhost:3000
NEXT_PUBLIC_HUMA_KEY=huma_live_••••••••02Auth0 client + proxy
// lib/auth0.ts
import { Auth0Client } from "@auth0/nextjs-auth0/server";
export const auth0 = new Auth0Client(); // reads the env vars above// proxy.ts (Next.js 16 — replaces middleware.ts)
import type { NextRequest } from "next/server";
import { auth0 } from "./lib/auth0";
export async function proxy(request: NextRequest) {
return await auth0.middleware(request); // mounts /auth/login, /auth/callback…
}
export const config = {
matcher: ["/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)"],
};Two gotchas we hit live: (1) Next.js 16 uses
proxy.ts —middleware.ts is deprecated for the Node runtime. (2) The Auth0 middleware intercepts GET requests — if you smoke-test with curl -I (a HEAD request) you'll get a confusing 404. Use a plain GET and you'll see the 307 to your tenant.03Configure callback URLs
In your Auth0 application → Settings → Application URIs:
Allowed Callback URLs: http://localhost:3000/auth/callback
Allowed Logout URLs: http://localhost:3000(Add your production URLs alongside when you deploy.)
04Gate the signup redirect
// app/page.tsx — gate the signup redirect
"use client";
import { HumaGate } from "usehuma/react";
export default function Home() {
return (
<main style={{ padding: 48, textAlign: "center" }}>
<h1>Create your account</h1>
<HumaGate
apiKey={process.env.NEXT_PUBLIC_HUMA_KEY!}
userId="auth0_signup_visitor"
fallback={<p>Verifying you're human…</p>}
>
<a href="/auth/login?screen_hint=signup">Sign up →</a>
</HumaGate>
</main>
);
}How it behaves: ~4 seconds of invisible signal collection while the visitor reads your page, then the "Sign up" link appears for verified humans and routes through
/auth/login?screen_hint=signup straight to Auth0's signup screen. Bots get a retry wall — and the redirect path is never in their DOM.Auth0 for identity, useHUMA for humanity.
14-day free trial · one API key · zero PII.
Get your API key →