Skip to content

feat: add web consent redirect URIs to BYO Entra apps#450

Open
ragurubhaarath wants to merge 6 commits into
mainfrom
u/bhraguru/public-clients-redirect-uris
Open

feat: add web consent redirect URIs to BYO Entra apps#450
ragurubhaarath wants to merge 6 commits into
mainfrom
u/bhraguru/public-clients-redirect-uris

Conversation

@ragurubhaarath
Copy link
Copy Markdown
Contributor

Summary

  • Adds environment-aware consent redirect URIs as web platform redirect URIs on the -PublicClients Entra app created during develop-mcp publish and develop-mcp register-external-mcp-server flows
  • Test/PreProd/PPE: https://sdf.admin.cloud.microsoft/?ref=tools/consent and https://ignite.admin.cloud.microsoft/?ref=tools/consent
  • Prod (default): https://admin.cloud.microsoft/?ref=tools/consent
  • Environment resolved from explicit parameter, A365_ENVIRONMENT env var, or defaults to prod

Test plan

  • Unit tests pass (14 tests in EntraAppProvisionerTests)
  • Tested live register-external-mcp-server against PreProd — confirmed publicClient URIs (4) and web URIs (2) are set separately via two PATCH calls
  • Verify web redirect URIs appear under "Web" platform in Entra portal for the created app

🤖 Generated with Claude Code

Add environment-aware consent redirect URIs (web platform) to the
PublicClients app created during publish and register flows. Test/PreProd
gets sdf.admin and ignite.admin URIs; Prod gets admin.cloud.microsoft.
Environment is resolved from the explicit parameter, A365_ENVIRONMENT
env var, or defaults to prod.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ragurubhaarath ragurubhaarath requested a review from a team as a code owner June 6, 2026 17:09
Copilot AI review requested due to automatic review settings June 6, 2026 17:09
@ragurubhaarath ragurubhaarath requested a review from a team as a code owner June 6, 2026 17:09
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 6, 2026

⚠️ Deprecation Warning: The deny-licenses option is deprecated for possible removal in the next major release. For more information, see issue 997.

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the Entra Public Clients app provisioning logic to also set environment-specific consent redirect URIs on the Web platform, in addition to the existing publicClient canonical redirect URIs, and updates unit tests accordingly.

Changes:

  • Add env-to-consent-redirect-URI mapping and patch Web platform redirect URIs during Public Clients app creation.
  • Expand unit tests to validate both publicClient and web redirect URI updates across prod vs test/preprod/ppe.
  • Adjust publish flow call site to account for the new optional environment parameter insertion (via named ct:).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
src/Microsoft.Agents.A365.DevTools.Cli/Services/EntraAppProvisioner.cs Adds environment-aware consent redirect URI selection and applies it via a second Graph PATCH to the app’s web redirect URIs.
src/Tests/Microsoft.Agents.A365.DevTools.Cli.Tests/Services/EntraAppProvisionerTests.cs Updates tests to assert separate PATCH calls for publicClient vs web redirect URIs across environments and failure modes.
src/Microsoft.Agents.A365.DevTools.Cli/Commands/PublishCommandExecutor.cs Updates the provisioning call site to use named ct: after inserting the new optional method parameter.

bhaarathms and others added 2 commits June 6, 2026 10:18
…Clients

Extract SetWebConsentRedirectUrisAsync helper and call it from both
CreateProxyAppAsync (A365Proxy, RemoteProxy) and
CreatePublicClientsAppAsync. All apps created in the addmcpserver flow
now get the environment-aware consent redirect URIs on the web platform.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…irect URI overwrite

The register flow's UpdateA365RedirectUrisAsync and
UpdateRemoteProxyRedirectUrisAsync overwrite web.redirectUris with the
platform-returned redirect URI, erasing consent URIs set earlier by the
provisioner. Move consent URI injection to these final PATCH calls so
the consent URIs and platform redirect URIs coexist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 6, 2026 18:12
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.

Comment on lines +122 to +137
var resolvedEnvironment = environment ?? Environment.GetEnvironmentVariable("A365_ENVIRONMENT") ?? "prod";
var consentUris = GetConsentRedirectUris(resolvedEnvironment);

var success = await _graphApiService.UpdateAppRedirectUrisAsync(tenantId, objectId, consentUris, ct);
if (success)
{
_logger.LogDebug(
"Set {RedirectUriCount} web redirect URIs on '{AppName}' ({ObjectId}): {RedirectUris}",
consentUris.Length, appName, objectId, string.Join(", ", consentUris));
}
else
{
var msg = $"Failed to set web redirect URIs on {roleDisplay} app '{appName}'.";
_logger.LogWarning(msg);
warnings?.Add(msg);
}
Comment on lines 319 to +320
var publicClients = await provisioner.CreatePublicClientsAppAsync(
input.ServerName, tenantId, serviceTreeId: null, warnings, ct);
input.ServerName, tenantId, serviceTreeId: null, warnings, ct: ct);
Comment on lines +183 to +189
capturedWebUris.Should().ContainSingle();
capturedWebUris[0].Should().BeEquivalentTo(
new[]
{
"https://admin.cloud.microsoft/?ref=tools/consent",
},
opt => opt.WithStrictOrdering());
Comment on lines +233 to +240
capturedWebUris.Should().ContainSingle();
capturedWebUris[0].Should().BeEquivalentTo(
new[]
{
"https://sdf.admin.cloud.microsoft/?ref=tools/consent",
"https://ignite.admin.cloud.microsoft/?ref=tools/consent",
},
opt => opt.WithStrictOrdering());
Comment on lines +786 to +789
var environment = Environment.GetEnvironmentVariable("A365_ENVIRONMENT") ?? "prod";
var a365Uris = DevelopMcpCommand.BuildRedirectUriList(a365RedirectUri, a365TcUri, a365NonTcUri)
.Concat(EntraAppProvisioner.GetConsentRedirectUris(environment))
.ToArray();
Comment on lines +823 to +826
var environment = Environment.GetEnvironmentVariable("A365_ENVIRONMENT") ?? "prod";
var remoteUris = DevelopMcpCommand.BuildRedirectUriList(remoteRedirectUri, remoteTcUri, remoteNonTcUri)
.Concat(EntraAppProvisioner.GetConsentRedirectUris(environment))
.ToArray();
Comment on lines +282 to 299
[Fact]
public async Task CreatePublicClientsAppAsync_WhenWebRedirectUriUpdateReturnsFalse_AppendsWarning()
{
_graph.CreateEntraAppAsync(TenantId, Arg.Any<string>(), serviceTreeId: Arg.Any<string?>(), Arg.Any<CancellationToken>())
.Returns(Task.FromResult<(string ObjectId, string ClientId)?>((AppObjectId, AppClientId)));
_graph.UpdateAppPublicClientRedirectUrisAsync(
TenantId, AppObjectId, Arg.Any<string[]>(), Arg.Any<CancellationToken>())
.Returns(Task.FromResult(true));
_graph.UpdateAppRedirectUrisAsync(
TenantId, AppObjectId, Arg.Any<string[]>(), Arg.Any<CancellationToken>())
.Returns(Task.FromResult(false));

var warnings = new List<string>();
var result = await _provisioner.CreatePublicClientsAppAsync(ServerName, TenantId, serviceTreeId: null, warnings);

result.ClientId.Should().Be(AppClientId);
warnings.Should().ContainSingle().Which.Should().Be($"Failed to set web redirect URIs on Public Clients app '{ServerName}-PublicClients'.");
}
@ragurubhaarath ragurubhaarath changed the title feat: add web consent redirect URIs to PublicClients Entra apps feat: add web consent redirect URIs to BYO Entra apps Jun 6, 2026
…thout platform redirect URI

When the platform does not return a redirect URI (e.g. NoAuth flow for
A365Proxy, or missing remoteMCPServerProxyRedirectUri for RemoteProxy),
the consent redirect URIs were skipped entirely. Add a fallback that
sets consent-only web redirect URIs on all proxy apps regardless.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pronak657
pronak657 previously approved these changes Jun 6, 2026
…rage

- GetConsentRedirectUris returns defensive copies to prevent mutation of
  shared static arrays
- SetWebConsentRedirectUrisAsync now uses RetryHelper for transient
  Graph failures, consistent with publicClient redirect URI handling
- Add because: clauses to web consent URI test assertions documenting
  the admin consent portal contract
- Add test for web redirect URI update throw path

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 6, 2026 18:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comment on lines +36 to +42
internal static string[] GetConsentRedirectUris(string environment)
{
return environment?.ToLowerInvariant() switch
{
"test" or "preprod" or "ppe" => [.. TestPreProdConsentRedirectUris],
_ => [.. ProdConsentRedirectUris],
};
Comment on lines +225 to +233
capturedPublicClientUris[0].Should().BeEquivalentTo(
new[]
{
$"ms-appx-web://Microsoft.AAD.BrokerPlugin/{AppClientId}",
"http://localhost:8080/callback",
"https://vscode.dev/redirect",
"http://localhost",
},
opt => opt.WithStrictOrdering());
Comment on lines +791 to +794
var environment = Environment.GetEnvironmentVariable("A365_ENVIRONMENT") ?? "prod";
var a365Uris = DevelopMcpCommand.BuildRedirectUriList(a365RedirectUri, a365TcUri, a365NonTcUri)
.Concat(EntraAppProvisioner.GetConsentRedirectUris(environment))
.ToArray();
…aking internal URLs

Replace hardcoded test/preprod consent redirect URIs with
A365_CONSENT_REDIRECT_URIS_{ENV} env var (comma-separated). Prod URI
remains hardcoded as it is public. When no env var is set, all
environments fall back to the prod URI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants