Test Okta sign-in locally with an OIDC redirect URI
Test Okta OIDC sign-in on localhost with a Horizon tunnel, and set the sign-in redirect URI on your app integration once.
Sign in with Okta on your laptop, with a sign-in redirect URI that stays the same across restarts.
Okta checks the redirect_uri of each sign-in request against the Sign-in redirect URIs of your app integration. A stable Horizon URL means you set that list once.
Before you begin
- Node.js 18 or later
- A Horizon account and the CLI (see Getting started)
- A reserved subdomain for
-s. Reserve one on the Subdomains page. - An Okta org where you can create app integrations
- 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 Okta 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 Okta won't surprise you later.
Create the app integration in Okta
This page uses the Okta provider in Auth.js (next-auth).
- In the Okta Admin Console, open Applications and Resources, then Applications.
- Select Create App Integration.
- Select OIDC - OpenID Connect as the sign-in method and Web Application as the application type. Okta warns that the wrong app type can break sign-in and sign-out.
- Set Sign-in redirect URIs to
https://my-app.hrzn.run/api/auth/callback/okta. This is the callback path Auth.js uses with Next.js. - Set Sign-out redirect URIs to
https://my-app.hrzn.run. - Under Controlled access, choose who can sign in, then save.
- On the General tab, under Client Credentials, copy the Client ID and Client Secret.
Okta says sign-in redirect URIs must be absolute URIs. The Okta docs don't allow wildcards for sign-out redirect URIs.
Set the app environment variables
Install Auth.js and generate a secret. npx auth secret adds AUTH_SECRET to .env.local.
npm install next-auth@betanpx auth secretAdd the Okta values. AUTH_TRUST_HOST=true tells Auth.js to trust the X-Forwarded-Host header. Horizon sets Host to localhost:3000 and sends the public host in that header, so without it the callback can point at localhost.
AUTH_OKTA_ID=your_client_id
AUTH_OKTA_SECRET=your_client_secret
AUTH_OKTA_ISSUER=your_okta_issuer_url
AUTH_TRUST_HOST=trueCreate the Auth.js config with the Okta provider.
import NextAuth from "next-auth";
import Okta from "next-auth/providers/okta";
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [Okta],
});Create the route handler.
import { handlers } from "@/auth";
export const { GET, POST } = handlers;Add a sign-in button.
import { signIn } from "@/auth";
export default function Home() {
return (
<form
action={async () => {
"use server";
await signIn("okta");
}}
>
<button type="submit">Sign in with Okta</button>
</form>
);
}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 Sign in with Okta. Start from the public URL so the browser, Okta and your app agree on the host.
Check it works
Okta shows its sign-in page. After you sign in, Okta redirects the browser to https://my-app.hrzn.run/api/auth/callback/okta, and Auth.js sends you back to your app.
Your Horizon terminal prints a GET line for /api/auth/callback/okta. A 3xx status means your app redirected you onward. If the line shows a 4xx or 5xx, see Troubleshooting.
Troubleshooting
The redirect_uri must be a login redirect URI
Okta returns a 400 Bad Request when the redirect_uri of the sign-in request isn't one of the Sign-in redirect URIs on the app integration.
- Open the app integration, and check that
https://my-app.hrzn.run/api/auth/callback/oktais in Sign-in redirect URIs. - Check that
AUTH_OKTA_IDbelongs to the same app integration. - Check the scheme and the path.
httpandhttpsare different URIs.
The callback goes to localhost
Horizon sets the Host header to localhost:3000 and sends the public host in X-Forwarded-Host. Auth.js trusts that header only when AUTH_TRUST_HOST is true. Set it, then restart npm run dev.
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 Okta's guide to signing users in to a web app.
- Read the Auth.js Okta provider page.
Test Kinde sign-in locally with a public callback URL
Test Kinde sign-in on localhost with a Horizon tunnel, using a stable HTTPS URL for the allowed callback and logout redirect URLs.
Test Supabase Auth redirects and OAuth locally
Test Supabase Auth sign-in and OAuth providers on localhost with a Horizon tunnel, and set the Site URL and Redirect URLs once.