Skip to content

Conversation

@bluedog13
Copy link
Contributor

@bluedog13 bluedog13 commented Aug 8, 2025

OAuth Redirect URI Format Not Aligned with Microsoft's URL Standards

Problem

VS Code's OAuth implementation generates redirect URIs without trailing slashes, while Microsoft's own OAuth 2.0 documentation and standards-compliant identity providers (including Entra ID) require trailing slashes in redirect URIs per RFC specifications.

This creates a mismatch where:

  • VS Code generates: http://127.0.0.1:3000
  • IDP expects: http://127.0.0.1:3000/

Root Cause

Microsoft Entra ID (and other compliant IDPs) automatically append trailing slashes to redirect URIs during OAuth flows, following Microsoft's documented standards. However, VS Code's implementation returns URLs without trailing slashes, causing URI mismatch validation failures.

Recent Change Context

A June 29th PR that modified loopbackServer.ts removed the trailing slash, introducing this standards compliance issue. This change made VS Code generate non-compliant redirect URIs that don't align with Microsoft's own OAuth 2.0 format requirements.

Solution

This PR restores trailing slashes in two key locations:

  1. loopbackServer.ts (line 105): Runtime redirect URI generation
  2. oauth.ts (lines 739-746): Dynamic client registration redirect URIs

Changes:

  • http://127.0.0.1:${port}http://127.0.0.1:${port}/
  • http://localhosthttp://localhost/
  • http://127.0.0.1http://127.0.0.1/
  • http://localhost:${port}http://localhost:${port}/

Impact

  • Resolves OAuth authentication failures with "redirect_uri_mismatch" errors
  • Ensures compatibility with standards-compliant OAuth providers
  • Aligns VS Code with Microsoft's documented OAuth 2.0 URL format requirements

Standards Reference

This change ensures VS Code follows Microsoft's own OAuth 2.0 redirect URI format requirements, improving compatibility with standards-compliant identity providers.

Fixes #260425

This change adds a trailing slash to the redirect URI returned by the
loopbackServer's redirectUri getter to match the expected format for
OAuth client registration.

The issue occurs because Microsoft Entra ID automatically appends
a trailing slash to redirect URIs without a path segment, but VS Code
was returning URLs without the trailing slash, causing validation
failures during OAuth authentication.

Fixes microsoft#260425
if (this._port === undefined) {
throw new Error('Server is not started yet');
}
return `http://127.0.0.1:${this._port}`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you only update this and not the redirect uris?

'http://localhost',
'http://127.0.0.1',
// Added these for any server that might do
// only exact match on the redirect URI even
// though the spec says it should not care
// about the port.
`http://localhost:${DEFAULT_AUTH_FLOW_PORT}`,
`http://127.0.0.1:${DEFAULT_AUTH_FLOW_PORT}`
],

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above file has not been updated in a while.

The June 29th PR that modified loopbackServer.ts, removed the trailing slash, introducing this standards compliance issue.

Copy link
Contributor Author

@bluedog13 bluedog13 Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change may have affected it
a62ed27

Let me update this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have updated the PR with changes to src/vs/base/common/oauth.ts

Complements the loopbackServer.ts fix by ensuring redirect URIs used in
OAuth dynamic client registration also include trailing slashes for
complete standards compliance with Microsoft's OAuth 2.0 URL format.

Updated redirect URIs:
- http://localhost -> http://localhost/
- http://127.0.0.1 -> http://127.0.0.1/
- http://localhost:{port} -> http://localhost:{port}/
- http://127.0.0.1:{port} -> http://127.0.0.1:{port}/
@bluedog13 bluedog13 changed the title Fix OAuth redirect URI validation by adding trailing slash Fix OAuth redirect URI format to align with Microsoft's URL standards Aug 8, 2025
TylerLeonhardt
TylerLeonhardt previously approved these changes Aug 8, 2025
Copy link
Member

@TylerLeonhardt TylerLeonhardt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just need you to agree to the contributor agreement and we can get this in!

@vs-code-engineering vs-code-engineering bot added this to the August 2025 milestone Aug 8, 2025
@bluedog13
Copy link
Contributor Author

@microsoft-github-policy-service agree

Tyriar
Tyriar previously approved these changes Aug 8, 2025
@Tyriar
Copy link
Member

Tyriar commented Aug 8, 2025

Tests failing:

11805 passing (1m)
  82 pending
  1 failing

  1) OAuth
       Network Functions
         fetchDynamicRegistration should make correct request and parse response:

      
      + expected - actual

       [
         "https://insiders.vscode.dev/redirect"
         "https://vscode.dev/redirect"
      -  "http://localhost/"
      -  "http://127.0.0.1/"
      -  "http://localhost:33418/"
      -  "http://127.0.0.1:33418/"
      +  "http://localhost"
      +  "http://127.0.0.1/"
      +  "http://localhost:33418"
      +  "http://127.0.0.1:33418/"
       ]

@bluedog13
Copy link
Contributor Author

bluedog13 commented Aug 8, 2025

Do you want me to open a different PR to fix the tests or update the current one itself?

@TylerLeonhardt
Copy link
Member

@bluedog13 can you update the current one please

The fetchDynamicRegistration function correctly includes trailing slashes
on redirect URIs per the implementation. This updates the test expectations
to match the actual behavior, fixing the test failure.

The implementation in oauth.ts includes trailing slashes on localhost URIs:
- 'http://localhost/' (with trailing slash)
- 'http://127.0.0.1/' (with trailing slash)
- 'http://localhost:/' (with trailing slash)
- 'http://127.0.0.1:/' (with trailing slash)

This test was expecting URIs without trailing slashes, causing the assertion
to fail. The fix aligns the test with the correct implementation behavior.
@bluedog13 bluedog13 dismissed stale reviews from Tyriar and TylerLeonhardt via 3ff823a August 8, 2025 20:20
@bluedog13
Copy link
Contributor Author

The tests have been updated.

@TylerLeonhardt TylerLeonhardt enabled auto-merge (squash) August 8, 2025 20:25
@TylerLeonhardt TylerLeonhardt merged commit 8065598 into microsoft:main Aug 8, 2025
17 checks passed
@TylerLeonhardt
Copy link
Member

Thanks for contributing @bluedog13!

@bluedog13
Copy link
Contributor Author

Thank you for accepting the PR. @TylerLeonhardt

@vs-code-engineering vs-code-engineering bot locked and limited conversation to collaborators Sep 22, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

VS Code OAuth Redirect URI Format Not Aligned with Microsoft's URL Standards

4 participants