Redirect URIs for local, staging, and production: Secure patterns and anti-patterns
A developer's guide to registering redirect URIs per environment, debugging "invalid redirect URI" errors, and knowing when to use impersonation instead.
Every developer who integrates OAuth-based authentication eventually hits the same wall: you click "Sign in," the browser spins for a moment, and then you're staring at an "invalid redirect URI" error. You double-check the URL. It looks right. You restart your dev server. Same error.
The problem is almost never the URL itself. It's a mismatch between what your code sends and what you've registered in the dashboard, compounded by the fact that local development, staging review apps, and production all demand different redirect strategies.
This article walks through the patterns that work, the anti-patterns that invite security incidents, and when you should skip the redirect-URI dance entirely and reach for impersonation instead.
What a redirect URI actually does
During an OAuth 2.0 authorization code flow, the redirect URI is the callback endpoint where the authorization server sends the user after they authenticate. The response includes a short-lived authorization code that your backend exchanges for tokens.
Because that code grants access to a user's account, the authorization server must verify that the redirect URI in the request exactly matches one that was pre-registered. If it doesn't, the server rejects the request. This strict matching is the primary defense against authorization code interception; an attacker who can redirect the code to their own server can exchange it and impersonate the user.
In WorkOS, redirect URIs are configured in the Redirects page of the dashboard, per environment. If the URI your application passes in the redirect_uri parameter isn't registered there, the flow will fail and your users won't be able to sign in.
How WorkOS environments map to your deployment stages
WorkOS provides separate environments with distinct API keys and redirect URI rules:
Sandbox environments allow http:// and localhost redirect URIs. This is where you develop and test. The built-in Test Organization and mock identity provider let you exercise the full SSO flow without configuring a real IdP.
Production environments enforce HTTPS and prohibit localhost. The sole exception is http://127.0.0.1 for native clients, per RFC 8252. Every redirect URI you register here must be a fully qualified HTTPS URL on a domain you control.
This separation is intentional. Sandbox rules are permissive so you can iterate quickly. Production rules are strict because a misconfigured redirect URI in production is a security vulnerability, not a nuisance.
Pattern 1: Local development
For local development, register a redirect URI like http://localhost:3000/callback in your Sandbox environment. Store it in an environment variable:
Make sure the path in your application's routing matches exactly. If your redirect URI is http://localhost:3000/callback, the route handler must live at /callback. A trailing-slash mismatch (/callback vs /callback/) will cause a failure.
The variable-port problem
If your dev server assigns a random port on each restart, you have two options:
- Pin the port. Most frameworks let you specify a fixed port (
next dev -p 3000,vite --port 3000). This is the simplest approach and works for the vast majority of teams. - Use a wildcard port. WorkOS supports
http://localhost:*/callbackas a wildcard redirect URI, strictly limited tolocalhostand loopback addresses like127.0.0.1. This pattern exists to support RFC 8252 for native apps, but it works for web dev servers too.
Pin the port whenever possible. Wildcard ports are a convenience, not a best practice. They expand the set of URIs that will be accepted, which is the opposite of what you want from a security standpoint.
Pattern 2: Staging and review apps
Modern CI/CD pipelines often deploy every pull request to a unique URL. Vercel generates https://my-app-abc123.vercel.app; Heroku review apps produce https://my-app-pr-42.herokuapp.com; Railway, Render, and Netlify have their own patterns.
You can't register every ephemeral URL individually. This is where wildcard subdomains come in.
WorkOS supports a * wildcard character in redirect URIs for subdomains, with these rules:
- The wildcard must be in the leftmost subdomain position:
https://*.example.com/callbackworks;https://app.*.example.com/callbackdoes not. - Only one wildcard per URI.
- The wildcard will not match across multiple subdomain levels:
https://*.example.comwon't matchhttps://a.b.example.com. - Wildcards can include prefixes and suffixes:
https://pr-*-preview.example.comis valid. - A wildcard URI cannot be set as the default redirect URI.
- In production, the protocol must be HTTPS.
- Wildcards cannot be used with public suffix domains (e.g.,
*.vercel.app,*.ngrok-free.app).
That last rule is the one developers most commonly run into. Public suffix domains are shared across tenants: allowing a wildcard on *.vercel.app would mean any Vercel deployment could be a valid redirect target for your application, which would be a critical vulnerability. If your review apps live on a provider's shared domain, you need to route them through a custom domain you own. Set up a wildcard DNS record like *.preview.yourapp.com and point it at your review app infrastructure.
The dynamic redirect URI approach
For Next.js apps on Vercel, the authkit-nextjs library supports setting the redirect URI dynamically based on the deployment URL. This means you can read the VERCEL_URL environment variable at runtime and pass it as the redirect_uri parameter in the authorization request (as long as the resulting URL matches a wildcard pattern you've registered).
Pattern 3: Production
Production redirect URIs should be:
- Exact. No wildcards.
- HTTPS only.
- On a domain you own and control.
- As few as possible (ideally one).
Register something like https://app.yourcompany.com/auth/callback and make it the default redirect URI in the WorkOS dashboard. Multi-tenant applications typically use a single redirect URI and differentiate tenants using the state parameter or the organization ID from the returned profile, not multiple redirect URIs.
Single-tenant applications that serve different customers on different subdomains can use multiple explicit redirect URIs. Register each one. Avoid wildcards in production unless you have an exceptionally strong reason and fully understand the implications.
Anti-patterns that will hurt you
- Registering overly broad wildcards.
https://*.yourcompany.com/callbackin production seems convenient if you haveapp.yourcompany.com,staging.yourcompany.com, andbeta.yourcompany.com. But it also matchesevil.yourcompany.comif an attacker can create a subdomain on your domain (through a dangling DNS record, a compromised subdomain, or a subdomain takeover). Keep production redirect URIs explicit. - Sharing API keys across environments. Using your production WorkOS API key locally so you can "test against real data" means your local
http://localhost:3000/callbackredirect URI must be registered in production (which WorkOS correctly forbids). This pattern is the source of a huge number of "invalid redirect URI" debugging sessions. Use Sandbox credentials locally. Use production credentials in production. - Pointing local development at production. A common workaround when debugging a customer-reported issue is to configure your local app to use production API keys and attempt to reproduce the problem. This creates several hazards: your local environment can't use
localhostredirect URIs with production credentials, you might accidentally mutate production data, and the authentication tokens you obtain locally are real production tokens. If you're trying to see what a specific user sees, impersonation (covered below) is the correct tool. - Using
ngrokor tunnel services with wildcards. Tunneling services like ngrok give you a public URL that forwards to your local machine. Developers sometimes registerhttps://*.ngrok-free.appas a redirect URI to accommodate the randomly generated hostnames. WorkOS explicitly blocks wildcards on public suffix domains because these domains are shared across all users of the tunneling service; any ngrok user could potentially intercept your redirect. If you must use a tunnel, use a paid plan with a stable custom domain and register that specific domain. - Forgetting to register the URI before deploying. The redirect URI must exist in the WorkOS dashboard before your application sends users through the auth flow. If you deploy a new callback path and forget to add it to the dashboard, every login attempt will fail. Make redirect URI registration part of your deployment checklist or automate it.
Debugging "invalid redirect URI" errors
When you hit this error, work through the following checks:
- Exact string match. Copy the redirect URI from your code and compare it character-by-character with what's in the dashboard. Check for trailing slashes, protocol mismatches (
httpvshttps), port differences, and path differences. - Correct environment. Confirm you're using the API key and client ID for the environment where the redirect URI is registered. This is the single most common cause (using Sandbox keys with a production redirect URI or vice versa).
- Default URI vs. per-request URI. If you're passing
redirect_urias a parameter in the authorization URL, that value must match a registered URI. If you're relying on the default, make sure one is actually set. - Wildcard rules. If you're using a wildcard, verify it follows all the rules: leftmost subdomain only, single wildcard, not a public suffix domain, HTTPS in production. Remember that wildcard URIs cannot be set as the default.
- Check the error response. When WorkOS can't generate an authorization URL, it redirects to your redirect URI with
erroranderror_descriptionquery parameters. Inspect the full URL in your browser's address bar or network tab.
When impersonation is a better tool
Many "redirect URI" headaches originate from a legitimate goal: a developer or support engineer wants to see what a specific user sees in production. The instinct is to somehow route the production auth flow through a local machine so you can step through the code with a debugger.
This is almost always the wrong approach. WorkOS offers user impersonation as a purpose-built alternative.
Impersonation lets an administrator assume the identity of any user without knowing their credentials, modifying redirect URIs, or touching the auth flow at all. Here's how it works:
- Navigate to the user in the WorkOS dashboard.
- Under Danger Zone, select Impersonate User.
- Provide a required justification (this is recorded in the audit log).
- Choose the organization if the user belongs to more than one.
- Click Impersonate User. Your browser is redirected to your application's callback with an authorization code for that user.
The impersonation session expires after 60 minutes. Every impersonation emits a session.created event with an impersonator field that records who impersonated whom and why. This creates a clear audit trail that "I logged in as them on my local machine using production keys" never provides.
For your application code, the authentication response includes an impersonator field when the session was started via impersonation. You can use this to render a staff bar, redact sensitive data, or restrict destructive actions:
If you're using the authkit-nextjs library, a built-in <Impersonation /> component renders this banner automatically.
The key insight: impersonation lets you debug what a user sees in the actual production environment with proper auditing, no redirect URI gymnastics, and no risk of leaking production tokens to a local machine. It is more secure, more auditable, and faster than any workaround involving local redirect URIs pointed at production.
A decision framework
When you're deciding how to configure redirect URIs for a new environment or debug a user-reported issue, use this framework:
Summary
Redirect URIs are a security boundary, not a convenience feature. The strictness you encounter when configuring them (exact string matching, HTTPS enforcement, wildcard restrictions) exists because a misconfigured redirect URI is one of the most well-understood OAuth attack vectors.
WorkOS gives you the tools to handle every common deployment topology: permissive Sandbox environments for local development, wildcard subdomain support for review apps, and strict production rules that prevent the most common mistakes. When the problem you're actually trying to solve is "see what a user sees," impersonation is the right tool. It's more secure, auditable, and doesn't require touching redirect URIs at all.
The developers who rarely fight redirect URI errors are the ones who internalized a simple rule: each environment gets its own credentials, its own redirect URIs, and its own configuration. Cross-pollinate them and you'll spend your afternoon debugging string mismatches instead of building your product.