-
Notifications
You must be signed in to change notification settings - Fork 13
Open
Description
Summary
The authorization server does not comply with RFC 8252 Section 7.3, which requires allowing any port for loopback redirect URIs. Native apps using dynamic port selection for OAuth callbacks are currently rejected.
RFC 8252 Requirement
Section 7.3 states:
"The authorization server MUST allow any port to be specified at the time of the request for loopback IP redirect URIs"
This is because native apps typically:
- Bind to an OS-assigned available port (cannot predict which port)
- Start a temporary HTTP server on that port to receive the callback
- Need the authorization server to accept any port for loopback addresses
Current Behavior (Non-Compliant)
src/core/validators/authorize_validator.go:156-164:
for _, r := range client.RedirectURIs {
if input.RedirectURI == r.URI { // Exact string match only
clientHasRedirectURI = true
}
}Example:
- Registered URI:
http://127.0.0.1/callback - Request URI:
http://127.0.0.1:54321/callback - Result: ❌ Rejected (should be accepted)
Expected Behavior (RFC 8252 Compliant)
For loopback addresses only (127.0.0.1, [::1], localhost):
- Match scheme, hostname, and path
- Ignore port differences
| Registered | Requested | Result |
|---|---|---|
http://127.0.0.1/callback |
http://127.0.0.1/callback |
✅ Accept |
http://127.0.0.1/callback |
http://127.0.0.1:12345/callback |
✅ Accept |
http://127.0.0.1:8080/callback |
http://127.0.0.1:54321/callback |
✅ Accept |
http://[::1]/callback |
http://[::1]:9999/callback |
✅ Accept |
https://example.com/callback |
https://example.com:8080/callback |
❌ Reject (not loopback) |
Proposed Solution
func isLoopbackURI(uri string) bool {
parsed, err := url.Parse(uri)
if err != nil {
return false
}
host := parsed.Hostname()
return host == "127.0.0.1" || host == "::1" || host == "localhost"
}
func loopbackURIsMatch(registered, requested string) bool {
regParsed, err1 := url.Parse(registered)
reqParsed, err2 := url.Parse(requested)
if err1 != nil || err2 != nil {
return false
}
// Compare scheme, host (without port), and path
return regParsed.Scheme == reqParsed.Scheme &&
regParsed.Hostname() == reqParsed.Hostname() &&
regParsed.Path == reqParsed.Path
}
// In ValidateClientAndRedirectURI:
for _, r := range client.RedirectURIs {
if input.RedirectURI == r.URI {
clientHasRedirectURI = true
break
}
// RFC 8252 Section 7.3: Allow port variance for loopback
if isLoopbackURI(r.URI) && loopbackURIsMatch(r.URI, input.RedirectURI) {
clientHasRedirectURI = true
break
}
}Files Affected
src/core/validators/authorize_validator.go- Main fix locationsrc/core/validators/authorize_validator_test.go- Add test cases
Test Cases Needed
- Loopback with no port registered, port in request → Accept
- Loopback with port registered, different port in request → Accept
- Loopback with mismatched path → Reject
- Loopback with mismatched scheme (http vs https) → Reject
- Non-loopback with port difference → Reject (exact match required)
- IPv6 loopback
[::1]with port variance → Accept
References
Metadata
Metadata
Assignees
Labels
No labels