Skip to content

Support dynamic port matching for localhost redirect URIs (RFC 8252 §7.3 extension) #873

@roncodingenthusiast

Description

@roncodingenthusiast

Preflight checklist

Ory Network Project

No response

Describe your problem

Fosite's dynamic port matching for loopback redirect URIs (per RFC 8252 §7.3) works for 127.0.0.1 and [::1] but not localhost. A client that registers http://localhost/callback cannot use http://localhost:54321/callback at authorization time.

The root cause is isLoopbackAddress, which uses net.ParseIP(hostname).IsLoopback(). Since net.ParseIP("localhost") returns nil, localhost is never recognized as loopback for port matching.

Fosite does handle localhost elsewhere: IsLocalhost explicitly checks hn == "localhost" to allow plain HTTP redirects. But that function is only used for transport security checks, not port matching.

Function Purpose Handles localhost?
IsLocalhost Transport security (allow HTTP?) Yes
isLoopbackAddress Dynamic port matching No

RFC 8252 §7.3 strictly specifies IP literals for loopback URIs, and §8.3 says localhost is NOT RECOMMENDED. However, since Fosite already accepts localhost for security purposes, and real-world clients (e.g. MCP/OAuth flows) register http://localhost/callback by convention, extending port matching to cover localhost would make the two code paths consistent.

Describe your ideal solution

Add localhost handling to isLoopbackAddress:

func isLoopbackAddress(hostname string) bool {
    if hostname == "localhost" {
        return true
    }
    return net.ParseIP(hostname).IsLoopback()
}

The existing hostname equality check in isMatchingAsLoopback (registered.Hostname() == requested.Hostname()) already prevents cross-matching between localhost and IP literals.

Workarounds or alternatives

  1. Register IP literals instead of localhost: Use http://127.0.0.1/callback as the RFC recommends. Requires updating existing clients that use localhost by convention.
  2. Patch downstream: Override redirect URI matching in each Fosite consumer.
  3. Register the exact port: Use http://localhost:54321/callback. Defeats dynamic port allocation.

Version

v0.49.0

Additional Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    featNew feature or request.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions