OAuth Redirect URIs For Desktop And CLI MCP Clients
Desktop and command-line OAuth clients, including MCP clients, often open the user’s browser for authorization and start a temporary HTTP listener to receive the callback. The operating system assigns an available port, so the redirect URI changes each time the client starts. IdentityServer’s default redirect URI validator uses exact string matching, which rejects a port that was not registered in advance.
IdentityServer provides an opt-in validator for the AppAuth pattern described by RFC 8252. It accepts an ephemeral port on the IPv4 loopback address while keeping exact matching for other redirect URIs.
How To Enable Port-Agnostic Loopback Redirects
Section titled “How To Enable Port-Agnostic Loopback Redirects”Use this setup when a public client can use the IPv4 loopback address but cannot know its callback port before it starts.
Register the validator in the IdentityServer host:
// Program.cs in the IdentityServer hostbuilder.Services.AddIdentityServer() .AddAppAuthRedirectUriValidator();AddAppAuthRedirectUriValidator registers StrictRedirectUriValidatorAppAuth as the application’s
IRedirectUriValidator. It replaces the default validator, keeps exact matching for regular redirect URIs, and adds the
port-agnostic 127.0.0.1 behavior described below.
Configure the public client in the IdentityServer host with PKCE and the exact base URI http://127.0.0.1:
// Config.cs in the IdentityServer hostnew Client{ ClientId = "desktop-mcp-client", RequireClientSecret = false, RequirePkce = true, AllowedGrantTypes = GrantTypes.Code, RedirectUris = { "http://127.0.0.1" }, AllowedScopes = { "openid", "mcp:tools" }};At runtime, the client can use an available port and callback path:
http://127.0.0.1:49152/callbackThe validator applies the same port-agnostic behavior to post-logout redirects when the client registers
http://127.0.0.1 in PostLogoutRedirectUris.
What Does The AppAuth Validator Accept?
Section titled “What Does The AppAuth Validator Accept?”The built-in validator requires all the following:
- The client has
RequirePkce = true - The registered redirect URI is exactly
http://127.0.0.1, without a port - The requested redirect URI uses
http, the IPv4 literal127.0.0.1, and a numeric port from 0 through 65535
Clients should use the non-zero port assigned by the operating system. Port 0 is accepted by the validator, but it does not identify the port where the client is listening.
It does not apply port-agnostic matching to localhost, IPv6 loopback ([::1]), HTTPS loopback URIs, or any other host.
Those values still need an exact registered match unless you provide a custom validator.
How To Secure The Local Callback
Section titled “How To Secure The Local Callback”RFC 8252 allows HTTP for loopback redirects because the request does not leave the device. It requires authorization servers to allow an ephemeral port for loopback IP redirect URIs.
The client should:
- Use an external browser for authorization
- Bind the listener only to the loopback interface
- Open the listener immediately before authorization and close it after the callback
- Use PKCE and validate the authorization response state
- Avoid
localhost, whose name resolution may not point only to the loopback interface
PKCE protects an intercepted authorization code, but it does not make a shared client secret confidential. Desktop and command-line applications should be configured as public clients unless they can protect credentials independently.
The built-in validator intentionally supports only 127.0.0.1. If a third-party client requires localhost or IPv6,
use a custom IRedirectUriValidator and document why the broader behavior is needed.