Skip to content

feat: add RFC 8252 loopback port flexibility for native apps#145

Merged
mattzcarey merged 6 commits intocloudflare:mainfrom
mattzcarey:feat/rfc8252-loopback-port-flexibility
Feb 26, 2026
Merged

feat: add RFC 8252 loopback port flexibility for native apps#145
mattzcarey merged 6 commits intocloudflare:mainfrom
mattzcarey:feat/rfc8252-loopback-port-flexibility

Conversation

@mattzcarey
Copy link
Contributor

Summary

  • Add RFC 8252 Section 7.3 compliance for loopback redirect URI port handling
  • Native apps (VS Code, Cursor, CLI tools) can now use ephemeral ports obtained from the OS at runtime
  • Loopback URIs (127.x.x.x, ::1) match on scheme, host, and path while ignoring port; non-loopback URIs still require exact match

Background

Per RFC 8252 Section 7.3:

While redirect URIs using localhost (i.e., "http://localhost:{port}/{path}") function similarly to loopback IP redirects, the use of localhost is NOT RECOMMENDED. [...] To perform authorization using loopback interface redirect URIs, the native app [...] performs a Loopback Interface Redirection by constructing the redirect_uri from the loopback IP address [...] and whatever port the HTTP server is listening on.

The authorization server MUST allow any port to be specified at the time of the request for loopback IP redirect URIs, to accommodate clients that obtain an available ephemeral port from the operating system at the time of the request.

Native desktop applications like VS Code, Cursor, and CLI tools typically:

  1. Start a local HTTP server on an ephemeral port
  2. Register a redirect URI like http://127.0.0.1:8080/callback
  3. But at runtime, the OS assigns a different port (e.g., http://127.0.0.1:52431/callback)

This change enables these native apps to work correctly by allowing any port for loopback redirect URIs.

Implementation

Added two helper functions:

  • isLoopbackUri() - Detects loopback addresses (127.0.0.0/8 and ::1)
  • isValidRedirectUri() - Validates redirect URIs with RFC 8252 loopback support

Replaced all 3 occurrences of redirectUris.includes(redirectUri) with isValidRedirectUri(redirectUri, clientInfo.redirectUris):

  1. Authorization request parsing
  2. Token exchange
  3. completeAuthorization

Test Plan

  • All 215 existing tests pass
  • Manual testing with native app using ephemeral port
  • Verify non-loopback URIs still require exact match
  • Verify loopback URIs with different schemes are rejected
  • Verify loopback URIs with different paths are rejected

Fixes #35

Per RFC 8252 Section 7.3, authorization servers MUST allow any port for
loopback IP redirect URIs (127.0.0.0/8 and ::1). Native apps like VS Code,
Cursor, and CLI tools obtain ephemeral ports from the OS at runtime.

This change allows loopback redirect URIs to match on scheme, host, and
path while ignoring the port. Non-loopback URIs still require exact match.

Fixes cloudflare#35
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 23, 2026

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/workers-oauth-provider/@cloudflare/workers-oauth-provider@145

commit: 9a57612

@changeset-bot
Copy link

changeset-bot bot commented Feb 23, 2026

🦋 Changeset detected

Latest commit: 9a57612

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@cloudflare/workers-oauth-provider Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@mattzcarey mattzcarey marked this pull request as draft February 23, 2026 16:31
@mattzcarey mattzcarey marked this pull request as draft February 23, 2026 16:31
Add 22 tests covering all RFC 8252 Section 7.3 loopback port flexibility
scenarios including IPv4/IPv6 loopback, port flexibility, path/scheme/host
rejection, localhost exclusion, token exchange, completeAuthorization,
full end-to-end flows, and multiple registered URI matching.

Also include query string comparison in loopback URI validation per Codex
review feedback - RFC 8252 only exempts port, not query.
@mattzcarey mattzcarey marked this pull request as ready for review February 25, 2026 12:32
@mattzcarey mattzcarey merged commit 6ce5c10 into cloudflare:main Feb 26, 2026
4 checks passed
@github-actions github-actions bot mentioned this pull request Feb 26, 2026
mattzcarey pushed a commit that referenced this pull request Feb 26, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @cloudflare/workers-oauth-provider@0.2.4

### Patch Changes

- [#136](#136)
[`a8c5936`](a8c5936)
Thanks [@mattzcarey](https://github.com/mattzcarey)! - Add
`/.well-known/oauth-protected-resource` endpoint (RFC 9728) for OAuth
2.0 Protected Resource Metadata discovery, as required by the MCP
authorization specification. The endpoint is always served with sensible
defaults (request origin as resource and authorization server), and can
be customized via the new `resourceMetadata` option.

- [#151](#151)
[`dbb150e`](dbb150e)
Thanks [@mattzcarey](https://github.com/mattzcarey)! - Add
`allowPlainPKCE` option to enforce S256-only PKCE as recommended by
OAuth 2.1. When set to false, the plain PKCE method is rejected and only
S256 is accepted. Defaults to true for backward compatibility.

- [#140](#140)
[`65d5cfa`](65d5cfa)
Thanks [@mattzcarey](https://github.com/mattzcarey)! - Fix apiHandler
route matching when set to '/' to use exact match instead of prefix
match, preventing it from matching all routes and breaking OAuth
endpoints

- [#150](#150)
[`734738c`](734738c)
Thanks [@mattzcarey](https://github.com/mattzcarey)! - Fix TypeScript
types by making OAuthProviderOptions generic over Env, eliminating the
need for @ts-expect-error workarounds when using typed environments

- [#145](#145)
[`6ce5c10`](6ce5c10)
Thanks [@mattzcarey](https://github.com/mattzcarey)! - Add RFC 8252
Section 7.3 compliance: allow any port for loopback redirect URIs
(127.x.x.x, ::1) to support native apps that use ephemeral ports

- [#143](#143)
[`8909060`](8909060)
Thanks [@mattzcarey](https://github.com/mattzcarey)! - Include
`resource_metadata` URL in `WWW-Authenticate` headers on 401 responses
per RFC 9728 §5.1, enabling clients to discover the protected resource
metadata endpoint directly from authentication challenges.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Please follow the best practices for Loopback Interface Redirection and allow localhost with any port

2 participants