git-ecosystem/git-credential-manager · error · ArgumentException
Only localhost is supported as a redirect URI.
Error message
Only localhost is supported as a redirect URI.
What it means
OAuth2SystemWebBrowser.UpdateRedirectUri rewrites the redirect URI to a loopback address with a free TCP port so the embedded system browser can intercept the authorization response. It throws ArgumentException because only loopback (localhost/127.0.0.1) redirect URIs can be intercepted locally.
Solutions
- Use a loopback redirect URI such as http://localhost/callback (port is optional; a free port is chosen automatically)
- Register http://localhost as an allowed redirect URI in your OAuth provider's app settings
- Use a different browser/flow (e.g. device code flow) when a non-loopback redirect is required
Example fix
// before
browser.UpdateRedirectUri(new Uri("https://myapp.example.com/callback"));
// after
browser.UpdateRedirectUri(new Uri("http://localhost/callback")); Defensive patterns
Strategy: validation
Validate before calling
if (!redirectUri.IsLoopback) throw new ArgumentException("Browser flow requires a loopback redirect URI; use device code flow instead.", nameof(redirectUri)); Type guard
bool IsLoopbackRedirect(Uri u) => u.IsLoopback;
Try / catch
try { uri = browser.UpdateRedirectUri(uri); } catch (ArgumentException) { return await GetTokenByDeviceCodeAsync(client, scopes); } Prevention
- Always use http://localhost[...]/ as redirect URI for desktop flows
- Register the localhost redirect URI with your OAuth provider
- Check uri.IsLoopback before invoking any OAuth2SystemWebBrowser API
When it happens
Trigger: Calling UpdateRedirectUri with a Uri whose IsLoopback is false — e.g. https://myapp.example.com/callback, a public hostname, or a non-loopback IP.
Common situations: Registering an OAuth app with an https production redirect URI and reusing it in a desktop flow; copying a web-app redirect URI into the CLI config; misunderstanding that this browser implementation only supports local loopback interception.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Bitbucket DC OAuth Client ID must be defined
- Bitbucket DC OAuth Client Secret must be defined
- RemoteUri must be defined to generate Bitbucket DC OAuth2…
- Extra query parameter
- Missing ' ' in response.
AI-assisted analysis of git-ecosystem/git-credential-manager@e8ce762cd0 (2026-09-11).
Data as JSON: /api/errors/e564abb8db4e5892.
Report an issue: GitHub.
Appendix: source
Thrown at src/Core/Authentication/OAuth/OAuth2SystemWebBrowser.cs:85
</script></body></html>";
private readonly ISessionManager _sessionManager;
private readonly OAuth2WebBrowserOptions _options;
public OAuth2SystemWebBrowser(ISessionManager sessionManager, OAuth2WebBrowserOptions options)
{
EnsureArgument.NotNull(sessionManager, nameof(sessionManager));
EnsureArgument.NotNull(options, nameof(options));
_sessionManager = sessionManager;
_options = options;
}
public Uri UpdateRedirectUri(Uri uri)
{
if (!uri.IsLoopback)
{
throw new ArgumentException("Only localhost is supported as a redirect URI.", nameof(uri));
}
// If a port has been specified use it, otherwise find a free one
if (uri.IsDefaultPort)
{
int port = GetFreeTcpPort();
return new UriBuilder(uri) {Port = port}.Uri;
}
return uri;
}
public async Task<IDictionary<string, string>> GetAuthenticationResponseAsync(
Uri authorizationUri, Uri redirectUri, OAuth2ResponseMode responseMode, CancellationToken ct)
{
if (!redirectUri.IsLoopback)
{
throw new ArgumentException("Only localhost is supported as a redirect URI.", nameof(redirectUri));View on GitHub (pinned to e8ce762cd0)