Skip to content

fix: support custom URI schemes in OAuth client registration#181

Merged
taylorotwell merged 9 commits into
laravel:mainfrom
alexis-riot:fix/oauth-custom-scheme-redirect-uris
Mar 26, 2026
Merged

fix: support custom URI schemes in OAuth client registration#181
taylorotwell merged 9 commits into
laravel:mainfrom
alexis-riot:fix/oauth-custom-scheme-redirect-uris

Conversation

@alexis-riot
Copy link
Copy Markdown
Contributor

Summary

Fixes #173

Native desktop OAuth clients (Cursor IDE, VS Code, Claude Desktop) use private-use URI schemes (RFC 8252) like cursor:// for redirect callbacks. The current url validation rule in OAuthRegisterController rejects these because PHP's filter_var(FILTER_VALIDATE_URL) only accepts http(s):// schemes. Additionally, validation errors return HTML redirects instead of JSON when the client sends Accept: */*.

Changes

  • config/mcp.php — Add allowed_custom_schemes config array (empty by default, opt-in). Developers explicitly whitelist the schemes they need, preserving strict MCP spec compliance by default.
  • OAuthRegisterController — Replace the url rule with a custom closure that accepts URIs whose scheme is in allowed_custom_schemes (validating that a host component is present), and falls back to standard filter_var URL validation otherwise. Replace $request->validate() with Validator::make() to guarantee a JSON 422 response regardless of the Accept header.
  • RegistrarTest — 7 new Pest test cases covering custom scheme acceptance/rejection, edge cases, and the JSON error format fix.

Design decisions

  • Opt-in by default: Empty allowed_custom_schemes preserves strict MCP spec compliance. No behavioral change for existing users.
  • Explicit JSON responses: Validator::make() + manual response()->json() guarantees 422 JSON regardless of Accept header, fixing the HTML redirect bug.
  • No domain checks on custom schemes: Custom scheme URIs bypass redirect_domains validation since domain semantics don't apply to private-use URI schemes.

Test plan

  • Custom schemes accepted when configured (cursor://, vscode://, claude://)
  • Custom schemes rejected when not configured
  • Custom schemes rejected when a different scheme is configured
  • Custom schemes with missing host component rejected
  • Standard HTTP URLs still work alongside custom schemes
  • JSON error response returned even with Accept: */* header
  • All existing tests pass unchanged

Made with Cursor

Native desktop OAuth clients (Cursor, VS Code, Claude Desktop) use
private-use URI schemes (RFC 8252) for redirect callbacks. The 'url'
validation rule in OAuthRegisterController rejects these because PHP's
filter_var(FILTER_VALIDATE_URL) only accepts http(s):// schemes.
Additionally, validation errors return HTML redirects instead of JSON
when the client sends Accept: */*.

- Add opt-in 'allowed_custom_schemes' config option to mcp.php
- Replace 'url' rule with custom closure supporting configured schemes
- Use Validator::make() to guarantee JSON 422 responses on failure
- Add tests for custom scheme handling and JSON error format

Fixes laravel#173

Made-with: Cursor
@alexis-riot alexis-riot force-pushed the fix/oauth-custom-scheme-redirect-uris branch from 8ad5945 to 95827f4 Compare March 25, 2026 12:31
@taylorotwell taylorotwell marked this pull request as draft March 25, 2026 14:09
@pushpak1300 pushpak1300 self-requested a review March 25, 2026 14:12
@pushpak1300 pushpak1300 removed their assignment Mar 26, 2026
@pushpak1300 pushpak1300 marked this pull request as ready for review March 26, 2026 11:19
@taylorotwell taylorotwell merged commit f342a34 into laravel:main Mar 26, 2026
0 of 21 checks passed
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.

OAuth dynamic client registration rejects custom URI schemes like cursor:// for desktop clients (Cursor IDE)

3 participants