Test Auth0 sign-in locally with a public callback URL
Test Auth0 sign-in on localhost with a Horizon tunnel, and set Allowed Callback URLs, Allowed Logout URLs and Allowed Web Origins once.
Sign in with Auth0 on your laptop, with callback, logout and origin URLs that stay the same across restarts.
Auth0 only redirects to URLs you list on the application. A stable Horizon URL means you set that list once.
Before you begin
- Node.js 20 or later, which the Auth0 Next.js SDK requires
- A Horizon account and the CLI (see Getting started)
- A reserved subdomain for
-s. Reserve one on the Subdomains page. - An Auth0 tenant with a Regular Web Application, and a Next.js app
Start a tunnel
Use -s with a subdomain you reserved. Without it, the subdomain is random and changes every run, so the URLs you save in Auth0 would point at a dead URL after a restart. Reserved subdomains are a paid feature, see Pricing.
hrzn tunnel http://localhost:3000 -s my-appHORIZON: Tunnel connected
URL https://my-app.hrzn.run (reserved)
Forwarding http://localhost:3000
Request log https://hrzn.run/dashboard/tunnels/my-appYour public URL is https://my-app.hrzn.run. Keep this terminal open.
The first time you open the URL in a browser, Horizon shows a Before you continue page. Select Continue to site. You see it once every 7 days per IP address, so the redirect back from Auth0 won't surprise you later.
Add the URLs in Auth0
- In the Auth0 Dashboard, open Applications and select your application.
- On the Settings tab, scroll to the Application URIs section.
- Set Allowed Callback URLs to
https://my-app.hrzn.run/auth/callback. - Set Allowed Logout URLs to
https://my-app.hrzn.run. - Set Allowed Web Origins to
https://my-app.hrzn.run. - Save your changes.
Set the app environment variables
Install the Auth0 SDK for Next.js.
npm install @auth0/nextjs-auth0Set APP_BASE_URL to the public URL. If you leave it out, the SDK infers the base URL from the request host, and Horizon sets the Host header to localhost:3000. Generate AUTH0_SECRET with openssl rand -hex 32.
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_CLIENT_ID=your_client_id
AUTH0_CLIENT_SECRET=your_client_secret
AUTH0_SECRET=your_generated_secret
APP_BASE_URL=https://my-app.hrzn.runCreate the Auth0 client.
import { Auth0Client } from "@auth0/nextjs-auth0/server";
export const auth0 = new Auth0Client();The SDK mounts /auth/login, /auth/logout and /auth/callback through a proxy. On Next.js 16, create proxy.ts.
import { auth0 } from "./lib/auth0";
export async function proxy(request: Request) {
return await auth0.middleware(request);
}
export const config = {
matcher: [
"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
],
};On Next.js 15, create middleware.ts instead.
import type { NextRequest } from "next/server";
import { auth0 } from "./lib/auth0";
export async function middleware(request: NextRequest) {
return await auth0.middleware(request);
}
export const config = {
matcher: [
"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
],
};Add a sign-in link. Use a plain <a> tag, because Auth0 advises against <Link prefetch={true}> for login links.
export default function Home() {
return <a href="/auth/login">Log in</a>;
}Start the app on port 3000. Restart it after you edit .env.local.
npm run devSign in through the public URL
Open https://my-app.hrzn.run and select Log in. Start from the public URL so the browser, Auth0 and your app agree on the host.
Check it works
Auth0 shows its Universal Login page. After you sign in, Auth0 redirects the browser to https://my-app.hrzn.run/auth/callback, and the SDK sends you back to your app.
Your Horizon terminal prints a GET line for /auth/callback. A 3xx status means your app redirected you onward. If the line shows a 4xx or 5xx, see Troubleshooting.
Troubleshooting
Callback URL mismatch
Auth0 shows "The provided redirect_uri is not in the list of allowed callback URLs". The redirect_uri your app sent doesn't match a value in Allowed Callback URLs.
- Check for a trailing slash, a different path or
httpinstead ofhttps. - Check that
APP_BASE_URLishttps://my-app.hrzn.run. - Check that you saved the change on the application your
AUTH0_CLIENT_IDbelongs to.
The callback goes to localhost
APP_BASE_URL is missing or still holds http://localhost:3000. Horizon sets the Host header to localhost:3000 and sends the public host in X-Forwarded-Host, so a framework that builds URLs from Host gets localhost. Set APP_BASE_URL to https://my-app.hrzn.run and restart npm run dev.
/auth/login returns 404
The proxy file is missing or in the wrong place. Auth0's quickstart says /auth/login returns a 404 without it. Check that proxy.ts (Next.js 16) or middleware.ts (Next.js 15) exists in the project root, or in src if your app uses it.
The tunnel URL changed
You started the tunnel without -s, so Horizon gave you a new random subdomain. Restart with -s my-app and the URL stays the same. -s needs a subdomain you reserved, see Pricing.
Nothing reaches your app
- Check that the Horizon terminal is still running. If its last line is
Connection lost. Reconnecting…, wait forReconnected. - Check that your app listens on port 3000.
Next steps
- Read Auth0's Next.js quickstart.
- Read the
@auth0/nextjs-auth0README.
Test OAuth redirect URLs locally
Test OAuth and social login on localhost with a stable HTTPS redirect URL from a Horizon tunnel, and fix redirect URI mismatches.
Test Firebase Authentication locally with authorized domains
Test Firebase Authentication sign-in on localhost with a Horizon tunnel, and add the tunnel host to the authorized domains once.