Skip to content

Commit 87c0397

Browse files
authored
Add AdditionalAuthorizationParameters to OAuthOptions/OpenIdConnectOptions (#54119)
1 parent b9eaae0 commit 87c0397

File tree

8 files changed

+85
-6
lines changed

8 files changed

+85
-6
lines changed

src/Security/Authentication/OAuth/src/OAuthHandler.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -303,12 +303,12 @@ protected virtual string BuildChallengeUrl(AuthenticationProperties properties,
303303
var scope = scopeParameter != null ? FormatScope(scopeParameter) : FormatScope();
304304

305305
var parameters = new Dictionary<string, string>
306-
{
307-
{ "client_id", Options.ClientId },
308-
{ "scope", scope },
309-
{ "response_type", "code" },
310-
{ "redirect_uri", redirectUri },
311-
};
306+
{
307+
{ "client_id", Options.ClientId },
308+
{ "scope", scope },
309+
{ "response_type", "code" },
310+
{ "redirect_uri", redirectUri },
311+
};
312312

313313
if (Options.UsePkce)
314314
{
@@ -328,6 +328,11 @@ protected virtual string BuildChallengeUrl(AuthenticationProperties properties,
328328

329329
parameters["state"] = Options.StateDataFormat.Protect(properties);
330330

331+
foreach (var additionalParameter in Options.AdditionalAuthorizationParameters)
332+
{
333+
parameters.Add(additionalParameter.Key, additionalParameter.Value);
334+
}
335+
331336
return QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, parameters!);
332337
}
333338

src/Security/Authentication/OAuth/src/OAuthOptions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ public override void Validate()
8383
/// </summary>
8484
public ICollection<string> Scope { get; } = new HashSet<string>();
8585

86+
/// <summary>
87+
/// Gets the additional parameters that will be included in the authorization request.
88+
/// </summary>
89+
/// <remarks>
90+
/// The additional parameters can be used to customize the authorization request,
91+
/// providing extra information or fulfilling specific requirements of the OAuth provider.
92+
/// These parameters are typically, but not always, appended to the query string.
93+
/// </remarks>
94+
public IDictionary<string, string> AdditionalAuthorizationParameters { get; } = new Dictionary<string, string>();
95+
8696
/// <summary>
8797
/// Gets or sets the type used to secure data handled by the middleware.
8898
/// </summary>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
#nullable enable
2+
Microsoft.AspNetCore.Authentication.OAuth.OAuthOptions.AdditionalAuthorizationParameters.get -> System.Collections.Generic.IDictionary<string!, string!>!

src/Security/Authentication/OpenIdConnect/src/OpenIdConnectHandler.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,11 @@ private async Task HandleChallengeAsyncInternal(AuthenticationProperties propert
450450

451451
GenerateCorrelationId(properties);
452452

453+
foreach (var additionalParameter in Options.AdditionalAuthorizationParameters)
454+
{
455+
message.Parameters.Add(additionalParameter.Key, additionalParameter.Value);
456+
}
457+
453458
var redirectContext = new RedirectContext(Context, Scheme, Options, properties)
454459
{
455460
ProtocolMessage = message

src/Security/Authentication/OpenIdConnect/src/OpenIdConnectOptions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,16 @@ public override void Validate()
236236
/// </summary>
237237
public ICollection<string> Scope { get; } = new HashSet<string>();
238238

239+
/// <summary>
240+
/// Gets the additional parameters that will be included in the authorization request.
241+
/// </summary>
242+
/// <remarks>
243+
/// The additional parameters can be used to customize the authorization request,
244+
/// providing extra information or fulfilling specific requirements of the OpenIdConnect provider.
245+
/// These parameters are typically, but not always, appended to the query string.
246+
/// </remarks>
247+
public IDictionary<string, string> AdditionalAuthorizationParameters { get; } = new Dictionary<string, string>();
248+
239249
/// <summary>
240250
/// Requests received on this path will cause the handler to invoke SignOut using the SignOutScheme.
241251
/// </summary>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
#nullable enable
2+
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions.AdditionalAuthorizationParameters.get -> System.Collections.Generic.IDictionary<string!, string!>!

src/Security/Authentication/test/OAuthTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,32 @@ public async Task RedirectToAuthorizeEndpoint_HasScopeAsConfigured()
193193
Assert.Contains("scope=foo%20bar", res.Headers.Location.Query);
194194
}
195195

196+
[Fact]
197+
public async Task RedirectToAuthorizeEndpoint_HasAdditionalAuthorizationParametersAsConfigured()
198+
{
199+
using var host = await CreateHost(
200+
s => s.AddAuthentication(o => o.DisableAutoDefaultScheme = true).AddOAuth(
201+
"Weblie",
202+
opt =>
203+
{
204+
ConfigureDefaults(opt);
205+
opt.AdditionalAuthorizationParameters.Add("prompt", "login");
206+
opt.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
207+
}),
208+
async ctx =>
209+
{
210+
await ctx.ChallengeAsync("Weblie");
211+
return true;
212+
});
213+
214+
using var server = host.GetTestServer();
215+
var transaction = await server.SendAsync("https://www.example.com/challenge");
216+
var res = transaction.Response;
217+
218+
Assert.Equal(HttpStatusCode.Redirect, res.StatusCode);
219+
Assert.Contains("prompt=login&audience=https%3A%2F%2Fapi.example.com", res.Headers.Location.Query);
220+
}
221+
196222
[Fact]
197223
public async Task RedirectToAuthorizeEndpoint_HasScopeAsOverwritten()
198224
{

src/Security/Authentication/test/OpenIdConnect/OpenIdConnectChallengeTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,4 +670,25 @@ public async Task Challenge_HasOverwrittenMaxAgeParaFromBaseAuthenticationProper
670670
settings.ValidateChallengeRedirect(res.Headers.Location);
671671
Assert.Contains("max_age=1234", res.Headers.Location.Query);
672672
}
673+
674+
[Fact]
675+
public async Task Challenge_WithAdditionalAuthorizationParameters()
676+
{
677+
var settings = new TestSettings(opt =>
678+
{
679+
opt.ClientId = "Test Id";
680+
opt.Authority = TestServerBuilder.DefaultAuthority;
681+
opt.AdditionalAuthorizationParameters.Add("prompt", "login");
682+
opt.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
683+
});
684+
685+
var server = settings.CreateTestServer();
686+
var transaction = await server.SendAsync(TestServerBuilder.TestHost + TestServerBuilder.ChallengeWithProperties);
687+
688+
var res = transaction.Response;
689+
690+
Assert.Equal(HttpStatusCode.Redirect, res.StatusCode);
691+
settings.ValidateChallengeRedirect(res.Headers.Location);
692+
Assert.Contains("prompt=login&audience=https%3A%2F%2Fapi.example.com", res.Headers.Location.Query);
693+
}
673694
}

0 commit comments

Comments
 (0)