Pin OIDC redirect to App__Domain when set
Override the OIDC redirect_uri (and post-logout redirect) to <domain>/signin-oidc instead of deriving it from the request host. Set in both the authorize request and the code->token redemption so Entra sees a matching redirect_uri. Falls back to request-host derivation when App__Domain is unset. Domain binding hoisted so OIDC and ClientConnect share one AppDomainOptions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+34
-2
@@ -69,6 +69,12 @@ builder.Services.AddDataProtection()
|
||||
// Localization string source — Scoped: one per circuit, with its own explicit culture.
|
||||
builder.Services.AddScoped<SharepointToolbox.Web.Localization.TranslationSource>();
|
||||
|
||||
// ── Public domain ─────────────────────────────────────────────────────────────
|
||||
// App__Domain (e.g. sptb.example.com) drives both OIDC sign-in (below) and the
|
||||
// SharePoint-connect redirect URI. Bound once here so both consumers share it.
|
||||
var appDomain = new AppDomainOptions();
|
||||
builder.Configuration.GetSection("App").Bind(appDomain);
|
||||
|
||||
// ── Authentication ────────────────────────────────────────────────────────────
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
@@ -133,6 +139,34 @@ else
|
||||
options.MapInboundClaims = false;
|
||||
options.TokenValidationParameters.NameClaimType = "preferred_username";
|
||||
|
||||
// When App__Domain is set, pin the OIDC redirect_uri (and post-logout redirect) to that
|
||||
// public host instead of deriving it from the request scheme/host. Keeps sign-in working
|
||||
// when the app can't see its real external host (no/incorrect forwarded Host header, or
|
||||
// several hostnames reach the same instance). The value must match the /signin-oidc URI
|
||||
// registered on the Oidc app. The authorize request and the code→token redemption MUST
|
||||
// send the identical redirect_uri, so override it in both events.
|
||||
var oidcRedirectUri = appDomain.BuildUrl(options.CallbackPath.Value ?? "/signin-oidc");
|
||||
var postLogoutUri = appDomain.BuildUrl(options.SignedOutCallbackPath.Value ?? "/signout-callback-oidc");
|
||||
if (oidcRedirectUri is not null)
|
||||
{
|
||||
options.Events.OnRedirectToIdentityProvider = ctx =>
|
||||
{
|
||||
ctx.ProtocolMessage.RedirectUri = oidcRedirectUri;
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
options.Events.OnAuthorizationCodeReceived = ctx =>
|
||||
{
|
||||
if (ctx.TokenEndpointRequest is not null)
|
||||
ctx.TokenEndpointRequest.RedirectUri = oidcRedirectUri;
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
options.Events.OnRedirectToIdentityProviderForSignOut = ctx =>
|
||||
{
|
||||
ctx.ProtocolMessage.PostLogoutRedirectUri = postLogoutUri;
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
}
|
||||
|
||||
options.Events.OnTokenValidated = async ctx =>
|
||||
{
|
||||
var userService = ctx.HttpContext.RequestServices.GetRequiredService<IUserService>();
|
||||
@@ -176,8 +210,6 @@ builder.Services.Configure<ClientConnectOptions>(builder.Configuration.GetSectio
|
||||
// when ClientConnect__RedirectUri isn't set explicitly. Lets a deployment configure a
|
||||
// single domain (e.g. sptb.example.com) instead of spelling out the full callback URL.
|
||||
// An explicit RedirectUri still wins, so existing configs are unaffected.
|
||||
var appDomain = new AppDomainOptions();
|
||||
builder.Configuration.GetSection("App").Bind(appDomain);
|
||||
builder.Services.PostConfigure<ClientConnectOptions>(opts =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(opts.RedirectUri) &&
|
||||
|
||||
Reference in New Issue
Block a user