Skip to content
New Livestream: How Banks Protect Their Apps with FAPI 2.0. Register Now!

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 host
builder.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 host
new 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/callback

The validator applies the same port-agnostic behavior to post-logout redirects when the client registers http://127.0.0.1 in PostLogoutRedirectUris.

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 literal 127.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.

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.