What the provider is actually comparing
When your app sends a user to a sign-in provider, it includes a return address, usually called redirect_uri. The provider compares that value with the callback addresses registered for your app. A mismatch error means that comparison failed; it does not mean your login code is broken or that the provider is down. Current security guidance (RFC 9700, January 2025) requires authorization servers to use exact string matching, with one carve-out for native apps that use a variable port on localhost.
Exact means exact. Google states that the scheme, letter case and trailing slash must all be identical and that wildcards are not allowed. https://app.invalid/auth/callback and https://app.invalid/auth/callback/ are different strings, as are http and https, a www prefix, a port number and a different path.
- Compare the whole string, not the part you expect to matter.
- The address that counts is the one your app sends in the authorisation request, not the one you intended to send.
- GitHub documents a wildcard-style matching mode that is on for some older apps; do not rely on it, because it lets codes travel to more addresses than you intend.
Where your app gets the address from
Most apps do not hard-code the return address. They build it from a framework base-URL setting, an environment variable, or the host the request arrived on. That is why sign-in can work on one address and fail on another: a preview deployment has a new host name, a production variable was never set, or a proxy makes the app believe its own address is something else. In Auth.js version 5, for example, the host is inferred from request headers and the base-URL variable is mostly unnecessary except for a non-default base path, so a wrong forwarded host header produces a wrong return address.
The most reliable evidence is the provider's own error page or the browser address bar at the moment of the error, which shows the exact value your app sent. Copy it without editing and compare it with the registered list.
- Check which environment variable or framework setting the failing environment really reads, and that it was set before the last build or restart.
- Check whether the failing address is a temporary preview host that nobody registered.
- If the value is correct but the provider rejects it, the registered list is the side to change.
Other causes that look similar
Several different failures are described as a redirect error. A provider can show an unverified-app or test-users-only warning, which is a review or publishing status and not a code fault. An invalid-client message usually means the client identifier or secret in the failing environment belongs to a different provider app. A sign-in can also fail one step later: RFC 6749 requires that when a redirect URI was sent in the authorization request it is sent again in the token request with an identical value, so an app that rebuilds the address differently for the second request fails after the user has already approved access.
If the return reaches your app but no session starts, the cause may be the stored state value or code verifier, or the session cookie, rather than the registered address. Those have their own guides.
- Error names the redirect address: compare strings.
- Error names an unverified app or test users: check the provider console status.
- Error names the client: check which client identifier the failing environment uses.
- Return reaches your app and the login page shows again: look at state, verifier and cookies.
A safe first investigation
Use a test account and a non-production provider app if you can; do not experiment with a production client secret. Start one sign-in, copy the redirect address from the provider's error page, and put it beside the registered list. If they differ, decide which one is right. Usually the app should be changed to build a stable address and the console should be given exactly that string. Do not add a wildcard or a broad prefix to make a changing preview address work; Google forbids wildcards, and where they are allowed they widen where a sign-in code can be delivered.
- Register one exact callback per environment, and keep a separate provider app for each environment where you can.
- For changing preview hosts, use one stable test address and sign in there instead of registering each preview.
- Never paste a client secret into a ticket or an enquiry.
What fixes it, what does not fit and how the paid job is accepted
A repair builds the correct return address for each environment and gives the person who holds the provider console the exact list to register. It does not include provider app review, consent-screen publishing, single sign-on for business customers or merging duplicate user accounts. Our posted test price for one provider and up to three environments is £195, untested, paid only after a test sign-in passes in every agreed environment and you sign off. Acceptance also requires that a return with a missing or altered state value is rejected, so a fix cannot work by switching a check off. You keep the client secret and the console; we hold neither. Send the provider name, the failing environments and the redacted error text in your first enquiry, not secrets, tokens or source code.
- The worked example shows a synthetic registered list and a request matrix with the mismatch named for each row.
Sources and limits
- RFC 9700: OAuth 2.0 Security Best Current Practice (January 2025) Checked 2026-10-11.
- Authorization servers are required to compare redirect URIs by exact string matching (section 2.1); the only carve-out is variable port numbers for native apps using localhost.
- RFC 6749: The OAuth 2.0 Authorization Framework Checked 2026-10-11.
- If a redirect URI was sent in the authorization request it must also be sent in the token request, and the two values must be identical (section 4.1.3).
- Google: OAuth 2.0 for web server applications Checked 2026-10-11.
- The redirect_uri must exactly match an authorised URI; scheme, letter case and trailing slash must be identical; wildcards are not allowed; HTTPS is required except for localhost.
- GitHub: Authorizing OAuth apps Checked 2026-10-11.
- Without wildcard matching the redirect URL must exactly match the callback URL; if redirect_uri is omitted users are sent to the first configured callback URL.
- Auth.js: Deployment Checked 2026-10-11.
- In Auth.js v5 the host is inferred from request headers, so AUTH_URL is mostly unnecessary except for a non-default base path.