Browse Source

Rename the device, cryptography, logout and verification endpoints and the associated events/event handlers

pull/2176/head
Kévin Chalet 1 year ago
parent
commit
d4c05e2e23
  1. 6
      gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs
  2. 2
      sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/AuthenticationController.cs
  3. 8
      sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthorizationController.cs
  4. 24
      sandbox/OpenIddict.Sandbox.AspNet.Server/Startup.cs
  5. 2
      sandbox/OpenIddict.Sandbox.AspNet.Server/Views/Authorization/EndSession.cshtml
  6. 2
      sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/AuthenticationController.cs
  7. 14
      sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthorizationController.cs
  8. 6
      sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/UserinfoController.cs
  9. 24
      sandbox/OpenIddict.Sandbox.AspNetCore.Server/Startup.cs
  10. 4
      sandbox/OpenIddict.Sandbox.AspNetCore.Server/Views/Authorization/EndSession.cshtml
  11. 14
      sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs
  12. 2
      sandbox/OpenIddict.Sandbox.Console.Client/Program.cs
  13. 2
      sandbox/OpenIddict.Sandbox.Maui.Client/MainPage.xaml.cs
  14. 2
      sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.cs
  15. 2
      sandbox/OpenIddict.Sandbox.Wpf.Client/MainWindow.xaml.cs
  16. 2
      src/OpenIddict.Abstractions/Managers/IOpenIddictApplicationManager.cs
  17. 16
      src/OpenIddict.Abstractions/OpenIddictConstants.cs
  18. 120
      src/OpenIddict.Abstractions/OpenIddictResources.resx
  19. 4
      src/OpenIddict.Abstractions/Primitives/OpenIddictConfiguration.cs
  20. 2
      src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreBuilder.cs
  21. 4
      src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreConstants.cs
  22. 10
      src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs
  23. 10
      src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.Session.cs
  24. 2
      src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreOptions.cs
  25. 2
      src/OpenIddict.Client.Owin/OpenIddictClientOwinBuilder.cs
  26. 4
      src/OpenIddict.Client.Owin/OpenIddictClientOwinConstants.cs
  27. 4
      src/OpenIddict.Client.Owin/OpenIddictClientOwinHandler.cs
  28. 10
      src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.Session.cs
  29. 2
      src/OpenIddict.Client.Owin/OpenIddictClientOwinOptions.cs
  30. 2
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationConstants.cs
  31. 38
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
  32. 16
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.cs
  33. 28
      src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.Discovery.cs
  34. 58
      src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.Userinfo.cs
  35. 2
      src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
  36. 4
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Device.cs
  37. 8
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs
  38. 72
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs
  39. 194
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
  40. 102
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml
  41. 2
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xsd
  42. 56
      src/OpenIddict.Client/OpenIddictClientBuilder.cs
  43. 2
      src/OpenIddict.Client/OpenIddictClientConfiguration.cs
  44. 40
      src/OpenIddict.Client/OpenIddictClientEvents.Discovery.cs
  45. 24
      src/OpenIddict.Client/OpenIddictClientEvents.Session.cs
  46. 28
      src/OpenIddict.Client/OpenIddictClientEvents.Userinfo.cs
  47. 24
      src/OpenIddict.Client/OpenIddictClientEvents.cs
  48. 8
      src/OpenIddict.Client/OpenIddictClientExtensions.cs
  49. 16
      src/OpenIddict.Client/OpenIddictClientHandlerFilters.cs
  50. 46
      src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs
  51. 36
      src/OpenIddict.Client/OpenIddictClientHandlers.Session.cs
  52. 26
      src/OpenIddict.Client/OpenIddictClientHandlers.Userinfo.cs
  53. 180
      src/OpenIddict.Client/OpenIddictClientHandlers.cs
  54. 34
      src/OpenIddict.Client/OpenIddictClientModels.cs
  55. 8
      src/OpenIddict.Client/OpenIddictClientOptions.cs
  56. 100
      src/OpenIddict.Client/OpenIddictClientService.cs
  57. 2
      src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
  58. 58
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreBuilder.cs
  59. 4
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreConstants.cs
  60. 6
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreExtensions.cs
  61. 8
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs
  62. 50
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlerFilters.cs
  63. 38
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Device.cs
  64. 8
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Discovery.cs
  65. 92
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs
  66. 22
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Userinfo.cs
  67. 10
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
  68. 44
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreOptions.cs
  69. 56
      src/OpenIddict.Server.Owin/OpenIddictServerOwinBuilder.cs
  70. 4
      src/OpenIddict.Server.Owin/OpenIddictServerOwinConstants.cs
  71. 6
      src/OpenIddict.Server.Owin/OpenIddictServerOwinExtensions.cs
  72. 8
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs
  73. 36
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlerFilters.cs
  74. 44
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Device.cs
  75. 12
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Discovery.cs
  76. 94
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs
  77. 26
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Userinfo.cs
  78. 10
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
  79. 40
      src/OpenIddict.Server.Owin/OpenIddictServerOwinOptions.cs
  80. 74
      src/OpenIddict.Server/OpenIddictServerBuilder.cs
  81. 36
      src/OpenIddict.Server/OpenIddictServerConfiguration.cs
  82. 20
      src/OpenIddict.Server/OpenIddictServerEndpointType.cs
  83. 72
      src/OpenIddict.Server/OpenIddictServerEvents.Device.cs
  84. 50
      src/OpenIddict.Server/OpenIddictServerEvents.Discovery.cs
  85. 34
      src/OpenIddict.Server/OpenIddictServerEvents.Session.cs
  86. 24
      src/OpenIddict.Server/OpenIddictServerEvents.Userinfo.cs
  87. 10
      src/OpenIddict.Server/OpenIddictServerExtensions.cs
  88. 78
      src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs
  89. 193
      src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs
  90. 92
      src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs
  91. 153
      src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs
  92. 100
      src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs
  93. 168
      src/OpenIddict.Server/OpenIddictServerHandlers.cs
  94. 24
      src/OpenIddict.Server/OpenIddictServerOptions.cs
  95. 2
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreConstants.cs
  96. 2
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinConstants.cs
  97. 28
      src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.Discovery.cs
  98. 2
      src/OpenIddict.Validation/OpenIddictValidationConfiguration.cs
  99. 36
      src/OpenIddict.Validation/OpenIddictValidationEvents.Discovery.cs
  100. 28
      src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs

6
gen/OpenIddict.Client.WebIntegration.Generators/OpenIddictClientWebIntegrationGenerator.cs

@ -1037,8 +1037,8 @@ public sealed partial class OpenIddictClientWebIntegrationConfiguration
TokenEndpoint = new Uri($""{{ environment.configuration.token_endpoint | string.replace '\'' '""' }}"", UriKind.Absolute),
{{~ end ~}}
{{~ if environment.configuration.userinfo_endpoint ~}}
UserinfoEndpoint = new Uri($""{{ environment.configuration.userinfo_endpoint | string.replace '\'' '""' }}"", UriKind.Absolute),
{{~ if environment.configuration.user_info_endpoint ~}}
UserInfoEndpoint = new Uri($""{{ environment.configuration.user_info_endpoint | string.replace '\'' '""' }}"", UriKind.Absolute),
{{~ end ~}}
CodeChallengeMethodsSupported =
@ -1157,7 +1157,7 @@ public sealed partial class OpenIddictClientWebIntegrationConfiguration
IntrospectionEndpoint = (string?) configuration.Attribute("IntrospectionEndpoint"),
RevocationEndpoint = (string?) configuration.Attribute("RevocationEndpoint"),
TokenEndpoint = (string?) configuration.Attribute("TokenEndpoint"),
UserinfoEndpoint = (string?) configuration.Attribute("UserinfoEndpoint"),
UserInfoEndpoint = (string?) configuration.Attribute("UserInfoEndpoint"),
CodeChallengeMethodsSupported = configuration.Elements("CodeChallengeMethod").ToList() switch
{

2
sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/AuthenticationController.cs

@ -96,7 +96,7 @@ public class AuthenticationController : Controller
context.Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
// Extract the client registration identifier and retrieve the associated server configuration.
// If the provider is known to support remote sign-out, ask OpenIddict to initiate a logout request.
// If the provider is known to support remote sign-out, ask OpenIddict to initiate a end session request.
if (identity.FindFirst(Claims.Private.RegistrationId)?.Value is string identifier &&
await _service.GetServerConfigurationByRegistrationIdAsync(identifier) is { EndSessionEndpoint: Uri })
{

8
sandbox/OpenIddict.Sandbox.AspNet.Server/Controllers/AuthorizationController.cs

@ -309,8 +309,8 @@ public class AuthorizationController : Controller
return new EmptyResult();
}
[HttpGet, Route("~/connect/logout")]
public ActionResult Logout() => View(new AuthorizeViewModel
[HttpGet, Route("~/connect/endsession")]
public ActionResult EndSession() => View(new AuthorizeViewModel
{
// Flow the request parameters so they can be received by the Accept/Reject actions.
Parameters = string.Equals(Request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase) ?
@ -322,8 +322,8 @@ public class AuthorizationController : Controller
select new KeyValuePair<string, string>(name, value)
});
[ActionName(nameof(Logout)), HttpPost, Route("~/connect/logout"), ValidateAntiForgeryToken]
public ActionResult LogoutPost()
[ActionName(nameof(EndSession)), HttpPost, Route("~/connect/endsession"), ValidateAntiForgeryToken]
public ActionResult EndSessionPost()
{
var context = HttpContext.GetOwinContext();
context.Authentication.SignOut(DefaultAuthenticationTypes.ApplicationCookie);

24
sandbox/OpenIddict.Sandbox.AspNet.Server/Startup.cs

@ -86,24 +86,22 @@ public class Startup
// Register the OpenIddict server components.
.AddServer(options =>
{
// Enable the authorization, device, introspection,
// logout, token, userinfo and verification endpoints.
// Enable the flows that will be used by the client applications.
options.SetAuthorizationEndpointUris("connect/authorize")
.SetDeviceEndpointUris("connect/device")
.SetDeviceAuthorizationEndpointUris("connect/device")
.SetEndSessionEndpointUris("connect/endsession")
.SetEndUserVerificationEndpointUris("connect/verify")
.SetIntrospectionEndpointUris("connect/introspect")
.SetLogoutEndpointUris("connect/logout")
.SetTokenEndpointUris("connect/token")
.SetUserinfoEndpointUris("connect/userinfo")
.SetVerificationEndpointUris("connect/verify");
.SetUserInfoEndpointUris("connect/userinfo");
// Note: this sample uses the code, device code, password and refresh token flows, but you
// can enable the other flows if you need to support implicit or client credentials.
// Enable the flows that will be used by the client applications.
options.AllowAuthorizationCodeFlow()
.AllowDeviceCodeFlow()
.AllowDeviceAuthorizationFlow()
.AllowPasswordFlow()
.AllowRefreshTokenFlow();
// Mark the "email", "profile", "roles" and "demo_api" scopes as supported scopes.
// Register the public scopes that will be exposed by the configuration endpoint.
options.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles, "demo_api");
// Register the signing and encryption credentials.
@ -116,7 +114,7 @@ public class Startup
// Register the OWIN host and configure the OWIN-specific options.
options.UseOwin()
.EnableAuthorizationEndpointPassthrough()
.EnableLogoutEndpointPassthrough()
.EnableEndSessionEndpointPassthrough()
.EnableTokenEndpointPassthrough();
})
@ -221,7 +219,7 @@ public class Startup
Permissions =
{
Permissions.Endpoints.Authorization,
Permissions.Endpoints.Logout,
Permissions.Endpoints.EndSession,
Permissions.Endpoints.Token,
Permissions.GrantTypes.AuthorizationCode,
Permissions.GrantTypes.RefreshToken,
@ -254,7 +252,7 @@ public class Startup
Permissions =
{
Permissions.Endpoints.Authorization,
Permissions.Endpoints.Device,
Permissions.Endpoints.DeviceAuthorization,
Permissions.Endpoints.Token,
Permissions.GrantTypes.AuthorizationCode,
Permissions.GrantTypes.DeviceCode,

2
sandbox/OpenIddict.Sandbox.AspNet.Server/Views/Authorization/Logout.cshtml → sandbox/OpenIddict.Sandbox.AspNet.Server/Views/Authorization/EndSession.cshtml

@ -8,7 +8,7 @@
{
@Html.AntiForgeryToken()
@* Flow the request parameters so they can be received by the LogoutPost action: *@
@* Flow the request parameters so they can be received by the EndSessionPost action: *@
foreach (var parameter in Model.Parameters)
{
<input type="hidden" name="@parameter.Key" value="@parameter.Value" />

2
sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/AuthenticationController.cs

@ -92,7 +92,7 @@ public class AuthenticationController : Controller
await HttpContext.SignOutAsync();
// Extract the client registration identifier and retrieve the associated server configuration.
// If the provider is known to support remote sign-out, ask OpenIddict to initiate a logout request.
// If the provider is known to support remote sign-out, ask OpenIddict to initiate a end session request.
if (identity.FindFirst(Claims.Private.RegistrationId)?.Value is string identifier &&
await _service.GetServerConfigurationByRegistrationIdAsync(identifier) is { EndSessionEndpoint: Uri })
{

14
sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/AuthorizationController.cs

@ -312,7 +312,7 @@ public class AuthorizationController : Controller
#endregion
#region Device flow
// Note: to support the device flow, you must provide your own verification endpoint action:
// Note: to support the device authorization flow, you must provide your own verification endpoint action:
[Authorize, HttpGet("~/connect/verify"), IgnoreAntiforgeryToken]
public async Task<IActionResult> Verify()
{
@ -411,15 +411,15 @@ public class AuthorizationController : Controller
});
#endregion
#region Logout support for interactive flows like code and implicit
// Note: the logout action is only useful when implementing interactive
#region End session support for interactive flows like code and implicit
// Note: the end session action is only useful when implementing interactive
// flows like the authorization code flow or the implicit flow.
[HttpGet("~/connect/logout")]
public IActionResult Logout() => View();
[HttpGet("~/connect/endsession")]
public IActionResult EndSession() => View();
[ActionName(nameof(Logout)), HttpPost("~/connect/logout"), ValidateAntiForgeryToken]
public async Task<IActionResult> LogoutPost()
[ActionName(nameof(EndSession)), HttpPost("~/connect/endsession"), ValidateAntiForgeryToken]
public async Task<IActionResult> EndSessionPost()
{
// Ask ASP.NET Core Identity to delete the local and external cookies created
// when the user agent is redirected from the external identity provider

6
sandbox/OpenIddict.Sandbox.AspNetCore.Server/Controllers/UserinfoController.cs

@ -9,17 +9,17 @@ using static OpenIddict.Abstractions.OpenIddictConstants;
namespace OpenIddict.Sandbox.AspNetCore.Server.Controllers;
public class UserinfoController : Controller
public class UserInfoController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
public UserinfoController(UserManager<ApplicationUser> userManager)
public UserInfoController(UserManager<ApplicationUser> userManager)
=> _userManager = userManager;
[Authorize(AuthenticationSchemes = OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)]
[HttpGet("~/connect/userinfo"), HttpPost("~/connect/userinfo")]
[IgnoreAntiforgeryToken, Produces("application/json")]
public async Task<IActionResult> Userinfo()
public async Task<IActionResult> UserInfo()
{
var user = await _userManager.FindByIdAsync(User.GetClaim(Claims.Subject));
if (user is null)

24
sandbox/OpenIddict.Sandbox.AspNetCore.Server/Startup.cs

@ -100,28 +100,26 @@ public class Startup
// Register the OpenIddict server components.
.AddServer(options =>
{
// Enable the authorization, device, introspection, logout,
// token, revocation, userinfo and verification endpoints.
// Enable the endpoints that will be used by the client applications.
options.SetAuthorizationEndpointUris("connect/authorize")
.SetDeviceEndpointUris("connect/device")
.SetDeviceAuthorizationEndpointUris("connect/device")
.SetEndSessionEndpointUris("connect/endsession")
.SetEndUserVerificationEndpointUris("connect/verify")
.SetIntrospectionEndpointUris("connect/introspect")
.SetLogoutEndpointUris("connect/logout")
.SetRevocationEndpointUris("connect/revoke")
.SetTokenEndpointUris("connect/token")
.SetUserinfoEndpointUris("connect/userinfo")
.SetVerificationEndpointUris("connect/verify");
.SetUserInfoEndpointUris("connect/userinfo");
// Note: this sample enables all the supported flows but
// you can restrict the list of enabled flows if necessary.
// Enable the flows that will be used by the client applications.
options.AllowAuthorizationCodeFlow()
.AllowDeviceCodeFlow()
.AllowDeviceAuthorizationFlow()
.AllowHybridFlow()
.AllowImplicitFlow()
.AllowNoneFlow()
.AllowPasswordFlow()
.AllowRefreshTokenFlow();
// Mark the "email", "profile", "roles" and "demo_api" scopes as supported scopes.
// Register the public scopes that will be exposed by the configuration endpoint.
options.RegisterScopes(Scopes.Email, Scopes.Profile, Scopes.Roles, "demo_api");
// Register the signing and encryption credentials.
@ -135,10 +133,10 @@ public class Startup
options.UseAspNetCore()
.EnableStatusCodePagesIntegration()
.EnableAuthorizationEndpointPassthrough()
.EnableLogoutEndpointPassthrough()
.EnableEndSessionEndpointPassthrough()
.EnableEndUserVerificationEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableUserinfoEndpointPassthrough()
.EnableVerificationEndpointPassthrough();
.EnableUserInfoEndpointPassthrough();
// Note: if you don't want to specify a client_id when sending
// a token or revocation request, uncomment the following line:

4
sandbox/OpenIddict.Sandbox.AspNetCore.Server/Views/Authorization/Logout.cshtml → sandbox/OpenIddict.Sandbox.AspNetCore.Server/Views/Authorization/EndSession.cshtml

@ -4,8 +4,8 @@
<h1>Log out</h1>
<p class="lead text-left">Are you sure you want to sign out?</p>
<form asp-controller="Authorization" asp-action="Logout" method="post">
@* Flow the request parameters so they can be received by the LogoutPost action: *@
<form asp-controller="Authorization" asp-action="EndSession" method="post">
@* Flow the request parameters so they can be received by the EndSessionPost action: *@
@foreach (var parameter in Context.Request.HasFormContentType ?
(IEnumerable<KeyValuePair<string, StringValues>>) Context.Request.Form : Context.Request.Query)
{

14
sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs

@ -74,9 +74,9 @@ public class Worker : IHostedService
Permissions =
{
Permissions.Endpoints.Authorization,
Permissions.Endpoints.Device,
Permissions.Endpoints.DeviceAuthorization,
Permissions.Endpoints.Introspection,
Permissions.Endpoints.Logout,
Permissions.Endpoints.EndSession,
Permissions.Endpoints.Revocation,
Permissions.Endpoints.Token,
Permissions.GrantTypes.AuthorizationCode,
@ -127,7 +127,7 @@ public class Worker : IHostedService
Permissions =
{
Permissions.Endpoints.Authorization,
Permissions.Endpoints.Logout,
Permissions.Endpoints.EndSession,
Permissions.Endpoints.Token,
Permissions.GrantTypes.AuthorizationCode,
Permissions.GrantTypes.RefreshToken,
@ -188,7 +188,7 @@ public class Worker : IHostedService
Permissions =
{
Permissions.Endpoints.Authorization,
Permissions.Endpoints.Logout,
Permissions.Endpoints.EndSession,
Permissions.Endpoints.Token,
Permissions.GrantTypes.AuthorizationCode,
Permissions.GrantTypes.RefreshToken,
@ -229,7 +229,7 @@ public class Worker : IHostedService
Permissions =
{
Permissions.Endpoints.Authorization,
Permissions.Endpoints.Logout,
Permissions.Endpoints.EndSession,
Permissions.Endpoints.Token,
Permissions.GrantTypes.AuthorizationCode,
Permissions.GrantTypes.RefreshToken,
@ -270,7 +270,7 @@ public class Worker : IHostedService
Permissions =
{
Permissions.Endpoints.Authorization,
Permissions.Endpoints.Logout,
Permissions.Endpoints.EndSession,
Permissions.Endpoints.Token,
Permissions.GrantTypes.AuthorizationCode,
Permissions.GrantTypes.RefreshToken,
@ -329,7 +329,7 @@ public class Worker : IHostedService
Permissions =
{
Permissions.Endpoints.Authorization,
Permissions.Endpoints.Device,
Permissions.Endpoints.DeviceAuthorization,
Permissions.Endpoints.Token,
Permissions.GrantTypes.AuthorizationCode,
Permissions.GrantTypes.DeviceCode,

2
sandbox/OpenIddict.Sandbox.Console.Client/Program.cs

@ -40,7 +40,7 @@ var host = new HostBuilder()
// you can restrict the list of enabled flows if necessary.
options.AllowAuthorizationCodeFlow()
.AllowClientCredentialsFlow()
.AllowDeviceCodeFlow()
.AllowDeviceAuthorizationFlow()
.AllowHybridFlow()
.AllowImplicitFlow()
.AllowNoneFlow()

2
sandbox/OpenIddict.Sandbox.Maui.Client/MainPage.xaml.cs

@ -108,7 +108,7 @@ public partial class MainPage : ContentPage
// Ask OpenIddict to initiate the logout flow (typically, by starting the system browser).
var result = await _service.SignOutInteractivelyAsync(new()
{
AdditionalLogoutRequestParameters = parameters,
AdditionalEndSessionRequestParameters = parameters,
CancellationToken = source.Token,
ProviderName = provider
});

2
sandbox/OpenIddict.Sandbox.WinForms.Client/MainForm.cs

@ -152,7 +152,7 @@ public partial class MainForm : Form, IWinFormsShell
// Ask OpenIddict to initiate the logout flow (typically, by starting the system browser).
var result = await _service.SignOutInteractivelyAsync(new()
{
AdditionalLogoutRequestParameters = parameters,
AdditionalEndSessionRequestParameters = parameters,
CancellationToken = source.Token,
ProviderName = provider
});

2
sandbox/OpenIddict.Sandbox.Wpf.Client/MainWindow.xaml.cs

@ -113,7 +113,7 @@ public partial class MainWindow : Window, IWpfShell
// Ask OpenIddict to initiate the logout flow (typically, by starting the system browser).
var result = await _service.SignOutInteractivelyAsync(new()
{
AdditionalLogoutRequestParameters = parameters,
AdditionalEndSessionRequestParameters = parameters,
CancellationToken = source.Token,
ProviderName = provider
});

2
src/OpenIddict.Abstractions/Managers/IOpenIddictApplicationManager.cs

@ -502,7 +502,7 @@ public interface IOpenIddictApplicationManager
/// <param name="application">The application.</param>
/// <param name="uri">The URI that should be compared to one of the post_logout_redirect_uri stored in the database.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <remarks>Note: if no client_id parameter is specified in logout requests, this method may not be called.</remarks>
/// <remarks>Note: if no client_id parameter is specified in end session requests, this method may not be called.</remarks>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns a boolean indicating whether the post_logout_redirect_uri was valid.

16
src/OpenIddict.Abstractions/OpenIddictConstants.cs

@ -160,7 +160,7 @@ public static class OpenIddictConstants
{
public const string Essential = "essential";
public const string IdToken = "id_token";
public const string Userinfo = "userinfo";
public const string UserInfo = "userinfo";
public const string Value = "value";
public const string Values = "values";
}
@ -310,10 +310,10 @@ public static class OpenIddictConstants
public const string TokenEndpointAuthMethodsSupported = "token_endpoint_auth_methods_supported";
public const string TokenEndpointAuthSigningAlgValuesSupported = "token_endpoint_auth_signing_alg_values_supported";
public const string UiLocalesSupported = "ui_locales_supported";
public const string UserinfoEncryptionAlgValuesSupported = "userinfo_encryption_alg_values_supported";
public const string UserinfoEncryptionEncValuesSupported = "userinfo_encryption_enc_values_supported";
public const string UserinfoEndpoint = "userinfo_endpoint";
public const string UserinfoSigningAlgValuesSupported = "userinfo_signing_alg_values_supported";
public const string UserInfoEncryptionAlgValuesSupported = "userinfo_encryption_alg_values_supported";
public const string UserInfoEncryptionEncValuesSupported = "userinfo_encryption_enc_values_supported";
public const string UserInfoEndpoint = "userinfo_endpoint";
public const string UserInfoSigningAlgValuesSupported = "userinfo_signing_alg_values_supported";
}
public static class Parameters
@ -379,9 +379,9 @@ public static class OpenIddictConstants
public static class Endpoints
{
public const string Authorization = "ept:authorization";
public const string Device = "ept:device";
public const string DeviceAuthorization = "ept:device_authorization";
public const string EndSession = "ept:end_session";
public const string Introspection = "ept:introspection";
public const string Logout = "ept:logout";
public const string Revocation = "ept:revocation";
public const string Token = "ept:token";
}
@ -552,7 +552,7 @@ public static class OpenIddictConstants
public const string IdToken = "id_token";
public const string RefreshToken = "refresh_token";
public const string StateToken = "state_token";
public const string UserinfoToken = "userinfo_token";
public const string UserInfoToken = "userinfo_token";
public const string UserCode = "user_code";
}

120
src/OpenIddict.Abstractions/OpenIddictResources.resx

@ -219,39 +219,39 @@ To apply authorization responses, create a class implementing 'IOpenIddictServer
</data>
<data name="ID0031" xml:space="preserve">
<value>The device request was not correctly extracted.
To extract device requests, create a class implementing 'IOpenIddictServerHandler&lt;ExtractDeviceRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
To extract device requests, create a class implementing 'IOpenIddictServerHandler&lt;ExtractDeviceAuthorizationRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0032" xml:space="preserve">
<value>The client application details cannot be found in the database.</value>
</data>
<data name="ID0033" xml:space="preserve">
<value>The device response was not correctly applied.
To apply device responses, create a class implementing 'IOpenIddictServerHandler&lt;ApplyDeviceResponseContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
<value>The device authorization response was not correctly applied.
To apply device authorization responses, create a class implementing 'IOpenIddictServerHandler&lt;ApplyDeviceAuthorizationResponseContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0034" xml:space="preserve">
<value>The verification request was not correctly extracted.
To extract verification requests, create a class implementing 'IOpenIddictServerHandler&lt;ExtractVerificationRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
<value>The end-user verification request was not correctly extracted.
To extract end-user verification requests, create a class implementing 'IOpenIddictServerHandler&lt;ExtractEndUserVerificationRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0035" xml:space="preserve">
<value>The verification request was not handled.
To handle verification requests in a controller, create a custom action with the same route as the verification endpoint and enable the pass-through mode in the server ASP.NET Core or OWIN options using 'services.AddOpenIddict().AddServer().UseAspNetCore().EnableVerificationEndpointPassthrough()'.
Alternatively, create a class implementing 'IOpenIddictServerHandler&lt;HandleVerificationRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
<value>The end-user verification request was not handled.
To handle end-user verification requests in a controller, create a custom action with the same route as the end-user verification endpoint and enable the pass-through mode in the server ASP.NET Core or OWIN options using 'services.AddOpenIddict().AddServer().UseAspNetCore().EnableVerificationEndpointPassthrough()'.
Alternatively, create a class implementing 'IOpenIddictServerHandler&lt;HandleEndUserVerificationRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0036" xml:space="preserve">
<value>The verification response was not correctly applied.
To apply verification responses, create a class implementing 'IOpenIddictServerHandler&lt;ApplyVerificationResponseContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
<value>The end-user verification response was not correctly applied.
To apply end-user verification responses, create a class implementing 'IOpenIddictServerHandler&lt;ApplyEndUserVerificationResponseContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0037" xml:space="preserve">
<value>The configuration request was not correctly extracted.
To extract configuration requests, create a class implementing 'IOpenIddictServerHandler&lt;ExtractConfigurationRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0038" xml:space="preserve">
<value>The cryptography request was not correctly extracted.
To extract configuration requests, create a class implementing 'IOpenIddictServerHandler&lt;ExtractCryptographyRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
<value>The JSON Web Key Set request was not correctly extracted.
To extract configuration requests, create a class implementing 'IOpenIddictServerHandler&lt;ExtractJsonWebKeySetRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0039" xml:space="preserve">
<value>The cryptography response was not correctly applied.
To apply cryptography responses, create a class implementing 'IOpenIddictServerHandler&lt;ApplyCryptographyResponseContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
<value>The JSON Web Key Set response was not correctly applied.
To apply JSON Web Key Set responses, create a class implementing 'IOpenIddictServerHandler&lt;ApplyJsonWebKeySetResponseContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0040" xml:space="preserve">
<value>The token request was not correctly extracted.
@ -292,25 +292,25 @@ To extract revocation requests, create a class implementing 'IOpenIddictServerHa
To apply revocation responses, create a class implementing 'IOpenIddictServerHandler&lt;ApplyRevocationResponseContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0050" xml:space="preserve">
<value>The logout request was not correctly extracted.
To extract logout requests, create a class implementing 'IOpenIddictServerHandler&lt;ExtractLogoutRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
<value>The end session request was not correctly extracted.
To extract end session requests, create a class implementing 'IOpenIddictServerHandler&lt;ExtractEndSessionRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0051" xml:space="preserve">
<value>The logout request was not handled.
To handle logout requests in a controller, create a custom controller action with the same route as the logout endpoint and enable the pass-through mode in the server ASP.NET Core or OWIN options using 'services.AddOpenIddict().AddServer().UseAspNetCore().EnableLogoutEndpointPassthrough()'.
Alternatively, create a class implementing 'IOpenIddictServerHandler&lt;HandleLogoutRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
<value>The end session request was not handled.
To handle end session requests in a controller, create a custom controller action with the same route as the end session endpoint and enable the pass-through mode in the server ASP.NET Core or OWIN options using 'services.AddOpenIddict().AddServer().UseAspNetCore().EnableLogoutEndpointPassthrough()'.
Alternatively, create a class implementing 'IOpenIddictServerHandler&lt;HandleEndSessionRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0052" xml:space="preserve">
<value>The logout response was not correctly applied.
To apply logout responses, create a class implementing 'IOpenIddictServerHandler&lt;ApplyLogoutResponseContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
<value>The end session response was not correctly applied.
To apply end session responses, create a class implementing 'IOpenIddictServerHandler&lt;ApplyEndSessionResponseContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0053" xml:space="preserve">
<value>The userinfo request was not correctly extracted.
To extract userinfo requests, create a class implementing 'IOpenIddictServerHandler&lt;ExtractUserinfoRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
To extract userinfo requests, create a class implementing 'IOpenIddictServerHandler&lt;ExtractUserInfoRequestContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0054" xml:space="preserve">
<value>The userinfo response was not correctly applied.
To apply userinfo responses, create a class implementing 'IOpenIddictServerHandler&lt;ApplyUserinfoResponseContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
To apply userinfo responses, create a class implementing 'IOpenIddictServerHandler&lt;ApplyUserInfoResponseContext&gt;' and register it using 'services.AddOpenIddict().AddServer().AddEventHandler()'.</value>
</data>
<data name="ID0055" xml:space="preserve">
<value>The asymmetric encryption key doesn't contain the required private key.</value>
@ -381,13 +381,13 @@ Consider using 'options.AddSigningCredentials(SigningCredentials)' instead.</val
<value>The authorization endpoint must be enabled to use the authorization code and implicit flows.</value>
</data>
<data name="ID0078" xml:space="preserve">
<value>The device endpoint must be enabled to use the device flow.</value>
<value>The device authorization endpoint must be enabled to use the device authorization flow.</value>
</data>
<data name="ID0079" xml:space="preserve">
<value>The token endpoint must be enabled to use the authorization code, client credentials, device, password and refresh token flows.</value>
</data>
<data name="ID0080" xml:space="preserve">
<value>The verification endpoint must be enabled to use the device flow.</value>
<value>The end-user verification endpoint must be enabled to use the device authorization flow.</value>
</data>
<data name="ID0081" xml:space="preserve">
<value>Endpoint URIs cannot start with '{0}'.</value>
@ -400,7 +400,7 @@ To enable DI support, call 'services.AddQuartz(options =&gt; options.UseMicrosof
<value>Reference tokens cannot be used when disabling token storage.</value>
</data>
<data name="ID0084" xml:space="preserve">
<value>The device grant must be allowed when enabling the device endpoint.</value>
<value>The device grant must be allowed when enabling the device authorization endpoint.</value>
</data>
<data name="ID0085" xml:space="preserve">
<value>At least one encryption key must be registered in the OpenIddict server options.
@ -422,13 +422,13 @@ To use key rollover, register both the new certificate and the old one in the cr
<value>No custom authorization request validation handler was found. When enabling the degraded mode, a custom 'IOpenIddictServerHandler&lt;ValidateAuthorizationRequestContext&gt;' must be implemented to validate authorization requests (e.g to ensure the client_id and redirect_uri are valid).</value>
</data>
<data name="ID0090" xml:space="preserve">
<value>No custom device request validation handler was found. When enabling the degraded mode, a custom 'IOpenIddictServerHandler&lt;ValidateDeviceRequestContext&gt;' (or 'IOpenIddictServerHandler&lt;ProcessAuthenticationContext&gt;') must be implemented to validate device requests (e.g to ensure the client_id and client_secret are valid).</value>
<value>No custom device request validation handler was found. When enabling the degraded mode, a custom 'IOpenIddictServerHandler&lt;ValidateDeviceAuthorizationRequestContext&gt;' (or 'IOpenIddictServerHandler&lt;ProcessAuthenticationContext&gt;') must be implemented to validate device requests (e.g to ensure the client_id and client_secret are valid).</value>
</data>
<data name="ID0091" xml:space="preserve">
<value>No custom introspection request validation handler was found. When enabling the degraded mode, a custom 'IOpenIddictServerHandler&lt;ValidateIntrospectionRequestContext&gt;' (or 'IOpenIddictServerHandler&lt;ProcessAuthenticationContext&gt;') must be implemented to validate introspection requests (e.g to ensure the client_id and client_secret are valid).</value>
</data>
<data name="ID0092" xml:space="preserve">
<value>No custom logout request validation handler was found. When enabling the degraded mode, a custom 'IOpenIddictServerHandler&lt;ValidateLogoutRequestContext&gt;' must be implemented to validate logout requests (e.g to ensure the post_logout_redirect_uri is valid).</value>
<value>No custom end session request validation handler was found. When enabling the degraded mode, a custom 'IOpenIddictServerHandler&lt;ValidateEndSessionRequestContext&gt;' must be implemented to validate end session requests (e.g to ensure the post_logout_redirect_uri is valid).</value>
</data>
<data name="ID0093" xml:space="preserve">
<value>No custom revocation request validation handler was found. When enabling the degraded mode, a custom 'IOpenIddictServerHandler&lt;ValidateRevocationRequestContext&gt;' (or 'IOpenIddictServerHandler&lt;ProcessAuthenticationContext&gt;') must be implemented to validate revocation requests (e.g to ensure the client_id and client_secret are valid).</value>
@ -437,7 +437,7 @@ To use key rollover, register both the new certificate and the old one in the cr
<value>No custom token request validation handler was found. When enabling the degraded mode, a custom 'IOpenIddictServerHandler&lt;ValidateTokenRequestContext&gt;' (or 'IOpenIddictServerHandler&lt;ProcessAuthenticationContext&gt;') must be implemented to validate token requests (e.g to ensure the client_id and client_secret are valid).</value>
</data>
<data name="ID0095" xml:space="preserve">
<value>No custom verification request validation handler was found. When enabling the degraded mode, a custom 'IOpenIddictServerHandler&lt;ValidateVerificationRequestContext&gt;' must be implemented to validate verification requests (e.g to ensure the user_code is valid).</value>
<value>No custom end-user verification request validation handler was found. When enabling the degraded mode, a custom 'IOpenIddictServerHandler&lt;ValidateEndUserVerificationRequestContext&gt;' must be implemented to validate verification requests (e.g to ensure the user_code is valid).</value>
</data>
<data name="ID0096" xml:space="preserve">
<value>No custom token validation handler was found. When enabling the degraded mode, a custom 'IOpenIddictServerHandler&lt;ValidateTokenContext&gt;' must be implemented to handle device and user codes (e.g by retrieving them from a database).</value>
@ -512,7 +512,7 @@ To register the default in-memory distributed cache implementation, reference th
<value>The authorization request payload is malformed.</value>
</data>
<data name="ID0118" xml:space="preserve">
<value>The logout request payload is malformed.</value>
<value>The end session request payload is malformed.</value>
</data>
<data name="ID0119" xml:space="preserve">
<value>The OpenIddict OWIN server handler cannot be used as an active authentication handler.
@ -608,7 +608,7 @@ To register the OpenIddict core services, reference the 'OpenIddict.Core' packag
<value>The server configuration couldn't be retrieved.</value>
</data>
<data name="ID0146" xml:space="preserve">
<value>The JWKS URI couldn't be resolved from the provider metadata.</value>
<value>The JSON Web Key Set URI couldn't be resolved from the provider metadata.</value>
</data>
<data name="ID0147" xml:space="preserve">
<value>The server JSON Web Key set couldn't be retrieved.</value>
@ -638,25 +638,25 @@ To register the OpenIddict core services, reference the 'OpenIddict.Core' packag
Error URI: {2}</value>
</data>
<data name="ID0152" xml:space="preserve">
<value>An error occurred while preparing the cryptography request.
<value>An error occurred while preparing the JSON Web Key Set request.
Error: {0}
Error description: {1}
Error URI: {2}</value>
</data>
<data name="ID0153" xml:space="preserve">
<value>An error occurred while sending the cryptography request.
<value>An error occurred while sending the JSON Web Key Set request.
Error: {0}
Error description: {1}
Error URI: {2}</value>
</data>
<data name="ID0154" xml:space="preserve">
<value>An error occurred while extracting the cryptography response.
<value>An error occurred while extracting the JSON Web Key Set response.
Error: {0}
Error description: {1}
Error URI: {2}</value>
</data>
<data name="ID0155" xml:space="preserve">
<value>An error occurred while handling the cryptography response.
<value>An error occurred while handling the JSON Web Key Set response.
Error: {0}
Error description: {1}
Error URI: {2}</value>
@ -1777,7 +1777,7 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
<value>The specified user code is no longer valid.</value>
</data>
<data name="ID2027" xml:space="preserve">
<value>The client application is not allowed to use the device code flow.</value>
<value>The client application is not allowed to use the device authorization flow.</value>
</data>
<data name="ID2028" xml:space="preserve">
<value>The '{0}' parameter is not supported.</value>
@ -1864,7 +1864,7 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
<value>The specified client credentials are invalid.</value>
</data>
<data name="ID2056" xml:space="preserve">
<value>This client application is not allowed to use the device endpoint.</value>
<value>This client application is not allowed to use the device authorization endpoint.</value>
</data>
<data name="ID2057" xml:space="preserve">
<value>The '{0}' or '{1}' parameter must be specified when using the client credentials grant.</value>
@ -1993,19 +1993,19 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
<value>The issuer returned in the server configuration doesn't match the value set in the validation options.</value>
</data>
<data name="ID2099" xml:space="preserve">
<value>No JWKS endpoint could be found in the server configuration.</value>
<value>No JSON Web Key Set endpoint could be found in the server configuration.</value>
</data>
<data name="ID2100" xml:space="preserve">
<value>A server configuration containing an invalid '{0}' URI was returned.</value>
</data>
<data name="ID2102" xml:space="preserve">
<value>The JWKS document didn't contain a valid '{0}' node with at least one key.</value>
<value>The JSON Web Key Set document didn't contain a valid '{0}' node with at least one key.</value>
</data>
<data name="ID2103" xml:space="preserve">
<value>A JWKS response containing an unsupported key was returned.</value>
<value>A JSON Web Key Set response containing an unsupported key was returned.</value>
</data>
<data name="ID2104" xml:space="preserve">
<value>A JWKS response containing an invalid key was returned.</value>
<value>A JSON Web Key Set response containing an invalid key was returned.</value>
</data>
<data name="ID2105" xml:space="preserve">
<value>The mandatory '{0}' parameter couldn't be found in the introspection response.</value>
@ -2113,7 +2113,7 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
<value>The specified state token has already been redeemed.</value>
</data>
<data name="ID2140" xml:space="preserve">
<value>This client application is not allowed to use the logout endpoint.</value>
<value>This client application is not allowed to use the end session endpoint.</value>
</data>
<data name="ID2141" xml:space="preserve">
<value>The client application is not allowed to use the specified identity token hint.</value>
@ -2128,7 +2128,7 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
<value>The configuration request was rejected by the remote server.</value>
</data>
<data name="ID2145" xml:space="preserve">
<value>The cryptography request was rejected by the remote server.</value>
<value>The JSON Web Key Set request was rejected by the remote server.</value>
</data>
<data name="ID2146" xml:space="preserve">
<value>The introspection request was rejected by the remote server.</value>
@ -2418,7 +2418,7 @@ The principal used to create the token contained the following claims: {Claims}.
<value>The device request was rejected because invalid scopes were specified: {Scopes}.</value>
</data>
<data name="ID6062" xml:space="preserve">
<value>The device request was rejected because the application '{ClientId}' was not allowed to use the device endpoint.</value>
<value>The device request was rejected because the application '{ClientId}' was not allowed to use the device authorization endpoint.</value>
</data>
<data name="ID6063" xml:space="preserve">
<value>The device request was rejected because the application '{ClientId}' was not allowed to use the scope {Scope}.</value>
@ -2436,19 +2436,19 @@ The principal used to create the token contained the following claims: {Claims}.
<value>The configuration request was successfully validated.</value>
</data>
<data name="ID6068" xml:space="preserve">
<value>The cryptography request was successfully extracted: {Request}.</value>
<value>The JSON Web Key Set request was successfully extracted: {Request}.</value>
</data>
<data name="ID6069" xml:space="preserve">
<value>The cryptography request was successfully validated.</value>
<value>The JSON Web Key Set request was successfully validated.</value>
</data>
<data name="ID6070" xml:space="preserve">
<value>A JSON Web Key was excluded from the key set because it didn't contain the mandatory '{Parameter}' parameter.</value>
</data>
<data name="ID6071" xml:space="preserve">
<value>An unsupported signing key of type '{Type}' was ignored and excluded from the key set. Only RSA and ECDSA asymmetric security keys can be exposed via the JWKS endpoint.</value>
<value>An unsupported signing key of type '{Type}' was ignored and excluded from the key set. Only RSA and ECDSA asymmetric security keys can be exposed via the JSON Web Key Set endpoint.</value>
</data>
<data name="ID6072" xml:space="preserve">
<value>An unsupported signing key of type '{Type}' was ignored and excluded from the key set. Only RSA asymmetric security keys can be exposed via the JWKS endpoint.</value>
<value>An unsupported signing key of type '{Type}' was ignored and excluded from the key set. Only RSA asymmetric security keys can be exposed via the JSON Web Key Set endpoint.</value>
</data>
<data name="ID6073" xml:space="preserve">
<value>A signing key of type '{Type}' was ignored because its RSA public parameters couldn't be extracted.</value>
@ -2547,7 +2547,7 @@ The principal used to create the token contained the following claims: {Claims}.
<value>The revocation request was rejected because the received token was of an unsupported type.</value>
</data>
<data name="ID6118" xml:space="preserve">
<value>The device request was rejected because the application '{ClientId}' was not allowed to use the device code flow.</value>
<value>The device request was rejected because the application '{ClientId}' was not allowed to use the device authorization flow.</value>
</data>
<data name="ID6119" xml:space="preserve">
<value>The revocation request was rejected because the access token was issued to a different client or for another resource server.</value>
@ -2565,19 +2565,19 @@ The principal used to create the token contained the following claims: {Claims}.
<value>The token '{Identifier}' was not revoked because it couldn't be found.</value>
</data>
<data name="ID6124" xml:space="preserve">
<value>The logout request was successfully extracted: {Request}.</value>
<value>The end session request was successfully extracted: {Request}.</value>
</data>
<data name="ID6125" xml:space="preserve">
<value>The logout request was successfully validated.</value>
<value>The end session request was successfully validated.</value>
</data>
<data name="ID6126" xml:space="preserve">
<value>The logout request was rejected because the '{Parameter}' parameter wasn't a valid absolute URI: {PostLogoutRedirectUri}.</value>
<value>The end session request was rejected because the '{Parameter}' parameter wasn't a valid absolute URI: {PostLogoutRedirectUri}.</value>
</data>
<data name="ID6127" xml:space="preserve">
<value>The logout request was rejected because the '{Parameter}' contained a URI fragment: {PostLogoutRedirectUri}.</value>
<value>The end session request was rejected because the '{Parameter}' contained a URI fragment: {PostLogoutRedirectUri}.</value>
</data>
<data name="ID6128" xml:space="preserve">
<value>The logout request was rejected because the specified post_logout_redirect_uri was invalid: {PostLogoutRedirectUri}.</value>
<value>The end session request was rejected because the specified post_logout_redirect_uri was invalid: {PostLogoutRedirectUri}.</value>
</data>
<data name="ID6129" xml:space="preserve">
<value>The userinfo request was successfully extracted: {Request}.</value>
@ -2643,10 +2643,10 @@ The principal used to create the token contained the following claims: {Claims}.
<value>The authorization response was successfully returned to '{RedirectUri}' using the fragment response mode: {Response}.</value>
</data>
<data name="ID6150" xml:space="preserve">
<value>The logout request was rejected because an unknown or invalid '{Parameter}' was specified.</value>
<value>The end session request was rejected because an unknown or invalid '{Parameter}' was specified.</value>
</data>
<data name="ID6151" xml:space="preserve">
<value>The logout response was successfully returned to '{PostLogoutRedirectUri}': {Response}.</value>
<value>The end session response was successfully returned to '{PostLogoutRedirectUri}': {Response}.</value>
</data>
<data name="ID6152" xml:space="preserve">
<value>The ASP.NET Core Data Protection token '{Token}' was successfully validated and the following claims could be extracted: {Claims}.</value>
@ -2755,10 +2755,10 @@ This may indicate that the hashed entry is corrupted or malformed.</value>
<value>The configuration response returned by {Uri} was successfully extracted: {Response}.</value>
</data>
<data name="ID6188" xml:space="preserve">
<value>The cryptography request was successfully sent to {Uri}: {Request}.</value>
<value>The JSON Web Key Set request was successfully sent to {Uri}: {Request}.</value>
</data>
<data name="ID6189" xml:space="preserve">
<value>The cryptography response returned by {Uri} was successfully extracted: {Response}.</value>
<value>The JSON Web Key Set response returned by {Uri} was successfully extracted: {Response}.</value>
</data>
<data name="ID6190" xml:space="preserve">
<value>The introspection request was successfully sent to {Uri}: {Request}.</value>
@ -2782,7 +2782,7 @@ This may indicate that the hashed entry is corrupted or malformed.</value>
<value>The authorization request was rejected because the identity token used as a hint was issued to a different client.</value>
</data>
<data name="ID6198" xml:space="preserve">
<value>The logout request was rejected because the identity token used as a hint was issued to a different client.</value>
<value>The end session request was rejected because the identity token used as a hint was issued to a different client.</value>
</data>
<data name="ID6199" xml:space="preserve">
<value>The post-logout redirection request was successfully extracted: {Request}.</value>
@ -2797,7 +2797,7 @@ This may indicate that the hashed entry is corrupted or malformed.</value>
<value>The configuration request was rejected by the remote authorization server: {Response}.</value>
</data>
<data name="ID6204" xml:space="preserve">
<value>The cryptography request was rejected by the remote authorization server: {Response}.</value>
<value>The JSON Web Key Set request was rejected by the remote authorization server: {Response}.</value>
</data>
<data name="ID6205" xml:space="preserve">
<value>The introspection request was rejected by the remote authorization server: {Response}.</value>

4
src/OpenIddict.Abstractions/Primitives/OpenIddictConfiguration.cs

@ -72,7 +72,7 @@ public sealed class OpenIddictConfiguration
public JsonWebKeySet? JsonWebKeySet { get; set; }
/// <summary>
/// Gets or sets the URI of the JWKS endpoint.
/// Gets or sets the URI of the JSON Web Key Set endpoint.
/// </summary>
public Uri? JwksUri { get; set; }
@ -124,5 +124,5 @@ public sealed class OpenIddictConfiguration
/// <summary>
/// Gets or sets the URI of the userinfo endpoint.
/// </summary>
public Uri? UserinfoEndpoint { get; set; }
public Uri? UserInfoEndpoint { get; set; }
}

2
src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreBuilder.cs

@ -112,7 +112,7 @@ public sealed class OpenIddictClientAspNetCoreBuilder
/// <summary>
/// Enables error pass-through support, so that the rest of the request processing pipeline is
/// automatically invoked when returning an error from the interactive authorization and logout endpoints.
/// automatically invoked when returning an error from the interactive authorization and end session endpoints.
/// When this option is enabled, special logic must be added to these actions to handle errors, that can be
/// retrieved using <see cref="OpenIddictClientAspNetCoreHelpers.GetOpenIddictClientResponse(HttpContext)"/>.
/// </summary>

4
src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreConstants.cs

@ -33,7 +33,7 @@ public static class OpenIddictClientAspNetCoreConstants
public const string ResponseType = ".response_type";
public const string Scope = ".scope";
public const string StateTokenPrincipal = ".state_token_principal";
public const string UserinfoTokenPrincipal = ".userinfo_token_principal";
public const string UserInfoTokenPrincipal = ".userinfo_token_principal";
}
public static class Tokens
@ -47,6 +47,6 @@ public static class OpenIddictClientAspNetCoreConstants
public const string FrontchannelIdentityToken = "frontchannel_id_token";
public const string RefreshToken = "refresh_token";
public const string StateToken = "state_token";
public const string UserinfoToken = "userinfo_token";
public const string UserInfoToken = "userinfo_token";
}
}

10
src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs

@ -281,13 +281,13 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Op
});
}
if (!string.IsNullOrEmpty(context.UserinfoToken))
if (!string.IsNullOrEmpty(context.UserInfoToken))
{
tokens ??= new(capacity: 1);
tokens.Add(new AuthenticationToken
{
Name = Tokens.UserinfoToken,
Value = context.UserinfoToken
Name = Tokens.UserInfoToken,
Value = context.UserInfoToken
});
}
@ -331,9 +331,9 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Op
properties.SetParameter(Properties.StateTokenPrincipal, context.StateTokenPrincipal);
}
if (context.UserinfoTokenPrincipal is not null)
if (context.UserInfoTokenPrincipal is not null)
{
properties.SetParameter(Properties.UserinfoTokenPrincipal, context.UserinfoTokenPrincipal);
properties.SetParameter(Properties.UserInfoTokenPrincipal, context.UserInfoTokenPrincipal);
}
return AuthenticateResult.Success(new AuthenticationTicket(

10
src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandlers.Session.cs

@ -16,7 +16,7 @@ public static partial class OpenIddictClientAspNetCoreHandlers
{
public static ImmutableArray<OpenIddictClientHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create([
/*
* Session request processing:
* End session request processing:
*/
ProcessQueryRequest.Descriptor,
@ -41,16 +41,16 @@ public static partial class OpenIddictClientAspNetCoreHandlers
]);
/// <summary>
/// Contains the logic responsible for processing authorization requests using 302 redirects.
/// Contains the logic responsible for processing end session requests using 302 redirects.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary>
public sealed class ProcessQueryRequest : IOpenIddictClientHandler<ApplyLogoutRequestContext>
public sealed class ProcessQueryRequest : IOpenIddictClientHandler<ApplyEndSessionRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyLogoutRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyEndSessionRequestContext>()
.AddFilter<RequireHttpRequest>()
.UseSingletonHandler<ProcessQueryRequest>()
.SetOrder(250_000)
@ -58,7 +58,7 @@ public static partial class OpenIddictClientAspNetCoreHandlers
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyLogoutRequestContext context)
public ValueTask HandleAsync(ApplyEndSessionRequestContext context)
{
if (context is null)
{

2
src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreOptions.cs

@ -53,7 +53,7 @@ public sealed class OpenIddictClientAspNetCoreOptions : AuthenticationSchemeOpti
/// <summary>
/// Gets or sets a boolean indicating whether OpenIddict should allow the rest of the request processing pipeline
/// to be invoked when returning an error from the interactive authorization and logout endpoints.
/// to be invoked when returning an error from the interactive authorization and end session endpoints.
/// When this option is enabled, special logic must be added to these actions to handle errors, that can be
/// retrieved using <see cref="OpenIddictClientAspNetCoreHelpers.GetOpenIddictClientResponse(HttpContext)"/>.
/// </summary>

2
src/OpenIddict.Client.Owin/OpenIddictClientOwinBuilder.cs

@ -115,7 +115,7 @@ public sealed class OpenIddictClientOwinBuilder
/// <summary>
/// Enables error pass-through support, so that the rest of the request processing pipeline is
/// automatically invoked when returning an error from the interactive authorization and logout endpoints.
/// automatically invoked when returning an error from the interactive authorization and end session endpoints.
/// When this option is enabled, special logic must be added to these actions to handle errors, that can be
/// retrieved using <see cref="OpenIddictClientOwinHelpers.GetOpenIddictClientResponse(IOwinContext)"/>.
/// </summary>

4
src/OpenIddict.Client.Owin/OpenIddictClientOwinConstants.cs

@ -42,7 +42,7 @@ public static class OpenIddictClientOwinConstants
public const string ResponseType = ".response_type";
public const string Scope = ".scope";
public const string StateTokenPrincipal = ".state_token_principal";
public const string UserinfoTokenPrincipal = ".userinfo_token_principal";
public const string UserInfoTokenPrincipal = ".userinfo_token_principal";
}
public static class PropertyTypes
@ -64,6 +64,6 @@ public static class OpenIddictClientOwinConstants
public const string FrontchannelIdentityToken = "frontchannel_id_token";
public const string RefreshToken = "refresh_token";
public const string StateToken = "state_token";
public const string UserinfoToken = "userinfo_token";
public const string UserInfoToken = "userinfo_token";
}
}

4
src/OpenIddict.Client.Owin/OpenIddictClientOwinHandler.cs

@ -235,9 +235,9 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
properties.Dictionary[Tokens.StateToken] = context.StateToken;
}
if (!string.IsNullOrEmpty(context.UserinfoToken))
if (!string.IsNullOrEmpty(context.UserInfoToken))
{
properties.Dictionary[Tokens.UserinfoToken] = context.UserinfoToken;
properties.Dictionary[Tokens.UserInfoToken] = context.UserInfoToken;
}
return new AuthenticationTicket(context.MergedPrincipal?.Identity as ClaimsIdentity, properties);

10
src/OpenIddict.Client.Owin/OpenIddictClientOwinHandlers.Session.cs

@ -15,7 +15,7 @@ public static partial class OpenIddictClientOwinHandlers
{
public static ImmutableArray<OpenIddictClientHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create([
/*
* Session request processing:
* End session request processing:
*/
ProcessQueryRequest.Descriptor,
@ -39,16 +39,16 @@ public static partial class OpenIddictClientOwinHandlers
]);
/// <summary>
/// Contains the logic responsible for processing authorization requests using 302 redirects.
/// Contains the logic responsible for processing end session requests using 302 redirects.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
/// </summary>
public sealed class ProcessQueryRequest : IOpenIddictClientHandler<ApplyLogoutRequestContext>
public sealed class ProcessQueryRequest : IOpenIddictClientHandler<ApplyEndSessionRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyLogoutRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyEndSessionRequestContext>()
.AddFilter<RequireOwinRequest>()
.UseSingletonHandler<ProcessQueryRequest>()
.SetOrder(250_000)
@ -56,7 +56,7 @@ public static partial class OpenIddictClientOwinHandlers
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyLogoutRequestContext context)
public ValueTask HandleAsync(ApplyEndSessionRequestContext context)
{
if (context is null)
{

2
src/OpenIddict.Client.Owin/OpenIddictClientOwinOptions.cs

@ -60,7 +60,7 @@ public sealed class OpenIddictClientOwinOptions : AuthenticationOptions
/// <summary>
/// Gets or sets a boolean indicating whether OpenIddict should allow the rest of the request processing pipeline
/// to be invoked when returning an error from the interactive authorization and logout endpoints.
/// to be invoked when returning an error from the interactive authorization and end session endpoints.
/// When this option is enabled, special logic must be added to these actions to handle errors, that can be
/// retrieved using <see cref="OpenIddictClientOwinHelpers.GetOpenIddictClientResponse(IOwinContext)"/>.
/// </summary>

2
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationConstants.cs

@ -28,6 +28,6 @@ public static class OpenIddictClientSystemIntegrationConstants
public const string FrontchannelIdentityToken = "frontchannel_id_token";
public const string RefreshToken = "refresh_token";
public const string StateToken = "state_token";
public const string UserinfoToken = "userinfo_token";
public const string UserInfoToken = "userinfo_token";
}
}

38
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs

@ -45,7 +45,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
{
public static ImmutableArray<OpenIddictClientHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create([
/*
* Logout request processing:
* End session request processing:
*/
StartASWebAuthenticationSession.Descriptor,
LaunchCustomTabsIntent.Descriptor,
@ -70,10 +70,10 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
]);
/// <summary>
/// Contains the logic responsible for initiating logout requests using an AS web authentication session.
/// Contains the logic responsible for initiating end session requests using an AS web authentication session.
/// Note: this handler is not used when the user session is not interactive.
/// </summary>
public class StartASWebAuthenticationSession : IOpenIddictClientHandler<ApplyLogoutRequestContext>
public class StartASWebAuthenticationSession : IOpenIddictClientHandler<ApplyEndSessionRequestContext>
{
private readonly OpenIddictClientSystemIntegrationService _service;
@ -84,7 +84,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyLogoutRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyEndSessionRequestContext>()
.AddFilter<RequireInteractiveSession>()
.AddFilter<RequireASWebAuthenticationSession>()
.UseSingletonHandler<StartASWebAuthenticationSession>()
@ -97,7 +97,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
[SupportedOSPlatform("maccatalyst13.1")]
[SupportedOSPlatform("macos10.15")]
#pragma warning disable CS1998
public async ValueTask HandleAsync(ApplyLogoutRequestContext context)
public async ValueTask HandleAsync(ApplyEndSessionRequestContext context)
#pragma warning restore CS1998
{
if (context is null)
@ -122,7 +122,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
var source = new TaskCompletionSource<OpenIddictClientSystemIntegrationPlatformCallback>(
TaskCreationOptions.RunContinuationsAsynchronously);
// OpenIddict represents the complete interactive logout dance as a two-phase process:
// OpenIddict represents the complete interactive end session dance as a two-phase process:
// - The sign-out, during which the user is redirected to the authorization server, either
// by launching the system browser or, as in this case, using a web-view-like approach.
//
@ -313,16 +313,16 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
}
/// <summary>
/// Contains the logic responsible for initiating logout requests using a custom tabs intent.
/// Contains the logic responsible for initiating end session requests using a custom tabs intent.
/// Note: this handler is not used when the user session is not interactive.
/// </summary>
public class LaunchCustomTabsIntent : IOpenIddictClientHandler<ApplyLogoutRequestContext>
public class LaunchCustomTabsIntent : IOpenIddictClientHandler<ApplyEndSessionRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyLogoutRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyEndSessionRequestContext>()
.AddFilter<RequireInteractiveSession>()
.AddFilter<RequireCustomTabsIntent>()
.UseSingletonHandler<LaunchCustomTabsIntent>()
@ -333,7 +333,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
/// <inheritdoc/>
[SupportedOSPlatform("android21.0")]
#pragma warning disable CS1998
public async ValueTask HandleAsync(ApplyLogoutRequestContext context)
public async ValueTask HandleAsync(ApplyEndSessionRequestContext context)
#pragma warning restore CS1998
{
if (context is null)
@ -381,10 +381,10 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
}
/// <summary>
/// Contains the logic responsible for initiating logout requests using the web authentication broker.
/// Contains the logic responsible for initiating end session requests using the web authentication broker.
/// Note: this handler is not used when the user session is not interactive.
/// </summary>
public class InvokeWebAuthenticationBroker : IOpenIddictClientHandler<ApplyLogoutRequestContext>
public class InvokeWebAuthenticationBroker : IOpenIddictClientHandler<ApplyEndSessionRequestContext>
{
private readonly OpenIddictClientSystemIntegrationService _service;
@ -395,7 +395,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyLogoutRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyEndSessionRequestContext>()
.AddFilter<RequireInteractiveSession>()
.AddFilter<RequireWebAuthenticationBroker>()
.UseSingletonHandler<InvokeWebAuthenticationBroker>()
@ -406,7 +406,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
/// <inheritdoc/>
[SupportedOSPlatform("windows10.0.17763")]
#pragma warning disable CS1998
public async ValueTask HandleAsync(ApplyLogoutRequestContext context)
public async ValueTask HandleAsync(ApplyEndSessionRequestContext context)
#pragma warning restore CS1998
{
if (context is null)
@ -435,7 +435,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
throw new PlatformNotSupportedException(SR.GetResourceString(SR.ID0392));
}
// OpenIddict represents the complete interactive logout dance as a two-phase process:
// OpenIddict represents the complete interactive end session dance as a two-phase process:
// - The sign-out, during which the user is redirected to the authorization server, either
// by launching the system browser or, as in this case, using a web-view-like approach.
//
@ -546,16 +546,16 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
}
/// <summary>
/// Contains the logic responsible for initiating logout requests using the system browser.
/// Contains the logic responsible for initiating end session requests using the system browser.
/// Note: this handler is not used when the user session is not interactive.
/// </summary>
public class LaunchSystemBrowser : IOpenIddictClientHandler<ApplyLogoutRequestContext>
public class LaunchSystemBrowser : IOpenIddictClientHandler<ApplyEndSessionRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyLogoutRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyEndSessionRequestContext>()
.AddFilter<RequireInteractiveSession>()
.AddFilter<RequireSystemBrowser>()
.UseSingletonHandler<LaunchSystemBrowser>()
@ -564,7 +564,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ApplyLogoutRequestContext context)
public async ValueTask HandleAsync(ApplyEndSessionRequestContext context)
{
if (context is null)
{

16
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.cs

@ -60,7 +60,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
RestoreBackchannelIdentityTokenPrincipalFromMarshalledAuthentication.Descriptor,
RestoreBackchannelAccessTokenPrincipalFromMarshalledAuthentication.Descriptor,
RestoreRefreshTokenPrincipalFromMarshalledAuthentication.Descriptor,
RestoreUserinfoDetailsFromMarshalledAuthentication.Descriptor,
RestoreUserInfoDetailsFromMarshalledAuthentication.Descriptor,
RestoreMergedPrincipalFromMarshalledAuthentication.Descriptor,
CompleteAuthenticationOperation.Descriptor,
@ -1506,11 +1506,11 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
/// Contains the logic responsible for restoring the userinfo details
/// from the marshalled authentication context, if applicable.
/// </summary>
public sealed class RestoreUserinfoDetailsFromMarshalledAuthentication : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class RestoreUserInfoDetailsFromMarshalledAuthentication : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
private readonly OpenIddictClientSystemIntegrationMarshal _marshal;
public RestoreUserinfoDetailsFromMarshalledAuthentication(OpenIddictClientSystemIntegrationMarshal marshal)
public RestoreUserInfoDetailsFromMarshalledAuthentication(OpenIddictClientSystemIntegrationMarshal marshal)
=> _marshal = marshal ?? throw new ArgumentNullException(nameof(marshal));
/// <summary>
@ -1519,8 +1519,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireAuthenticationNonce>()
.UseSingletonHandler<RestoreUserinfoDetailsFromMarshalledAuthentication>()
.SetOrder(ValidateUserinfoTokenSubject.Descriptor.Order + 500)
.UseSingletonHandler<RestoreUserInfoDetailsFromMarshalledAuthentication>()
.SetOrder(ValidateUserInfoTokenSubject.Descriptor.Order + 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -1534,14 +1534,14 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
Debug.Assert(!string.IsNullOrEmpty(context.Nonce), SR.GetResourceString(SR.ID4019));
(context.UserinfoResponse, context.UserinfoTokenPrincipal, context.UserinfoToken) = context.EndpointType switch
(context.UserInfoResponse, context.UserInfoTokenPrincipal, context.UserInfoToken) = context.EndpointType switch
{
// When the authentication context is marshalled, restore the userinfo details from the other instance.
OpenIddictClientEndpointType.Unknown when _marshal.TryGetResult(context.Nonce, out var notification)
=> (notification.UserinfoResponse, notification.UserinfoTokenPrincipal, notification.UserinfoToken),
=> (notification.UserInfoResponse, notification.UserInfoTokenPrincipal, notification.UserInfoToken),
// Otherwise, don't alter the current context.
_ => (context.UserinfoResponse, context.UserinfoTokenPrincipal, context.UserinfoToken)
_ => (context.UserInfoResponse, context.UserInfoTokenPrincipal, context.UserInfoToken)
};
return default;

28
src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.Discovery.cs

@ -38,24 +38,24 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
/*
* Cryptography request processing:
*/
CreateHttpClient<PrepareCryptographyRequestContext>.Descriptor,
PrepareGetHttpRequest<PrepareCryptographyRequestContext>.Descriptor,
AttachHttpVersion<PrepareCryptographyRequestContext>.Descriptor,
AttachJsonAcceptHeaders<PrepareCryptographyRequestContext>.Descriptor,
AttachUserAgentHeader<PrepareCryptographyRequestContext>.Descriptor,
AttachFromHeader<PrepareCryptographyRequestContext>.Descriptor,
AttachHttpParameters<PrepareCryptographyRequestContext>.Descriptor,
SendHttpRequest<ApplyCryptographyRequestContext>.Descriptor,
DisposeHttpRequest<ApplyCryptographyRequestContext>.Descriptor,
CreateHttpClient<PrepareJsonWebKeySetRequestContext>.Descriptor,
PrepareGetHttpRequest<PrepareJsonWebKeySetRequestContext>.Descriptor,
AttachHttpVersion<PrepareJsonWebKeySetRequestContext>.Descriptor,
AttachJsonAcceptHeaders<PrepareJsonWebKeySetRequestContext>.Descriptor,
AttachUserAgentHeader<PrepareJsonWebKeySetRequestContext>.Descriptor,
AttachFromHeader<PrepareJsonWebKeySetRequestContext>.Descriptor,
AttachHttpParameters<PrepareJsonWebKeySetRequestContext>.Descriptor,
SendHttpRequest<ApplyJsonWebKeySetRequestContext>.Descriptor,
DisposeHttpRequest<ApplyJsonWebKeySetRequestContext>.Descriptor,
/*
* Configuration response processing:
*/
DecompressResponseContent<ExtractCryptographyResponseContext>.Descriptor,
ExtractJsonHttpResponse<ExtractCryptographyResponseContext>.Descriptor,
ExtractWwwAuthenticateHeader<ExtractCryptographyResponseContext>.Descriptor,
ValidateHttpResponse<ExtractCryptographyResponseContext>.Descriptor,
DisposeHttpResponse<ExtractCryptographyResponseContext>.Descriptor
DecompressResponseContent<ExtractJsonWebKeySetResponseContext>.Descriptor,
ExtractJsonHttpResponse<ExtractJsonWebKeySetResponseContext>.Descriptor,
ExtractWwwAuthenticateHeader<ExtractJsonWebKeySetResponseContext>.Descriptor,
ValidateHttpResponse<ExtractJsonWebKeySetResponseContext>.Descriptor,
DisposeHttpResponse<ExtractJsonWebKeySetResponseContext>.Descriptor
]);
}
}

58
src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.Userinfo.cs

@ -14,52 +14,52 @@ namespace OpenIddict.Client.SystemNetHttp;
public static partial class OpenIddictClientSystemNetHttpHandlers
{
public static class Userinfo
public static class UserInfo
{
public static ImmutableArray<OpenIddictClientHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create([
/*
* Userinfo request processing:
* UserInfo request processing:
*/
CreateHttpClient<PrepareUserinfoRequestContext>.Descriptor,
PrepareGetHttpRequest<PrepareUserinfoRequestContext>.Descriptor,
AttachHttpVersion<PrepareUserinfoRequestContext>.Descriptor,
AttachJsonAcceptHeaders<PrepareUserinfoRequestContext>.Descriptor,
AttachUserAgentHeader<PrepareUserinfoRequestContext>.Descriptor,
AttachFromHeader<PrepareUserinfoRequestContext>.Descriptor,
CreateHttpClient<PrepareUserInfoRequestContext>.Descriptor,
PrepareGetHttpRequest<PrepareUserInfoRequestContext>.Descriptor,
AttachHttpVersion<PrepareUserInfoRequestContext>.Descriptor,
AttachJsonAcceptHeaders<PrepareUserInfoRequestContext>.Descriptor,
AttachUserAgentHeader<PrepareUserInfoRequestContext>.Descriptor,
AttachFromHeader<PrepareUserInfoRequestContext>.Descriptor,
AttachBearerAccessToken.Descriptor,
AttachHttpParameters<PrepareUserinfoRequestContext>.Descriptor,
SendHttpRequest<ApplyUserinfoRequestContext>.Descriptor,
DisposeHttpRequest<ApplyUserinfoRequestContext>.Descriptor,
AttachHttpParameters<PrepareUserInfoRequestContext>.Descriptor,
SendHttpRequest<ApplyUserInfoRequestContext>.Descriptor,
DisposeHttpRequest<ApplyUserInfoRequestContext>.Descriptor,
/*
* Userinfo response processing:
* UserInfo response processing:
*/
DecompressResponseContent<ExtractUserinfoResponseContext>.Descriptor,
ExtractUserinfoTokenHttpResponse.Descriptor,
ExtractJsonHttpResponse<ExtractUserinfoResponseContext>.Descriptor,
ExtractWwwAuthenticateHeader<ExtractUserinfoResponseContext>.Descriptor,
ValidateHttpResponse<ExtractUserinfoResponseContext>.Descriptor,
DisposeHttpResponse<ExtractUserinfoResponseContext>.Descriptor
DecompressResponseContent<ExtractUserInfoResponseContext>.Descriptor,
ExtractUserInfoTokenHttpResponse.Descriptor,
ExtractJsonHttpResponse<ExtractUserInfoResponseContext>.Descriptor,
ExtractWwwAuthenticateHeader<ExtractUserInfoResponseContext>.Descriptor,
ValidateHttpResponse<ExtractUserInfoResponseContext>.Descriptor,
DisposeHttpResponse<ExtractUserInfoResponseContext>.Descriptor
]);
/// <summary>
/// Contains the logic responsible for attaching the access token to the HTTP Authorization header.
/// </summary>
public sealed class AttachBearerAccessToken : IOpenIddictClientHandler<PrepareUserinfoRequestContext>
public sealed class AttachBearerAccessToken : IOpenIddictClientHandler<PrepareUserInfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserinfoRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserInfoRequestContext>()
.AddFilter<RequireHttpUri>()
.UseSingletonHandler<AttachBearerAccessToken>()
.SetOrder(AttachHttpParameters<PrepareUserinfoRequestContext>.Descriptor.Order - 500)
.SetOrder(AttachHttpParameters<PrepareUserInfoRequestContext>.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(PrepareUserinfoRequestContext context)
public ValueTask HandleAsync(PrepareUserInfoRequestContext context)
{
if (context is null)
{
@ -86,21 +86,21 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
/// <summary>
/// Contains the logic responsible for extracting the response from the userinfo response.
/// </summary>
public sealed class ExtractUserinfoTokenHttpResponse : IOpenIddictClientHandler<ExtractUserinfoResponseContext>
public sealed class ExtractUserInfoTokenHttpResponse : IOpenIddictClientHandler<ExtractUserInfoResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ExtractUserinfoResponseContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<ExtractUserInfoResponseContext>()
.AddFilter<RequireHttpUri>()
.UseSingletonHandler<ExtractUserinfoTokenHttpResponse>()
.SetOrder(ExtractJsonHttpResponse<ExtractUserinfoResponseContext>.Descriptor.Order - 500)
.UseSingletonHandler<ExtractUserInfoTokenHttpResponse>()
.SetOrder(ExtractJsonHttpResponse<ExtractUserInfoResponseContext>.Descriptor.Order - 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ExtractUserinfoResponseContext context)
public async ValueTask HandleAsync(ExtractUserInfoResponseContext context)
{
if (context is null)
{
@ -108,7 +108,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
}
// Don't overwrite the response if one was already provided.
if (context.Response is not null || !string.IsNullOrEmpty(context.UserinfoToken))
if (context.Response is not null || !string.IsNullOrEmpty(context.UserInfoToken))
{
return;
}
@ -132,7 +132,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
MediaTypes.JsonWebToken, StringComparison.OrdinalIgnoreCase))
{
context.Response = new OpenIddictResponse();
context.UserinfoToken = await response.Content.ReadAsStringAsync();
context.UserInfoToken = await response.Content.ReadAsStringAsync();
return;
}

2
src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs

@ -28,7 +28,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
.. Exchange.DefaultHandlers,
.. Introspection.DefaultHandlers,
.. Revocation.DefaultHandlers,
.. Userinfo.DefaultHandlers
.. UserInfo.DefaultHandlers
]);
/// <summary>

4
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Device.cs

@ -73,9 +73,9 @@ public static partial class OpenIddictClientWebIntegrationHandlers
if (!string.IsNullOrEmpty(context.Response.UserCode) &&
Uri.TryCreate((string?) context.Response["verification_url"], UriKind.Absolute, out Uri? uri))
{
// Note: the user verification URI returned by Huawei points to an endpoint that always returns
// Note: the end-user verification URI returned by Huawei points to an endpoint that always returns
// a JSON error when it is accessed without the "user_code" parameter attached. To ensure the
// user verification URI returned by the OpenIddict client service to the caller can be used
// end-user verification URI returned by the OpenIddict client service to the caller can be used
// as-is, both parameters are replaced to always include the user code in the query string.
context.Response[Parameters.VerificationUri] =
context.Response[Parameters.VerificationUriComplete] = OpenIddictHelpers.AddQueryStringParameter(

8
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Discovery.cs

@ -414,10 +414,10 @@ public static partial class OpenIddictClientWebIntegrationHandlers
// limitation, the userinfo endpoint is replaced by the generic /me endpoint URI.
if (context.Registration.ProviderType is ProviderTypes.Atlassian)
{
context.Configuration.UserinfoEndpoint = new Uri("https://api.atlassian.com/me", UriKind.Absolute);
context.Configuration.UserInfoEndpoint = new Uri("https://api.atlassian.com/me", UriKind.Absolute);
}
// While Auth0 exposes an OpenID Connect-compliant logout endpoint, its address is not returned
// While Auth0 exposes an OpenID Connect-compliant end session endpoint, its address is not returned
// as part of the configuration document. To ensure RP-initiated logout is supported with Auth0,
// "end_session_endpoint" is manually computed using the issuer URI and added to the configuration.
else if (context.Registration.ProviderType is ProviderTypes.Auth0)
@ -439,7 +439,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
// in its configuration document. To work around that, the endpoint URI is manually added here.
else if (context.Registration.ProviderType is ProviderTypes.OrangeFrance)
{
context.Configuration.UserinfoEndpoint ??=
context.Configuration.UserInfoEndpoint ??=
new Uri("https://api.orange.com/openidconnect/fr/v1/userinfo", UriKind.Absolute);
}
@ -458,7 +458,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
new Uri("https://api-m.sandbox.paypal.com/v1/oauth2/revoke", UriKind.Absolute);
context.Configuration.TokenEndpoint =
new Uri("https://api-m.sandbox.paypal.com/v1/oauth2/token", UriKind.Absolute);
context.Configuration.UserinfoEndpoint =
context.Configuration.UserInfoEndpoint =
new Uri("https://api-m.sandbox.paypal.com/v1/oauth2/token/userinfo", UriKind.Absolute);
}

72
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.Userinfo.cs

@ -12,18 +12,18 @@ using System.Net.Http.Json;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpConstants;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlerFilters;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers.Userinfo;
using static OpenIddict.Client.SystemNetHttp.OpenIddictClientSystemNetHttpHandlers.UserInfo;
using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants;
namespace OpenIddict.Client.WebIntegration;
public static partial class OpenIddictClientWebIntegrationHandlers
{
public static class Userinfo
public static class UserInfo
{
public static ImmutableArray<OpenIddictClientHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create([
/*
* Userinfo request preparation:
* UserInfo request preparation:
*/
OverrideHttpMethod.Descriptor,
AttachRequestHeaders.Descriptor,
@ -32,31 +32,31 @@ public static partial class OpenIddictClientWebIntegrationHandlers
AttachNonStandardRequestPayload.Descriptor,
/*
* Userinfo response extraction:
* UserInfo response extraction:
*/
NormalizeContentType.Descriptor,
UnwrapUserinfoResponse.Descriptor,
UnwrapUserInfoResponse.Descriptor,
MapNonStandardResponseParameters.Descriptor,
]);
/// <summary>
/// Contains the logic responsible for overriding the HTTP method for the providers that require it.
/// </summary>
public sealed class OverrideHttpMethod : IOpenIddictClientHandler<PrepareUserinfoRequestContext>
public sealed class OverrideHttpMethod : IOpenIddictClientHandler<PrepareUserInfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserinfoRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserInfoRequestContext>()
.AddFilter<RequireHttpUri>()
.UseSingletonHandler<OverrideHttpMethod>()
.SetOrder(PreparePostHttpRequest<PrepareUserinfoRequestContext>.Descriptor.Order + 250)
.SetOrder(PreparePostHttpRequest<PrepareUserInfoRequestContext>.Descriptor.Order + 250)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(PrepareUserinfoRequestContext context)
public ValueTask HandleAsync(PrepareUserInfoRequestContext context)
{
if (context is null)
{
@ -89,21 +89,21 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// Contains the logic responsible for attaching additional
/// headers to the request for the providers that require it.
/// </summary>
public sealed class AttachRequestHeaders : IOpenIddictClientHandler<PrepareUserinfoRequestContext>
public sealed class AttachRequestHeaders : IOpenIddictClientHandler<PrepareUserInfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserinfoRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserInfoRequestContext>()
.AddFilter<RequireHttpUri>()
.UseSingletonHandler<AttachRequestHeaders>()
.SetOrder(AttachUserAgentHeader<PrepareUserinfoRequestContext>.Descriptor.Order + 250)
.SetOrder(AttachUserAgentHeader<PrepareUserInfoRequestContext>.Descriptor.Order + 250)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(PrepareUserinfoRequestContext context)
public ValueTask HandleAsync(PrepareUserInfoRequestContext context)
{
if (context is null)
{
@ -144,13 +144,13 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// Contains the logic responsible for attaching the access token
/// parameter to the request for the providers that require it.
/// </summary>
public sealed class AttachAccessTokenParameter : IOpenIddictClientHandler<PrepareUserinfoRequestContext>
public sealed class AttachAccessTokenParameter : IOpenIddictClientHandler<PrepareUserInfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserinfoRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserInfoRequestContext>()
.AddFilter<RequireHttpUri>()
.UseSingletonHandler<AttachAccessTokenParameter>()
.SetOrder(AttachBearerAccessToken.Descriptor.Order + 250)
@ -158,7 +158,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(PrepareUserinfoRequestContext context)
public ValueTask HandleAsync(PrepareUserInfoRequestContext context)
{
if (context is null)
{
@ -209,20 +209,20 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// Contains the logic responsible for attaching non-standard
/// parameters to the request for the providers that require it.
/// </summary>
public sealed class AttachNonStandardParameters : IOpenIddictClientHandler<PrepareUserinfoRequestContext>
public sealed class AttachNonStandardParameters : IOpenIddictClientHandler<PrepareUserInfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserinfoRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserInfoRequestContext>()
.UseSingletonHandler<AttachNonStandardParameters>()
.SetOrder(AttachHttpParameters<PrepareUserinfoRequestContext>.Descriptor.Order - 250)
.SetOrder(AttachHttpParameters<PrepareUserInfoRequestContext>.Descriptor.Order - 250)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(PrepareUserinfoRequestContext context)
public ValueTask HandleAsync(PrepareUserInfoRequestContext context)
{
if (context is null)
{
@ -243,21 +243,21 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// <summary>
/// Contains the logic responsible for attaching a non-standard payload for the providers that require it.
/// </summary>
public sealed class AttachNonStandardRequestPayload : IOpenIddictClientHandler<PrepareUserinfoRequestContext>
public sealed class AttachNonStandardRequestPayload : IOpenIddictClientHandler<PrepareUserInfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserinfoRequestContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<PrepareUserInfoRequestContext>()
.AddFilter<RequireHttpUri>()
.UseSingletonHandler<AttachNonStandardRequestPayload>()
.SetOrder(AttachHttpParameters<PrepareUserinfoRequestContext>.Descriptor.Order + 500)
.SetOrder(AttachHttpParameters<PrepareUserInfoRequestContext>.Descriptor.Order + 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(PrepareUserinfoRequestContext context)
public ValueTask HandleAsync(PrepareUserInfoRequestContext context)
{
if (context is null)
{
@ -292,21 +292,21 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// Contains the logic responsible for normalizing the returned content
/// type of userinfo responses for the providers that require it.
/// </summary>
public sealed class NormalizeContentType : IOpenIddictClientHandler<ExtractUserinfoResponseContext>
public sealed class NormalizeContentType : IOpenIddictClientHandler<ExtractUserInfoResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ExtractUserinfoResponseContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<ExtractUserInfoResponseContext>()
.AddFilter<RequireHttpUri>()
.UseSingletonHandler<NormalizeContentType>()
.SetOrder(ExtractUserinfoTokenHttpResponse.Descriptor.Order - 250)
.SetOrder(ExtractUserInfoTokenHttpResponse.Descriptor.Order - 250)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ExtractUserinfoResponseContext context)
public ValueTask HandleAsync(ExtractUserInfoResponseContext context)
{
if (context is null)
{
@ -358,20 +358,20 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// Contains the logic responsible for extracting the userinfo response
/// from nested JSON nodes (e.g "data") for the providers that require it.
/// </summary>
public sealed class UnwrapUserinfoResponse : IOpenIddictClientHandler<ExtractUserinfoResponseContext>
public sealed class UnwrapUserInfoResponse : IOpenIddictClientHandler<ExtractUserInfoResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ExtractUserinfoResponseContext>()
.UseSingletonHandler<UnwrapUserinfoResponse>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<ExtractUserInfoResponseContext>()
.UseSingletonHandler<UnwrapUserInfoResponse>()
.SetOrder(int.MaxValue - 50_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ExtractUserinfoResponseContext context)
public ValueTask HandleAsync(ExtractUserInfoResponseContext context)
{
if (context is null)
{
@ -458,20 +458,20 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// Contains the logic responsible for mapping non-standard response parameters
/// to their standard equivalent for the providers that require it.
/// </summary>
public sealed class MapNonStandardResponseParameters : IOpenIddictClientHandler<ExtractUserinfoResponseContext>
public sealed class MapNonStandardResponseParameters : IOpenIddictClientHandler<ExtractUserInfoResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ExtractUserinfoResponseContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<ExtractUserInfoResponseContext>()
.UseSingletonHandler<MapNonStandardResponseParameters>()
.SetOrder(UnwrapUserinfoResponse.Descriptor.Order + 1_000)
.SetOrder(UnwrapUserInfoResponse.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ExtractUserinfoResponseContext context)
public ValueTask HandleAsync(ExtractUserInfoResponseContext context)
{
if (context is null)
{

194
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs

@ -32,11 +32,11 @@ public static partial class OpenIddictClientWebIntegrationHandlers
AdjustRedirectUriInTokenRequest.Descriptor,
OverrideValidatedBackchannelTokens.Descriptor,
DisableBackchannelIdentityTokenNonceValidation.Descriptor,
OverrideUserinfoEndpoint.Descriptor,
DisableUserinfoRetrieval.Descriptor,
DisableUserinfoValidation.Descriptor,
AttachAdditionalUserinfoRequestParameters.Descriptor,
PopulateUserinfoTokenPrincipalFromTokenResponse.Descriptor,
OverrideUserInfoEndpoint.Descriptor,
DisableUserInfoRetrieval.Descriptor,
DisableUserInfoValidation.Descriptor,
AttachAdditionalUserInfoRequestParameters.Descriptor,
PopulateUserInfoTokenPrincipalFromTokenResponse.Descriptor,
MapCustomWebServicesFederationClaims.Descriptor,
/*
@ -61,7 +61,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
.. Exchange.DefaultHandlers,
.. Protection.DefaultHandlers,
.. Revocation.DefaultHandlers,
.. Userinfo.DefaultHandlers
.. UserInfo.DefaultHandlers
]);
/// <summary>
@ -797,15 +797,15 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// Contains the logic responsible for overriding the address
/// of the userinfo endpoint for the providers that require it.
/// </summary>
public sealed class OverrideUserinfoEndpoint : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class OverrideUserInfoEndpoint : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.UseSingletonHandler<OverrideUserinfoEndpoint>()
.SetOrder(ResolveUserinfoEndpoint.Descriptor.Order + 500)
.UseSingletonHandler<OverrideUserInfoEndpoint>()
.SetOrder(ResolveUserInfoEndpoint.Descriptor.Order + 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -817,7 +817,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
context.UserinfoEndpoint = context.Registration.ProviderType switch
context.UserInfoEndpoint = context.Registration.ProviderType switch
{
// Dailymotion's userinfo endpoint requires sending the user identifier in the URI path.
ProviderTypes.Dailymotion when (string?) context.TokenResponse?["uid"] is string identifier
@ -872,7 +872,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
_ => new Uri("https://accounts.zoho.com/oauth/user/info", UriKind.Absolute)
},
_ => context.UserinfoEndpoint
_ => context.UserInfoEndpoint
};
return default;
@ -882,15 +882,15 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// <summary>
/// Contains the logic responsible for disabling the userinfo retrieval for the providers that require it.
/// </summary>
public sealed class DisableUserinfoRetrieval : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class DisableUserInfoRetrieval : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.UseSingletonHandler<DisableUserinfoRetrieval>()
.SetOrder(EvaluateUserinfoRequest.Descriptor.Order + 250)
.UseSingletonHandler<DisableUserInfoRetrieval>()
.SetOrder(EvaluateUserInfoRequest.Descriptor.Order + 250)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -902,7 +902,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
context.SendUserinfoRequest = context.Registration.ProviderType switch
context.SendUserInfoRequest = context.Registration.ProviderType switch
{
// Note: ADFS has severe restrictions affecting the ability to access the userinfo endpoint
// (e.g the "resource" parameter MUST be null or the "urn:microsoft:userinfo" value MUST be
@ -930,7 +930,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
context.Scopes.Any(static scope => scope.StartsWith("XboxLive.", StringComparison.OrdinalIgnoreCase))
=> false,
_ => context.SendUserinfoRequest
_ => context.SendUserInfoRequest
},
// Note: some providers don't allow querying the userinfo endpoint when the "openid" scope
@ -945,10 +945,10 @@ public static partial class OpenIddictClientWebIntegrationHandlers
GrantTypes.DeviceCode or GrantTypes.RefreshToken when !context.Scopes.Contains(Scopes.OpenId)
=> false,
_ => context.SendUserinfoRequest
_ => context.SendUserInfoRequest
},
_ => context.SendUserinfoRequest
_ => context.SendUserInfoRequest
};
return default;
@ -958,15 +958,15 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// <summary>
/// Contains the logic responsible for disabling the userinfo validation for the providers that require it.
/// </summary>
public sealed class DisableUserinfoValidation : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class DisableUserInfoValidation : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.UseSingletonHandler<DisableUserinfoValidation>()
.SetOrder(DisableUserinfoRetrieval.Descriptor.Order + 250)
.UseSingletonHandler<DisableUserInfoValidation>()
.SetOrder(DisableUserInfoRetrieval.Descriptor.Order + 250)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -983,12 +983,12 @@ public static partial class OpenIddictClientWebIntegrationHandlers
//
// To ensure OpenIddict can be used with these providers, validation is disabled when necessary.
context.DisableUserinfoValidation = context.Registration.ProviderType switch
context.DisableUserInfoValidation = context.Registration.ProviderType switch
{
// SuperOffice doesn't offer a standard OpenID Connect userinfo endpoint.
ProviderTypes.SuperOffice => true,
_ => context.DisableUserinfoValidation
_ => context.DisableUserInfoValidation
};
return default;
@ -999,16 +999,16 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// Contains the logic responsible for attaching additional parameters
/// to the userinfo request for the providers that require it.
/// </summary>
public sealed class AttachAdditionalUserinfoRequestParameters : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class AttachAdditionalUserInfoRequestParameters : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireUserinfoRequest>()
.UseSingletonHandler<AttachAdditionalUserinfoRequestParameters>()
.SetOrder(AttachUserinfoRequestParameters.Descriptor.Order + 500)
.AddFilter<RequireUserInfoRequest>()
.UseSingletonHandler<AttachAdditionalUserInfoRequestParameters>()
.SetOrder(AttachUserInfoRequestParameters.Descriptor.Order + 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -1020,7 +1020,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
throw new ArgumentNullException(nameof(context));
}
Debug.Assert(context.UserinfoRequest is not null, SR.GetResourceString(SR.ID4008));
Debug.Assert(context.UserInfoRequest is not null, SR.GetResourceString(SR.ID4008));
// Dailymotion limits the number of fields returned by the userinfo endpoint
// but allows returning additional information using special parameters that
@ -1029,14 +1029,14 @@ public static partial class OpenIddictClientWebIntegrationHandlers
{
var settings = context.Registration.GetDailymotionSettings();
context.UserinfoRequest["fields"] = string.Join(",", settings.UserFields);
context.UserInfoRequest["fields"] = string.Join(",", settings.UserFields);
}
// Disqus requires sending the client identifier (called "public
// API key" in the documentation) as part of the userinfo request.
else if (context.Registration.ProviderType is ProviderTypes.Disqus)
{
context.UserinfoRequest["api_key"] = context.Registration.ClientId;
context.UserInfoRequest["api_key"] = context.Registration.ClientId;
}
// Facebook limits the number of fields returned by the userinfo endpoint
@ -1046,7 +1046,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
{
var settings = context.Registration.GetFacebookSettings();
context.UserinfoRequest["fields"] = string.Join(",", settings.Fields);
context.UserInfoRequest["fields"] = string.Join(",", settings.Fields);
}
// Meetup's userinfo endpoint is a GraphQL implementation that requires
@ -1055,7 +1055,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
{
var settings = context.Registration.GetMeetupSettings();
context.UserinfoRequest["query"] = $"query {{ self {{ {string.Join(" ", settings.UserFields)} }} }}";
context.UserInfoRequest["query"] = $"query {{ self {{ {string.Join(" ", settings.UserFields)} }} }}";
}
// Patreon limits the number of fields returned by the userinfo endpoint
@ -1065,7 +1065,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
{
var settings = context.Registration.GetPatreonSettings();
context.UserinfoRequest["fields[user]"] = string.Join(",", settings.UserFields);
context.UserInfoRequest["fields[user]"] = string.Join(",", settings.UserFields);
}
// StackOverflow requires sending an application key and a site parameter
@ -1074,8 +1074,8 @@ public static partial class OpenIddictClientWebIntegrationHandlers
{
var settings = context.Registration.GetStackExchangeSettings();
context.UserinfoRequest["key"] = settings.ApplicationKey;
context.UserinfoRequest["site"] = settings.Site;
context.UserInfoRequest["key"] = settings.ApplicationKey;
context.UserInfoRequest["site"] = settings.Site;
}
// SubscribeStar's userinfo endpoint is a GraphQL implementation that requires
@ -1084,20 +1084,20 @@ public static partial class OpenIddictClientWebIntegrationHandlers
{
var settings = context.Registration.GetSubscribeStarSettings();
context.UserinfoRequest["query"] = $"{{ user {{ {string.Join(", ", settings.UserFields)} }} }}";
context.UserInfoRequest["query"] = $"{{ user {{ {string.Join(", ", settings.UserFields)} }} }}";
}
// Todoist requires sending "sync_token" and "resource_types" parameters.
else if (context.Registration.ProviderType is ProviderTypes.Todoist)
{
context.UserinfoRequest["sync_token"] = "*";
context.UserinfoRequest["resource_types"] = "[\"user\"]";
context.UserInfoRequest["sync_token"] = "*";
context.UserInfoRequest["resource_types"] = "[\"user\"]";
}
// Trakt allows retrieving additional user details via the "extended" parameter.
else if (context.Registration.ProviderType is ProviderTypes.Trakt)
{
context.UserinfoRequest["extended"] = "full";
context.UserInfoRequest["extended"] = "full";
}
// Twitter limits the number of fields returned by the userinfo endpoint
@ -1107,15 +1107,15 @@ public static partial class OpenIddictClientWebIntegrationHandlers
{
var settings = context.Registration.GetTwitterSettings();
context.UserinfoRequest["expansions"] = string.Join(",", settings.Expansions);
context.UserinfoRequest["tweet.fields"] = string.Join(",", settings.TweetFields);
context.UserinfoRequest["user.fields"] = string.Join(",", settings.UserFields);
context.UserInfoRequest["expansions"] = string.Join(",", settings.Expansions);
context.UserInfoRequest["tweet.fields"] = string.Join(",", settings.TweetFields);
context.UserInfoRequest["user.fields"] = string.Join(",", settings.UserFields);
}
// Weibo requires sending the user identifier as part of the userinfo request.
else if (context.Registration.ProviderType is ProviderTypes.Weibo)
{
context.UserinfoRequest["uid"] = context.TokenResponse?["uid"];
context.UserInfoRequest["uid"] = context.TokenResponse?["uid"];
}
return default;
@ -1126,7 +1126,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
/// Contains the logic responsible for creating a userinfo token principal from the custom
/// parameters returned in the token response for the providers that require it.
/// </summary>
public sealed class PopulateUserinfoTokenPrincipalFromTokenResponse : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class PopulateUserInfoTokenPrincipalFromTokenResponse : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
@ -1134,8 +1134,8 @@ public static partial class OpenIddictClientWebIntegrationHandlers
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireTokenRequest>()
.UseSingletonHandler<PopulateUserinfoTokenPrincipalFromTokenResponse>()
.SetOrder(ValidateUserinfoToken.Descriptor.Order + 500)
.UseSingletonHandler<PopulateUserInfoTokenPrincipalFromTokenResponse>()
.SetOrder(ValidateUserInfoToken.Descriptor.Order + 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -1151,7 +1151,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
Debug.Assert(context.TokenResponse is not null, SR.GetResourceString(SR.ID4007));
// Don't overwrite the userinfo token principal if one was already set.
if (context.UserinfoTokenPrincipal is not null)
if (context.UserInfoTokenPrincipal is not null)
{
return default;
}
@ -1216,7 +1216,7 @@ public static partial class OpenIddictClientWebIntegrationHandlers
}
}
context.UserinfoTokenPrincipal = new ClaimsPrincipal(identity);
context.UserInfoTokenPrincipal = new ClaimsPrincipal(identity);
return default;
}
@ -1266,30 +1266,30 @@ public static partial class OpenIddictClientWebIntegrationHandlers
context.MergedPrincipal.SetClaim(ClaimTypes.Email, issuer: issuer, value: context.Registration.ProviderType switch
{
// Basecamp returns the email address as a custom "email_address" node:
ProviderTypes.Basecamp => (string?) context.UserinfoResponse?["email_address"],
ProviderTypes.Basecamp => (string?) context.UserInfoResponse?["email_address"],
// Bitly returns one or more email addresses as a custom "emails" node:
ProviderTypes.Bitly => context.UserinfoResponse?["emails"]
ProviderTypes.Bitly => context.UserInfoResponse?["emails"]
?.GetUnnamedParameters()
?.Where(parameter => (bool?) parameter["is_primary"] is true)
?.Select(parameter => (string?) parameter["email"])
?.FirstOrDefault(),
// HubSpot returns the email address as a custom "user" node:
ProviderTypes.HubSpot => (string?) context.UserinfoResponse?["user"],
ProviderTypes.HubSpot => (string?) context.UserInfoResponse?["user"],
// Mailchimp returns the email address as a custom "login/login_email" node:
ProviderTypes.Mailchimp => (string?) context.UserinfoResponse?["login"]?["login_email"],
ProviderTypes.Mailchimp => (string?) context.UserInfoResponse?["login"]?["login_email"],
// Notion returns the email address as a custom "bot/owner/user/person/email" node
// but requires a special capability to access this node, that may not be present:
ProviderTypes.Notion => (string?) context.UserinfoResponse?["bot"]?["owner"]?["user"]?["person"]?["email"],
ProviderTypes.Notion => (string?) context.UserInfoResponse?["bot"]?["owner"]?["user"]?["person"]?["email"],
// Patreon returns the email address as a custom "attributes/email" node:
ProviderTypes.Patreon => (string?) context.UserinfoResponse?["attributes"]?["email"],
ProviderTypes.Patreon => (string?) context.UserInfoResponse?["attributes"]?["email"],
// ServiceChannel and Zoho return the email address as a custom "Email" node:
ProviderTypes.ServiceChannel or ProviderTypes.Zoho => (string?) context.UserinfoResponse?["Email"],
ProviderTypes.ServiceChannel or ProviderTypes.Zoho => (string?) context.UserInfoResponse?["Email"],
// Shopify returns the email address as a custom "associated_user/email" node in token responses:
ProviderTypes.Shopify => (string?) context.TokenResponse?["associated_user"]?["email"],
@ -1304,42 +1304,42 @@ public static partial class OpenIddictClientWebIntegrationHandlers
ProviderTypes.Discord or ProviderTypes.Disqus or ProviderTypes.Kook or
ProviderTypes.Lichess or ProviderTypes.Mastodon or ProviderTypes.Mixcloud or
ProviderTypes.Trakt or ProviderTypes.WordPress
=> (string?) context.UserinfoResponse?["username"],
=> (string?) context.UserInfoResponse?["username"],
// Basecamp and Harvest don't return a username so one is created using the "first_name" and "last_name" nodes:
ProviderTypes.Basecamp or ProviderTypes.Harvest
when context.UserinfoResponse?.HasParameter("first_name") is true &&
context.UserinfoResponse?.HasParameter("last_name") is true
=> $"{(string?) context.UserinfoResponse?["first_name"]} {(string?) context.UserinfoResponse?["last_name"]}",
when context.UserInfoResponse?.HasParameter("first_name") is true &&
context.UserInfoResponse?.HasParameter("last_name") is true
=> $"{(string?) context.UserInfoResponse?["first_name"]} {(string?) context.UserInfoResponse?["last_name"]}",
// FitBit returns the username as a custom "displayName" node:
ProviderTypes.Fitbit => (string?) context.UserinfoResponse?["displayName"],
ProviderTypes.Fitbit => (string?) context.UserInfoResponse?["displayName"],
// Huawei returns the username as a custom "display_name" in the backchannel identity token:
ProviderTypes.Huawei => context.BackchannelIdentityTokenPrincipal?.GetClaim("display_name"),
// HubSpot returns the username as a custom "user" node:
ProviderTypes.HubSpot => (string?) context.UserinfoResponse?["user"],
ProviderTypes.HubSpot => (string?) context.UserInfoResponse?["user"],
// Mailchimp returns the username as a custom "accountname" node:
ProviderTypes.Mailchimp => (string?) context.UserinfoResponse?["accountname"],
ProviderTypes.Mailchimp => (string?) context.UserInfoResponse?["accountname"],
// Mailchimp returns the username as a custom "sub" node:
ProviderTypes.MusicBrainz => (string?) context.UserinfoResponse?["sub"],
ProviderTypes.MusicBrainz => (string?) context.UserInfoResponse?["sub"],
// Nextcloud returns the username as a custom "displayname" or "display-name" node:
ProviderTypes.Nextcloud => (string?) context.UserinfoResponse?["displayname"] ??
(string?) context.UserinfoResponse?["display-name"],
ProviderTypes.Nextcloud => (string?) context.UserInfoResponse?["displayname"] ??
(string?) context.UserInfoResponse?["display-name"],
// Notion returns the username as a custom "bot/owner/user/name" node but
// requires a special capability to access this node, that may not be present:
ProviderTypes.Notion => (string?) context.UserinfoResponse?["bot"]?["owner"]?["user"]?["name"],
ProviderTypes.Notion => (string?) context.UserInfoResponse?["bot"]?["owner"]?["user"]?["name"],
// Patreon doesn't return a username and requires using the complete user name as the username:
ProviderTypes.Patreon => (string?) context.UserinfoResponse?["attributes"]?["full_name"],
ProviderTypes.Patreon => (string?) context.UserInfoResponse?["attributes"]?["full_name"],
// ServiceChannel returns the username as a custom "UserName" node:
ProviderTypes.ServiceChannel => (string?) context.UserinfoResponse?["UserName"],
ProviderTypes.ServiceChannel => (string?) context.UserInfoResponse?["UserName"],
// Shopify doesn't return a username so one is created using the "first_name" and "last_name" nodes:
ProviderTypes.Shopify
@ -1349,31 +1349,31 @@ public static partial class OpenIddictClientWebIntegrationHandlers
// Smartsheet doesn't return a username so one is created using the "firstName" and "lastName" nodes:
ProviderTypes.Smartsheet
when context.UserinfoResponse?.HasParameter("firstName") is true &&
context.UserinfoResponse?.HasParameter("lastName") is true
=> $"{(string?) context.UserinfoResponse?["firstName"]} {(string?) context.UserinfoResponse?["lastName"]}",
when context.UserInfoResponse?.HasParameter("firstName") is true &&
context.UserInfoResponse?.HasParameter("lastName") is true
=> $"{(string?) context.UserInfoResponse?["firstName"]} {(string?) context.UserInfoResponse?["lastName"]}",
// These providers return the username as a custom "display_name" node:
ProviderTypes.Spotify or ProviderTypes.StackExchange or ProviderTypes.Zoom
=> (string?) context.UserinfoResponse?["display_name"],
=> (string?) context.UserInfoResponse?["display_name"],
// Strava returns the username as a custom "athlete/username" node in token responses:
ProviderTypes.Strava => (string?) context.TokenResponse?["athlete"]?["username"],
// Streamlabs returns the username as a custom "streamlabs/display_name" node:
ProviderTypes.Streamlabs => (string?) context.UserinfoResponse?["streamlabs"]?["display_name"],
ProviderTypes.Streamlabs => (string?) context.UserInfoResponse?["streamlabs"]?["display_name"],
// Todoist returns the username as a custom "full_name" node:
ProviderTypes.Todoist => (string?) context.UserinfoResponse?["full_name"],
ProviderTypes.Todoist => (string?) context.UserInfoResponse?["full_name"],
// Trovo returns the username as a custom "userName" node:
ProviderTypes.Trovo => (string?) context.UserinfoResponse?["userName"],
ProviderTypes.Trovo => (string?) context.UserInfoResponse?["userName"],
// Typeform returns the username as a custom "alias" node:
ProviderTypes.Typeform => (string?) context.UserinfoResponse?["alias"],
ProviderTypes.Typeform => (string?) context.UserInfoResponse?["alias"],
// Zoho returns the username as a custom "Display_Name" node:
ProviderTypes.Zoho => (string?) context.UserinfoResponse?["Display_Name"],
ProviderTypes.Zoho => (string?) context.UserInfoResponse?["Display_Name"],
_ => context.MergedPrincipal.GetClaim(ClaimTypes.Name)
});
@ -1383,14 +1383,14 @@ public static partial class OpenIddictClientWebIntegrationHandlers
// These providers return the user identifier as a custom "user_id" node:
ProviderTypes.Amazon or ProviderTypes.HubSpot or
ProviderTypes.StackExchange or ProviderTypes.Typeform
=> (string?) context.UserinfoResponse?["user_id"],
=> (string?) context.UserInfoResponse?["user_id"],
// ArcGIS and Trakt don't return a user identifier and require using the username as the identifier:
ProviderTypes.ArcGisOnline or ProviderTypes.Trakt
=> (string?) context.UserinfoResponse?["username"],
=> (string?) context.UserInfoResponse?["username"],
// Atlassian returns the user identifier as a custom "account_id" node:
ProviderTypes.Atlassian => (string?) context.UserinfoResponse?["account_id"],
ProviderTypes.Atlassian => (string?) context.UserInfoResponse?["account_id"],
// These providers return the user identifier as a custom "id" node:
ProviderTypes.Airtable or ProviderTypes.Basecamp or ProviderTypes.Box or
@ -1402,38 +1402,38 @@ public static partial class OpenIddictClientWebIntegrationHandlers
ProviderTypes.Pipedrive or ProviderTypes.Reddit or ProviderTypes.Smartsheet or
ProviderTypes.Spotify or ProviderTypes.SubscribeStar or ProviderTypes.Todoist or
ProviderTypes.Twitter or ProviderTypes.Weibo or ProviderTypes.Zoom
=> (string?) context.UserinfoResponse?["id"],
=> (string?) context.UserInfoResponse?["id"],
// Bitbucket returns the user identifier as a custom "uuid" node:
ProviderTypes.Bitbucket => (string?) context.UserinfoResponse?["uuid"],
ProviderTypes.Bitbucket => (string?) context.UserInfoResponse?["uuid"],
// Bitly returns the user identifier as a custom "login" node:
ProviderTypes.Bitly => (string?) context.UserinfoResponse?["login"],
ProviderTypes.Bitly => (string?) context.UserInfoResponse?["login"],
// Calendly returns the user identifier (formatted as a URI) as a custom "uri" node:
ProviderTypes.Calendly => (string?) context.UserinfoResponse?["uri"],
ProviderTypes.Calendly => (string?) context.UserInfoResponse?["uri"],
// DeviantArt returns the user identifier as a custom "userid" node:
ProviderTypes.DeviantArt => (string?) context.UserinfoResponse?["userid"],
ProviderTypes.DeviantArt => (string?) context.UserInfoResponse?["userid"],
// Fitbit returns the user identifier as a custom "encodedId" node:
ProviderTypes.Fitbit => (string?) context.UserinfoResponse?["encodedId"],
ProviderTypes.Fitbit => (string?) context.UserInfoResponse?["encodedId"],
// Mailchimp returns the user identifier as a custom "login/login_id" node:
ProviderTypes.Mailchimp => (string?) context.UserinfoResponse?["login"]?["login_id"],
ProviderTypes.Mailchimp => (string?) context.UserInfoResponse?["login"]?["login_id"],
// Mixcloud returns the user identifier as a custom "key" node:
ProviderTypes.Mixcloud => (string?) context.UserinfoResponse?["key"],
ProviderTypes.Mixcloud => (string?) context.UserInfoResponse?["key"],
// MusicBrainz returns the user identifier as a custom "metabrainz_user_id" node:
ProviderTypes.MusicBrainz => (string?) context.UserinfoResponse?["metabrainz_user_id"],
ProviderTypes.MusicBrainz => (string?) context.UserInfoResponse?["metabrainz_user_id"],
// Notion returns the user identifier as a custom "bot/owner/user/id" node but
// requires a special capability to access this node, that may not be present:
ProviderTypes.Notion => (string?) context.UserinfoResponse?["bot"]?["owner"]?["user"]?["id"],
ProviderTypes.Notion => (string?) context.UserInfoResponse?["bot"]?["owner"]?["user"]?["id"],
// ServiceChannel returns the user identifier as a custom "UserId" node:
ProviderTypes.ServiceChannel => (string?) context.UserinfoResponse?["UserId"],
ProviderTypes.ServiceChannel => (string?) context.UserInfoResponse?["UserId"],
// Shopify returns the user identifier as a custom "associated_user/id" node in token responses:
ProviderTypes.Shopify => (string?) context.TokenResponse?["associated_user"]?["id"],
@ -1445,23 +1445,23 @@ public static partial class OpenIddictClientWebIntegrationHandlers
ProviderTypes.StripeConnect => (string?) context.TokenResponse?["stripe_user_id"],
// Streamlabs returns the user identifier as a custom "streamlabs/id" node:
ProviderTypes.Streamlabs => (string?) context.UserinfoResponse?["streamlabs"]?["id"],
ProviderTypes.Streamlabs => (string?) context.UserInfoResponse?["streamlabs"]?["id"],
// Trovo returns the user identifier as a custom "userId" node:
ProviderTypes.Trovo => (string?) context.UserinfoResponse?["userId"],
ProviderTypes.Trovo => (string?) context.UserInfoResponse?["userId"],
// Tumblr doesn't return a user identifier and requires using the username as the identifier:
ProviderTypes.Tumblr => (string?) context.UserinfoResponse?["name"],
ProviderTypes.Tumblr => (string?) context.UserInfoResponse?["name"],
// Vimeo returns the user identifier as a custom "uri" node, prefixed with "/users/":
ProviderTypes.Vimeo => (string?) context.UserinfoResponse?["uri"] is string uri &&
ProviderTypes.Vimeo => (string?) context.UserInfoResponse?["uri"] is string uri &&
uri.StartsWith("/users/", StringComparison.Ordinal) ? uri["/users/".Length..] : null,
// WordPress returns the user identifier as a custom "ID" node:
ProviderTypes.WordPress => (string?) context.UserinfoResponse?["ID"],
ProviderTypes.WordPress => (string?) context.UserInfoResponse?["ID"],
// WordPress returns the user identifier as a custom "ZUID" node:
ProviderTypes.Zoho => (string?) context.UserinfoResponse?["ZUID"],
ProviderTypes.Zoho => (string?) context.UserInfoResponse?["ZUID"],
_ => context.MergedPrincipal.GetClaim(ClaimTypes.NameIdentifier)
});

102
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml

@ -57,7 +57,7 @@
<Environment Issuer="https://airtable.com/">
<Configuration AuthorizationEndpoint="https://airtable.com/oauth2/v1/authorize"
TokenEndpoint="https://airtable.com/oauth2/v1/token"
UserinfoEndpoint="https://api.airtable.com/v0/meta/whoami">
UserInfoEndpoint="https://api.airtable.com/v0/meta/whoami">
<CodeChallengeMethod Value="S256" />
<GrantType Value="authorization_code" />
@ -88,7 +88,7 @@
<Configuration AuthorizationEndpoint="https://www.amazon.com/ap/oa"
DeviceAuthorizationEndpoint="https://api.amazon.com/auth/o2/create/codepair"
TokenEndpoint="https://api.amazon.com/auth/o2/token"
UserinfoEndpoint="https://api.amazon.com/user/profile">
UserInfoEndpoint="https://api.amazon.com/user/profile">
<CodeChallengeMethod Value="plain" />
<CodeChallengeMethod Value="S256" />
@ -144,7 +144,7 @@
<Environment Issuer="https://www.arcgis.com/">
<Configuration AuthorizationEndpoint="https://www.arcgis.com/sharing/rest/oauth2/authorize"
TokenEndpoint="https://www.arcgis.com/sharing/rest/oauth2/token"
UserinfoEndpoint="https://www.arcgis.com/sharing/rest/community/self">
UserInfoEndpoint="https://www.arcgis.com/sharing/rest/community/self">
<CodeChallengeMethod Value="plain" />
<CodeChallengeMethod Value="S256" />
@ -248,7 +248,7 @@
<Environment Issuer="https://launchpad.37signals.com/">
<Configuration AuthorizationEndpoint="https://launchpad.37signals.com/authorization/new"
TokenEndpoint="https://launchpad.37signals.com/authorization/token"
UserinfoEndpoint="https://launchpad.37signals.com/authorization.json">
UserInfoEndpoint="https://launchpad.37signals.com/authorization.json">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -288,7 +288,7 @@
<Environment Issuer="https://bitbucket.org/">
<Configuration AuthorizationEndpoint="https://bitbucket.org/site/oauth2/authorize"
TokenEndpoint="https://bitbucket.org/site/oauth2/access_token"
UserinfoEndpoint="https://api.bitbucket.org/2.0/user">
UserInfoEndpoint="https://api.bitbucket.org/2.0/user">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -308,7 +308,7 @@
<Environment Issuer="https://bitly.com/">
<Configuration AuthorizationEndpoint="https://bitly.com/oauth/authorize"
TokenEndpoint="https://api-ssl.bitly.com/oauth/access_token"
UserinfoEndpoint="https://api-ssl.bitly.com/v4/user">
UserInfoEndpoint="https://api-ssl.bitly.com/v4/user">
<GrantType Value="authorization_code" />
<GrantType Value="password" />
</Configuration>
@ -328,7 +328,7 @@
<Environment Issuer="https://account.box.com/">
<Configuration AuthorizationEndpoint="https://account.box.com/api/oauth2/authorize"
TokenEndpoint="https://api.box.com/oauth2/token"
UserinfoEndpoint="https://api.box.com/2.0/users/me">
UserInfoEndpoint="https://api.box.com/2.0/users/me">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -350,7 +350,7 @@
IntrospectionEndpoint="https://auth.calendly.com/oauth/introspect"
RevocationEndpoint="https://auth.calendly.com/oauth/revoke"
TokenEndpoint="https://auth.calendly.com/oauth/token"
UserinfoEndpoint="https://api.calendly.com/users/me">
UserInfoEndpoint="https://api.calendly.com/users/me">
<CodeChallengeMethod Value="S256" />
<GrantType Value="authorization_code" />
@ -479,7 +479,7 @@
<Environment Issuer="https://deezer.com/">
<Configuration AuthorizationEndpoint="https://connect.deezer.com/oauth/auth.php"
TokenEndpoint="https://connect.deezer.com/oauth/access_token.php"
UserinfoEndpoint="https://api.deezer.com/user/me" />
UserInfoEndpoint="https://api.deezer.com/user/me" />
</Environment>
</Provider>
@ -497,7 +497,7 @@
<Configuration AuthorizationEndpoint="https://www.deviantart.com/oauth2/authorize"
RevocationEndpoint="https://www.deviantart.com/oauth2/revoke"
TokenEndpoint="https://www.deviantart.com/oauth2/token"
UserinfoEndpoint="https://www.deviantart.com/api/v1/oauth2/user/whoami">
UserInfoEndpoint="https://www.deviantart.com/api/v1/oauth2/user/whoami">
<GrantType Value="authorization_code" />
<GrantType Value="client_credentials" />
<GrantType Value="refresh_token" />
@ -519,7 +519,7 @@
<Configuration AuthorizationEndpoint="https://discord.com/oauth2/authorize"
RevocationEndpoint="https://discord.com/api/oauth2/token/revoke"
TokenEndpoint="https://discord.com/api/oauth2/token"
UserinfoEndpoint="https://discord.com/api/oauth2/@me">
UserInfoEndpoint="https://discord.com/api/oauth2/@me">
<CodeChallengeMethod Value="S256" />
<GrantType Value="authorization_code" />
@ -546,7 +546,7 @@
<Environment Issuer="https://disqus.com/">
<Configuration AuthorizationEndpoint="https://disqus.com/api/oauth/2.0/authorize/"
TokenEndpoint="https://disqus.com/api/oauth/2.0/access_token/"
UserinfoEndpoint="https://disqus.com/api/3.0/users/details.json">
UserInfoEndpoint="https://disqus.com/api/3.0/users/details.json">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -612,7 +612,7 @@
<Environment Issuer="{settings.Issuer}">
<Configuration AuthorizationEndpoint="{CreateAbsoluteUri(settings.Issuer, 'api/oauth2/auth')}"
TokenEndpoint="{CreateAbsoluteUri(settings.Issuer, 'api/oauth2/token')}"
UserinfoEndpoint="{CreateAbsoluteUri(settings.Issuer, 'api/v1/current/Me')}">
UserInfoEndpoint="{CreateAbsoluteUri(settings.Issuer, 'api/v1/current/Me')}">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -635,7 +635,7 @@
<Environment Issuer="https://www.facebook.com/">
<Configuration AuthorizationEndpoint="https://www.facebook.com/v16.0/dialog/oauth"
TokenEndpoint="https://graph.facebook.com/v16.0/oauth/access_token"
UserinfoEndpoint="https://graph.facebook.com/v16.0/me">
UserInfoEndpoint="https://graph.facebook.com/v16.0/me">
<CodeChallengeMethod Value="S256" />
</Configuration>
</Environment>
@ -676,7 +676,7 @@
<Environment Issuer="https://www.fitbit.com/">
<Configuration AuthorizationEndpoint="https://www.fitbit.com/oauth2/authorize"
TokenEndpoint="https://api.fitbit.com/oauth2/token"
UserinfoEndpoint="https://api.fitbit.com/1/user/-/profile.json">
UserInfoEndpoint="https://api.fitbit.com/1/user/-/profile.json">
<CodeChallengeMethod Value="plain" />
<CodeChallengeMethod Value="S256" />
@ -704,7 +704,7 @@
<Environment Issuer="https://gitee.com/">
<Configuration AuthorizationEndpoint="https://gitee.com/oauth/authorize"
TokenEndpoint="https://gitee.com/oauth/token"
UserinfoEndpoint="https://gitee.com/api/v5/user">
UserInfoEndpoint="https://gitee.com/api/v5/user">
<GrantType Value="authorization_code" />
<GrantType Value="password" />
<GrantType Value="refresh_token" />
@ -732,7 +732,7 @@
<Configuration AuthorizationEndpoint="https://github.com/login/oauth/authorize"
DeviceAuthorizationEndpoint="https://github.com/login/device/code"
TokenEndpoint="https://github.com/login/oauth/access_token"
UserinfoEndpoint="https://api.github.com/user">
UserInfoEndpoint="https://api.github.com/user">
<GrantType Value="authorization_code" />
<GrantType Value="urn:ietf:params:oauth:grant-type:device_code" />
</Configuration>
@ -781,7 +781,7 @@
<Environment Issuer="https://id.getharvest.com/">
<Configuration AuthorizationEndpoint="https://id.getharvest.com/oauth2/authorize"
TokenEndpoint="https://id.getharvest.com/api/v2/oauth2/token"
UserinfoEndpoint="https://id.getharvest.com/api/v2/accounts">
UserInfoEndpoint="https://id.getharvest.com/api/v2/accounts">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -892,7 +892,7 @@
<Environment Issuer="https://www.kookapp.cn/">
<Configuration AuthorizationEndpoint="https://www.kookapp.cn/app/oauth2/authorize"
TokenEndpoint="https://www.kookapp.cn/api/oauth2/token"
UserinfoEndpoint="https://www.kookapp.cn/api/v3/user/me" />
UserInfoEndpoint="https://www.kookapp.cn/api/v3/user/me" />
<!--
Note: Kook requires sending the "get_user_info" scope to be able to use the userinfo endpoint.
@ -915,7 +915,7 @@
<Environment Name="Production" Issuer="https://www.kroger.com/">
<Configuration AuthorizationEndpoint="https://api.kroger.com/v1/connect/oauth2/authorize"
TokenEndpoint="https://api.kroger.com/v1/connect/oauth2/token"
UserinfoEndpoint="https://api.kroger.com/v1/identity/profile">
UserInfoEndpoint="https://api.kroger.com/v1/identity/profile">
<GrantType Value="authorization_code" />
<GrantType Value="client_credentials" />
<GrantType Value="refresh_token" />
@ -933,7 +933,7 @@
<Environment Name="Certification" Issuer="https://www.kroger.com/">
<Configuration AuthorizationEndpoint="https://api-ce.kroger.com/v1/connect/oauth2/authorize"
TokenEndpoint="https://api-ce.kroger.com/v1/connect/oauth2/token"
UserinfoEndpoint="https://api-ce.kroger.com/v1/identity/profile">
UserInfoEndpoint="https://api-ce.kroger.com/v1/identity/profile">
<GrantType Value="authorization_code" />
<GrantType Value="client_credentials" />
<GrantType Value="refresh_token" />
@ -966,7 +966,7 @@
<Environment Issuer="https://passport.{(settings.Region?.ToUpperInvariant() is 'CN' ? 'feishu.cn' : 'larksuite.com')}/">
<Configuration AuthorizationEndpoint="https://passport.{(settings.Region?.ToUpperInvariant() is 'CN' ? 'feishu.cn' : 'larksuite.com')}/suite/passport/oauth/authorize"
TokenEndpoint="https://passport.{(settings.Region?.ToUpperInvariant() is 'CN' ? 'feishu.cn' : 'larksuite.com')}/suite/passport/oauth/token"
UserinfoEndpoint="https://passport.{(settings.Region?.ToUpperInvariant() is 'CN' ? 'feishu.cn' : 'larksuite.com')}/suite/passport/oauth/userinfo">
UserInfoEndpoint="https://passport.{(settings.Region?.ToUpperInvariant() is 'CN' ? 'feishu.cn' : 'larksuite.com')}/suite/passport/oauth/userinfo">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -988,7 +988,7 @@
<Environment Issuer="https://lichess.org/">
<Configuration AuthorizationEndpoint="https://lichess.org/oauth"
TokenEndpoint="https://lichess.org/api/token"
UserinfoEndpoint="https://lichess.org/api/account">
UserInfoEndpoint="https://lichess.org/api/account">
<CodeChallengeMethod Value="S256" />
</Configuration>
</Environment>
@ -1026,7 +1026,7 @@
<Environment Issuer="https://login.mailchimp.com/">
<Configuration AuthorizationEndpoint="https://login.mailchimp.com/oauth2/authorize"
TokenEndpoint="https://login.mailchimp.com/oauth2/token"
UserinfoEndpoint="https://login.mailchimp.com/oauth2/metadata" />
UserInfoEndpoint="https://login.mailchimp.com/oauth2/metadata" />
</Environment>
</Provider>
@ -1048,7 +1048,7 @@
<Environment Issuer="{settings.Issuer}">
<Configuration AuthorizationEndpoint="{CreateAbsoluteUri(settings.Issuer, 'oauth/authorize')}"
TokenEndpoint="{CreateAbsoluteUri(settings.Issuer, 'oauth/token')}"
UserinfoEndpoint="{CreateAbsoluteUri(settings.Issuer, 'api/v1/accounts/verify_credentials')}">
UserInfoEndpoint="{CreateAbsoluteUri(settings.Issuer, 'api/v1/accounts/verify_credentials')}">
<GrantType Value="authorization_code" />
<GrantType Value="client_credentials" />
<GrantType Value="password" />
@ -1072,7 +1072,7 @@
<Environment Issuer="https://www.meetup.com/">
<Configuration AuthorizationEndpoint="https://secure.meetup.com/oauth2/authorize"
TokenEndpoint="https://secure.meetup.com/oauth2/access"
UserinfoEndpoint="https://api.meetup.com/gql">
UserInfoEndpoint="https://api.meetup.com/gql">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -1133,7 +1133,7 @@
<Environment Issuer="https://www.mixcloud.com/">
<Configuration AuthorizationEndpoint="https://www.mixcloud.com/oauth/authorize"
TokenEndpoint="https://www.mixcloud.com/oauth/access_token"
UserinfoEndpoint="https://api.mixcloud.com/me" />
UserInfoEndpoint="https://api.mixcloud.com/me" />
</Environment>
</Provider>
@ -1151,7 +1151,7 @@
<Configuration AuthorizationEndpoint="https://musicbrainz.org/oauth2/authorize"
RevocationEndpoint="https://musicbrainz.org/oauth2/revoke"
TokenEndpoint="https://musicbrainz.org/oauth2/token"
UserinfoEndpoint="https://musicbrainz.org/oauth2/userinfo">
UserInfoEndpoint="https://musicbrainz.org/oauth2/userinfo">
<CodeChallengeMethod Value="plain" />
<CodeChallengeMethod Value="S256" />
@ -1186,7 +1186,7 @@
<Environment Issuer="{settings.Issuer}">
<Configuration AuthorizationEndpoint="{CreateAbsoluteUri(settings.Issuer, 'index.php/apps/oauth2/authorize')}"
TokenEndpoint="{CreateAbsoluteUri(settings.Issuer, 'index.php/apps/oauth2/api/v1/token')}"
UserinfoEndpoint="{CreateAbsoluteUri(settings.Issuer, 'ocs/v2.php/cloud/user?format=json')}">
UserInfoEndpoint="{CreateAbsoluteUri(settings.Issuer, 'ocs/v2.php/cloud/user?format=json')}">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -1209,7 +1209,7 @@
<Environment Issuer="https://www.notion.com/">
<Configuration AuthorizationEndpoint="https://api.notion.com/v1/oauth/authorize"
TokenEndpoint="https://api.notion.com/v1/oauth/token"
UserinfoEndpoint="https://api.notion.com/v1/users/me">
UserInfoEndpoint="https://api.notion.com/v1/users/me">
<TokenEndpointAuthMethod Value="client_secret_basic" />
</Configuration>
</Environment>
@ -1275,7 +1275,7 @@
<Environment Issuer="https://www.patreon.com/">
<Configuration AuthorizationEndpoint="https://www.patreon.com/oauth2/authorize"
TokenEndpoint="https://www.patreon.com/api/oauth2/token"
UserinfoEndpoint="https://www.patreon.com/api/oauth2/v2/identity">
UserInfoEndpoint="https://www.patreon.com/api/oauth2/v2/identity">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -1353,7 +1353,7 @@
<Environment Issuer="https://www.pipedrive.com/">
<Configuration AuthorizationEndpoint="https://oauth.pipedrive.com/oauth/authorize"
TokenEndpoint="https://oauth.pipedrive.com/oauth/token"
UserinfoEndpoint="https://api.pipedrive.com/v1/users/me">
UserInfoEndpoint="https://api.pipedrive.com/v1/users/me">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
@ -1424,7 +1424,7 @@
<Configuration AuthorizationEndpoint="https://www.reddit.com/api/v1/authorize"
RevocationEndpoint="https://www.reddit.com/api/v1/revoke_token"
TokenEndpoint="https://www.reddit.com/api/v1/access_token"
UserinfoEndpoint="https://oauth.reddit.com/api/v1/me">
UserInfoEndpoint="https://oauth.reddit.com/api/v1/me">
<GrantType Value="authorization_code" />
<GrantType Value="client_credentials" />
<GrantType Value="refresh_token" />
@ -1477,7 +1477,7 @@
<Environment Name="Production" Issuer="https://servicechannel.com/">
<Configuration AuthorizationEndpoint="https://login.servicechannel.com/oauth/authorize"
TokenEndpoint="https://login.servicechannel.com/oauth/token"
UserinfoEndpoint="https://api.servicechannel.com/v3/users/current/profile">
UserInfoEndpoint="https://api.servicechannel.com/v3/users/current/profile">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
@ -1488,7 +1488,7 @@
<Environment Name="Sandbox" Issuer="https://servicechannel.com/">
<Configuration AuthorizationEndpoint="https://sb2login.servicechannel.com/oauth/authorize"
TokenEndpoint="https://sb2login.servicechannel.com/oauth/token"
UserinfoEndpoint="https://sb2api.servicechannel.com/v3/users/current/profile">
UserInfoEndpoint="https://sb2api.servicechannel.com/v3/users/current/profile">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
@ -1566,7 +1566,7 @@
<Environment Issuer="https://www.smartsheet.com/">
<Configuration AuthorizationEndpoint="https://app.smartsheet.com/b/authorize"
TokenEndpoint="https://api.smartsheet.com/2.0/token"
UserinfoEndpoint="https://api.smartsheet.com/2.0/users/me">
UserInfoEndpoint="https://api.smartsheet.com/2.0/users/me">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -1586,7 +1586,7 @@
<Environment Issuer="https://accounts.spotify.com/">
<Configuration AuthorizationEndpoint="https://accounts.spotify.com/authorize"
TokenEndpoint="https://accounts.spotify.com/api/token"
UserinfoEndpoint="https://api.spotify.com/v1/me">
UserInfoEndpoint="https://api.spotify.com/v1/me">
<CodeChallengeMethod Value="S256" />
<GrantType Value="authorization_code" />
@ -1609,7 +1609,7 @@
<Environment Issuer="https://api.stackexchange.com/">
<Configuration AuthorizationEndpoint="https://stackoverflow.com/oauth"
TokenEndpoint="https://stackoverflow.com/oauth/access_token/json"
UserinfoEndpoint="https://api.stackexchange.com/2.3/me" />
UserInfoEndpoint="https://api.stackexchange.com/2.3/me" />
</Environment>
<Setting PropertyName="ApplicationKey" ParameterName="key" Type="String" Required="true"
@ -1694,7 +1694,7 @@
<Environment Issuer="https://streamlabs.com/">
<Configuration AuthorizationEndpoint="https://streamlabs.com/api/v2.0/authorize"
TokenEndpoint="https://streamlabs.com/api/v2.0/token"
UserinfoEndpoint="https://streamlabs.com/api/v2.0/user">
UserInfoEndpoint="https://streamlabs.com/api/v2.0/user">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -1713,7 +1713,7 @@
<Environment Issuer="https://www.subscribestar.com/">
<Configuration AuthorizationEndpoint="https://www.subscribestar.com/oauth2/authorize"
TokenEndpoint="https://www.subscribestar.com/oauth2/token"
UserinfoEndpoint="https://www.subscribestar.com/api/graphql/v1">
UserInfoEndpoint="https://www.subscribestar.com/api/graphql/v1">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -1783,7 +1783,7 @@
<Environment Issuer="https://todoist.com/">
<Configuration AuthorizationEndpoint="https://todoist.com/oauth/authorize"
TokenEndpoint="https://todoist.com/oauth/access_token"
UserinfoEndpoint="https://api.todoist.com/sync/v9/sync" />
UserInfoEndpoint="https://api.todoist.com/sync/v9/sync" />
<!--
Note: Todoist requires sending the "data:read" scope to be able to use the userinfo endpoint.
@ -1807,7 +1807,7 @@
<Configuration AuthorizationEndpoint="https://trakt.tv/oauth/authorize"
RevocationEndpoint="https://api.trakt.tv/oauth/revoke"
TokenEndpoint="https://api.trakt.tv/oauth/token"
UserinfoEndpoint="https://api.trakt.tv/users/me">
UserInfoEndpoint="https://api.trakt.tv/users/me">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -1833,7 +1833,7 @@
<Configuration AuthorizationEndpoint="https://open.trovo.live/page/login.html"
TokenEndpoint="https://open-api.trovo.live/openplatform/exchangetoken"
UserinfoEndpoint="https://open-api.trovo.live/openplatform/getuserinfo">
UserInfoEndpoint="https://open-api.trovo.live/openplatform/getuserinfo">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -1859,7 +1859,7 @@
<Environment Issuer="https://www.tumblr.com/">
<Configuration AuthorizationEndpoint="https://www.tumblr.com/oauth2/authorize"
TokenEndpoint="https://api.tumblr.com/v2/oauth2/token"
UserinfoEndpoint="https://api.tumblr.com/v2/user/info">
UserInfoEndpoint="https://api.tumblr.com/v2/user/info">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -1891,7 +1891,7 @@
<Environment Issuer="https://twitter.com/">
<Configuration AuthorizationEndpoint="https://twitter.com/i/oauth2/authorize"
TokenEndpoint="https://api.twitter.com/2/oauth2/token"
UserinfoEndpoint="https://api.twitter.com/2/users/me">
UserInfoEndpoint="https://api.twitter.com/2/users/me">
<CodeChallengeMethod Value="plain" />
<CodeChallengeMethod Value="S256" />
@ -1971,7 +1971,7 @@
<Environment Issuer="https://www.typeform.com/">
<Configuration AuthorizationEndpoint="https://api.typeform.com/oauth/authorize"
TokenEndpoint="https://api.typeform.com/oauth/token"
UserinfoEndpoint="https://api.typeform.com/me">
UserInfoEndpoint="https://api.typeform.com/me">
<GrantType Value="authorization_code" />
<GrantType Value="refresh_token" />
</Configuration>
@ -2010,7 +2010,7 @@
<Environment Issuer="https://api.vimeo.com/">
<Configuration AuthorizationEndpoint="https://api.vimeo.com/oauth/authorize"
TokenEndpoint="https://api.vimeo.com/oauth/access_token"
UserinfoEndpoint="https://api.vimeo.com/me" />
UserInfoEndpoint="https://api.vimeo.com/me" />
</Environment>
</Provider>
@ -2048,7 +2048,7 @@
<Configuration AuthorizationEndpoint="https://api.weibo.com/oauth2/authorize"
RevocationEndpoint="https://api.weibo.com/oauth2/revokeoauth2"
TokenEndpoint="https://api.weibo.com/oauth2/access_token"
UserinfoEndpoint="https://api.weibo.com/2/users/show.json" />
UserInfoEndpoint="https://api.weibo.com/2/users/show.json" />
</Environment>
<Setting PropertyName="Display" ParameterName="display" Type="String" Required="false"
@ -2074,7 +2074,7 @@
<Environment Issuer="https://www.wikimedia.org/">
<Configuration AuthorizationEndpoint="https://meta.wikimedia.org/w/rest.php/oauth2/authorize"
TokenEndpoint="https://meta.wikimedia.org/w/rest.php/oauth2/access_token"
UserinfoEndpoint="https://meta.wikimedia.org/w/rest.php/oauth2/resource/profile">
UserInfoEndpoint="https://meta.wikimedia.org/w/rest.php/oauth2/resource/profile">
<GrantType Value="authorization_code" />
<GrantType Value="client_credentials" />
<GrantType Value="refresh_token" />
@ -2094,7 +2094,7 @@
<Environment Issuer="https://wordpress.com/">
<Configuration AuthorizationEndpoint="https://public-api.wordpress.com/oauth2/authorize"
TokenEndpoint="https://public-api.wordpress.com/oauth2/token"
UserinfoEndpoint="https://public-api.wordpress.com/rest/v1/me" />
UserInfoEndpoint="https://public-api.wordpress.com/rest/v1/me" />
<!--
Note: by default, if no specific scope is requested, an unlimited access is granted by
WordPress. To avoid that, the special "auth" scope (that shouldn't be used with any
@ -2210,7 +2210,7 @@
<Configuration AuthorizationEndpoint="https://zoom.us/oauth/authorize"
RevocationEndpoint="https://zoom.us/oauth/revoke"
TokenEndpoint="https://zoom.us/oauth/token"
UserinfoEndpoint="https://api.zoom.us/v2/users/me">
UserInfoEndpoint="https://api.zoom.us/v2/users/me">
<CodeChallengeMethod Value="plain" />
<CodeChallengeMethod Value="S256" />

2
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xsd

@ -251,7 +251,7 @@
</xs:annotation>
</xs:attribute>
<xs:attribute name="UserinfoEndpoint" type="xs:string" use="optional">
<xs:attribute name="UserInfoEndpoint" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>The userinfo endpoint offered by the environment.</xs:documentation>
</xs:annotation>

56
src/OpenIddict.Client/OpenIddictClientBuilder.cs

@ -973,11 +973,11 @@ public sealed class OpenIddictClientBuilder
}
/// <summary>
/// Enables device code flow support. For more information about this
/// Enables device authorization flow support. For more information about this
/// specific OAuth 2.0 flow, visit https://tools.ietf.org/html/rfc8628.
/// </summary>
/// <returns>The <see cref="OpenIddictClientBuilder"/> instance.</returns>
public OpenIddictClientBuilder AllowDeviceCodeFlow()
public OpenIddictClientBuilder AllowDeviceAuthorizationFlow()
=> Configure(options => options.GrantTypes.Add(GrantTypes.DeviceCode));
/// <summary>
@ -1063,18 +1063,12 @@ public sealed class OpenIddictClientBuilder
=> Configure(options => options.GrantTypes.Add(GrantTypes.RefreshToken));
/// <summary>
/// Sets the relative or absolute URIs associated to the redirection endpoint.
/// Sets the relative or absolute URIs associated to the post-logout redirection endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// </summary>
/// <remarks>
/// Note: to mitigate mix-up attacks, it's recommended to use a unique redirection endpoint
/// URI per provider, unless all the registered providers support returning an "iss" parameter
/// containing their identity as part of authorization responses. For more information,
/// see https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.4.
/// </remarks>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictClientBuilder"/> instance.</returns>
public OpenIddictClientBuilder SetRedirectionEndpointUris(
public OpenIddictClientBuilder SetPostLogoutRedirectionEndpointUris(
[StringSyntax(StringSyntaxAttribute.Uri)] params string[] uris)
{
if (uris is null)
@ -1082,22 +1076,16 @@ public sealed class OpenIddictClientBuilder
throw new ArgumentNullException(nameof(uris));
}
return SetRedirectionEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
return SetPostLogoutRedirectionEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
}
/// <summary>
/// Sets the relative or absolute URIs associated to the redirection endpoint.
/// Sets the relative or absolute URIs associated to the post-logout redirection endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// </summary>
/// <remarks>
/// Note: to mitigate mix-up attacks, it's recommended to use a unique redirection endpoint
/// URI per provider, unless all the registered providers support returning an "iss" parameter
/// containing their identity as part of authorization responses. For more information,
/// see https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.4.
/// </remarks>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictClientBuilder"/> instance.</returns>
public OpenIddictClientBuilder SetRedirectionEndpointUris(params Uri[] uris)
public OpenIddictClientBuilder SetPostLogoutRedirectionEndpointUris(params Uri[] uris)
{
if (uris is null)
{
@ -1116,18 +1104,24 @@ public sealed class OpenIddictClientBuilder
return Configure(options =>
{
options.RedirectionEndpointUris.Clear();
options.RedirectionEndpointUris.AddRange(uris);
options.PostLogoutRedirectionEndpointUris.Clear();
options.PostLogoutRedirectionEndpointUris.AddRange(uris);
});
}
/// <summary>
/// Sets the relative or absolute URIs associated to the post-logout redirection endpoint.
/// Sets the relative or absolute URIs associated to the redirection endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// </summary>
/// <remarks>
/// Note: to mitigate mix-up attacks, it's recommended to use a unique redirection endpoint
/// URI per provider, unless all the registered providers support returning an "iss" parameter
/// containing their identity as part of authorization responses. For more information,
/// see https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.4.
/// </remarks>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictClientBuilder"/> instance.</returns>
public OpenIddictClientBuilder SetPostLogoutRedirectionEndpointUris(
public OpenIddictClientBuilder SetRedirectionEndpointUris(
[StringSyntax(StringSyntaxAttribute.Uri)] params string[] uris)
{
if (uris is null)
@ -1135,16 +1129,22 @@ public sealed class OpenIddictClientBuilder
throw new ArgumentNullException(nameof(uris));
}
return SetPostLogoutRedirectionEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
return SetRedirectionEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
}
/// <summary>
/// Sets the relative or absolute URIs associated to the post-logout redirection endpoint.
/// Sets the relative or absolute URIs associated to the redirection endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// </summary>
/// <remarks>
/// Note: to mitigate mix-up attacks, it's recommended to use a unique redirection endpoint
/// URI per provider, unless all the registered providers support returning an "iss" parameter
/// containing their identity as part of authorization responses. For more information,
/// see https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.4.
/// </remarks>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictClientBuilder"/> instance.</returns>
public OpenIddictClientBuilder SetPostLogoutRedirectionEndpointUris(params Uri[] uris)
public OpenIddictClientBuilder SetRedirectionEndpointUris(params Uri[] uris)
{
if (uris is null)
{
@ -1163,8 +1163,8 @@ public sealed class OpenIddictClientBuilder
return Configure(options =>
{
options.PostLogoutRedirectionEndpointUris.Clear();
options.PostLogoutRedirectionEndpointUris.AddRange(uris);
options.RedirectionEndpointUris.Clear();
options.RedirectionEndpointUris.AddRange(uris);
});
}

2
src/OpenIddict.Client/OpenIddictClientConfiguration.cs

@ -122,7 +122,7 @@ public sealed class OpenIddictClientConfiguration : IPostConfigureOptions<OpenId
else
{
if (!options.Handlers.Exists(static descriptor => descriptor.ContextType == typeof(ApplyConfigurationRequestContext)) ||
!options.Handlers.Exists(static descriptor => descriptor.ContextType == typeof(ApplyCryptographyRequestContext)))
!options.Handlers.Exists(static descriptor => descriptor.ContextType == typeof(ApplyJsonWebKeySetRequestContext)))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0313));
}

40
src/OpenIddict.Client/OpenIddictClientEvents.Discovery.cs

@ -123,15 +123,15 @@ public static partial class OpenIddictClientEvents
}
/// <summary>
/// Represents an event called for each request to the cryptography endpoint
/// to give the user code a chance to add parameters to the cryptography request.
/// Represents an event called for each request to the JSON Web Key Set endpoint
/// to give the user code a chance to add parameters to the JSON Web Key Set request.
/// </summary>
public sealed class PrepareCryptographyRequestContext : BaseExternalContext
public sealed class PrepareJsonWebKeySetRequestContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="PrepareCryptographyRequestContext"/> class.
/// Creates a new instance of the <see cref="PrepareJsonWebKeySetRequestContext"/> class.
/// </summary>
public PrepareCryptographyRequestContext(OpenIddictClientTransaction transaction)
public PrepareJsonWebKeySetRequestContext(OpenIddictClientTransaction transaction)
: base(transaction)
{
}
@ -147,15 +147,15 @@ public static partial class OpenIddictClientEvents
}
/// <summary>
/// Represents an event called for each request to the cryptography endpoint
/// to send the cryptography request to the remote authorization server.
/// Represents an event called for each request to the JSON Web Key Set endpoint
/// to send the JSON Web Key Set request to the remote authorization server.
/// </summary>
public sealed class ApplyCryptographyRequestContext : BaseExternalContext
public sealed class ApplyJsonWebKeySetRequestContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="ApplyCryptographyRequestContext"/> class.
/// Creates a new instance of the <see cref="ApplyJsonWebKeySetRequestContext"/> class.
/// </summary>
public ApplyCryptographyRequestContext(OpenIddictClientTransaction transaction)
public ApplyJsonWebKeySetRequestContext(OpenIddictClientTransaction transaction)
: base(transaction)
{
}
@ -171,15 +171,15 @@ public static partial class OpenIddictClientEvents
}
/// <summary>
/// Represents an event called for each cryptography response
/// Represents an event called for each JSON Web Key Set response
/// to extract the response parameters from the server response.
/// </summary>
public sealed class ExtractCryptographyResponseContext : BaseExternalContext
public sealed class ExtractJsonWebKeySetResponseContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="ExtractCryptographyResponseContext"/> class.
/// Creates a new instance of the <see cref="ExtractJsonWebKeySetResponseContext"/> class.
/// </summary>
public ExtractCryptographyResponseContext(OpenIddictClientTransaction transaction)
public ExtractJsonWebKeySetResponseContext(OpenIddictClientTransaction transaction)
: base(transaction)
{
}
@ -204,14 +204,14 @@ public static partial class OpenIddictClientEvents
}
/// <summary>
/// Represents an event called for each validated cryptography response.
/// Represents an event called for each validated JSON Web Key Set response.
/// </summary>
public sealed class HandleCryptographyResponseContext : BaseExternalContext
public sealed class HandleJsonWebKeySetResponseContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="HandleCryptographyResponseContext"/> class.
/// Creates a new instance of the <see cref="HandleJsonWebKeySetResponseContext"/> class.
/// </summary>
public HandleCryptographyResponseContext(OpenIddictClientTransaction transaction)
public HandleJsonWebKeySetResponseContext(OpenIddictClientTransaction transaction)
: base(transaction)
{
}
@ -235,8 +235,8 @@ public static partial class OpenIddictClientEvents
}
/// <summary>
/// Gets the security keys.
/// Gets the JSON Web Key Set.
/// </summary>
public JsonWebKeySet SecurityKeys { get; } = new JsonWebKeySet();
public JsonWebKeySet JsonWebKeySet { get; } = new JsonWebKeySet();
}
}

24
src/OpenIddict.Client/OpenIddictClientEvents.Session.cs

@ -11,15 +11,15 @@ namespace OpenIddict.Client;
public static partial class OpenIddictClientEvents
{
/// <summary>
/// Represents an event called for each request to the logout endpoint to give the user code
/// a chance to manually update the logout request before it is sent to the identity provider.
/// Represents an event called for each request to the end session endpoint to give the user code
/// a chance to manually update the end session request before it is sent to the identity provider.
/// </summary>
public sealed class PrepareLogoutRequestContext : BaseValidatingContext
public sealed class PrepareEndSessionRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="PrepareLogoutRequestContext"/> class.
/// Creates a new instance of the <see cref="PrepareEndSessionRequestContext"/> class.
/// </summary>
public PrepareLogoutRequestContext(OpenIddictClientTransaction transaction)
public PrepareEndSessionRequestContext(OpenIddictClientTransaction transaction)
: base(transaction)
{
}
@ -40,15 +40,15 @@ public static partial class OpenIddictClientEvents
}
/// <summary>
/// Represents an event called for each request to the logout endpoint
/// to give the user code a chance to manually send the logout request.
/// Represents an event called for each request to the end session endpoint
/// to give the user code a chance to manually send the end session request.
/// </summary>
public sealed class ApplyLogoutRequestContext : BaseValidatingContext
public sealed class ApplyEndSessionRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="PrepareLogoutRequestContext"/> class.
/// Creates a new instance of the <see cref="PrepareEndSessionRequestContext"/> class.
/// </summary>
public ApplyLogoutRequestContext(OpenIddictClientTransaction transaction)
public ApplyEndSessionRequestContext(OpenIddictClientTransaction transaction)
: base(transaction)
{
}
@ -75,8 +75,8 @@ public static partial class OpenIddictClientEvents
}
/// <summary>
/// Represents an event called for each request to the post-logout redirection endpoint to give the user code
/// a chance to manually extract the redirection request from the ambient HTTP context.
/// Represents an event called for each request to the post-logout redirection endpoint to give the
/// user code a chance to manually extract the redirection request from the ambient HTTP context.
/// </summary>
public sealed class ExtractPostLogoutRedirectionRequestContext : BaseValidatingContext
{

28
src/OpenIddict.Client/OpenIddictClientEvents.Userinfo.cs

@ -14,12 +14,12 @@ public static partial class OpenIddictClientEvents
/// Represents an event called for each request to the userinfo endpoint
/// to give the user code a chance to add parameters to the userinfo request.
/// </summary>
public sealed class PrepareUserinfoRequestContext : BaseExternalContext
public sealed class PrepareUserInfoRequestContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="PrepareUserinfoRequestContext"/> class.
/// Creates a new instance of the <see cref="PrepareUserInfoRequestContext"/> class.
/// </summary>
public PrepareUserinfoRequestContext(OpenIddictClientTransaction transaction)
public PrepareUserInfoRequestContext(OpenIddictClientTransaction transaction)
: base(transaction)
{
}
@ -38,12 +38,12 @@ public static partial class OpenIddictClientEvents
/// Represents an event called for each request to the userinfo endpoint
/// to send the userinfo request to the remote authorization server.
/// </summary>
public sealed class ApplyUserinfoRequestContext : BaseExternalContext
public sealed class ApplyUserInfoRequestContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="ApplyUserinfoRequestContext"/> class.
/// Creates a new instance of the <see cref="ApplyUserInfoRequestContext"/> class.
/// </summary>
public ApplyUserinfoRequestContext(OpenIddictClientTransaction transaction)
public ApplyUserInfoRequestContext(OpenIddictClientTransaction transaction)
: base(transaction)
{
}
@ -62,12 +62,12 @@ public static partial class OpenIddictClientEvents
/// Represents an event called for each userinfo response
/// to extract the response parameters from the server response.
/// </summary>
public sealed class ExtractUserinfoResponseContext : BaseExternalContext
public sealed class ExtractUserInfoResponseContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="ExtractUserinfoResponseContext"/> class.
/// Creates a new instance of the <see cref="ExtractUserInfoResponseContext"/> class.
/// </summary>
public ExtractUserinfoResponseContext(OpenIddictClientTransaction transaction)
public ExtractUserInfoResponseContext(OpenIddictClientTransaction transaction)
: base(transaction)
{
}
@ -93,18 +93,18 @@ public static partial class OpenIddictClientEvents
/// <summary>
/// Gets or sets the userinfo token, if available.
/// </summary>
public string? UserinfoToken { get; set; }
public string? UserInfoToken { get; set; }
}
/// <summary>
/// Represents an event called for each userinfo response.
/// </summary>
public sealed class HandleUserinfoResponseContext : BaseExternalContext
public sealed class HandleUserInfoResponseContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="HandleUserinfoResponseContext"/> class.
/// Creates a new instance of the <see cref="HandleUserInfoResponseContext"/> class.
/// </summary>
public HandleUserinfoResponseContext(OpenIddictClientTransaction transaction)
public HandleUserInfoResponseContext(OpenIddictClientTransaction transaction)
: base(transaction)
{
}
@ -130,7 +130,7 @@ public static partial class OpenIddictClientEvents
/// <summary>
/// Gets or sets the userinfo token, if available.
/// </summary>
public string? UserinfoToken { get; set; }
public string? UserInfoToken { get; set; }
/// <summary>
/// Gets or sets the principal containing the claims resolved from the userinfo response.

24
src/OpenIddict.Client/OpenIddictClientEvents.cs

@ -373,7 +373,7 @@ public static partial class OpenIddictClientEvents
/// <summary>
/// Gets or sets the URI of the userinfo endpoint, if applicable.
/// </summary>
public Uri? UserinfoEndpoint { get; set; }
public Uri? UserInfoEndpoint { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether a token request should be sent.
@ -383,7 +383,7 @@ public static partial class OpenIddictClientEvents
/// <summary>
/// Gets or sets a boolean indicating whether a token request should be sent.
/// </summary>
public bool SendUserinfoRequest { get; set; }
public bool SendUserInfoRequest { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether an authorization
@ -455,7 +455,7 @@ public static partial class OpenIddictClientEvents
/// <remarks>
/// Note: overriding the value of this property is generally not recommended.
/// </remarks>
public bool ExtractUserinfoToken { get; set; }
public bool ExtractUserInfoToken { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether an authorization
@ -527,7 +527,7 @@ public static partial class OpenIddictClientEvents
/// <remarks>
/// Note: overriding the value of this property is generally not recommended.
/// </remarks>
public bool RequireUserinfoToken { get; set; }
public bool RequireUserInfoToken { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the authorization
@ -599,7 +599,7 @@ public static partial class OpenIddictClientEvents
/// <remarks>
/// Note: overriding the value of this property is generally not recommended.
/// </remarks>
public bool ValidateUserinfoToken { get; set; }
public bool ValidateUserInfoToken { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether an invalid authorization code
@ -671,7 +671,7 @@ public static partial class OpenIddictClientEvents
/// <remarks>
/// Note: overriding the value of this property is generally not recommended.
/// </remarks>
public bool RejectUserinfoToken { get; set; }
public bool RejectUserInfoToken { get; set; }
/// <summary>
/// Gets or sets the authorization code to validate, if applicable.
@ -736,7 +736,7 @@ public static partial class OpenIddictClientEvents
/// <summary>
/// Gets or sets the userinfo token to validate, if applicable.
/// </summary>
public string? UserinfoToken { get; set; }
public string? UserInfoToken { get; set; }
/// <summary>
/// Gets or sets the principal extracted from the authorization code, if applicable.
@ -781,7 +781,7 @@ public static partial class OpenIddictClientEvents
/// <summary>
/// Gets or sets the principal extracted from the userinfo token, if applicable.
/// </summary>
public ClaimsPrincipal? UserinfoTokenPrincipal { get; set; }
public ClaimsPrincipal? UserInfoTokenPrincipal { get; set; }
/// <summary>
/// Gets or sets the request sent to the token endpoint, if applicable.
@ -796,12 +796,12 @@ public static partial class OpenIddictClientEvents
/// <summary>
/// Gets or sets the request sent to the userinfo endpoint, if applicable.
/// </summary>
public OpenIddictRequest? UserinfoRequest { get; set; }
public OpenIddictRequest? UserInfoRequest { get; set; }
/// <summary>
/// Gets or sets the response returned by the userinfo endpoint, if applicable.
/// </summary>
public OpenIddictResponse? UserinfoResponse { get; set; }
public OpenIddictResponse? UserInfoResponse { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether a client assertion
@ -862,7 +862,7 @@ public static partial class OpenIddictClientEvents
/// <summary>
/// Gets or sets a boolean indicating whether userinfo retrieval should be disabled.
/// </summary>
public bool DisableUserinfoRetrieval { get; set; }
public bool DisableUserInfoRetrieval { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether userinfo validation should be disabled.
@ -870,7 +870,7 @@ public static partial class OpenIddictClientEvents
/// <remarks>
/// Note: overriding the value of this property is generally not recommended.
/// </remarks>
public bool DisableUserinfoValidation { get; set; }
public bool DisableUserInfoValidation { get; set; }
}
/// <summary>

8
src/OpenIddict.Client/OpenIddictClientExtensions.cs

@ -67,10 +67,10 @@ public static class OpenIddictClientExtensions
builder.Services.TryAddSingleton<RequireTokenPayloadPersisted>();
builder.Services.TryAddSingleton<RequireTokenRequest>();
builder.Services.TryAddSingleton<RequireTokenStorageEnabled>();
builder.Services.TryAddSingleton<RequireUserinfoRequest>();
builder.Services.TryAddSingleton<RequireUserinfoTokenExtracted>();
builder.Services.TryAddSingleton<RequireUserinfoTokenPrincipal>();
builder.Services.TryAddSingleton<RequireUserinfoValidationEnabled>();
builder.Services.TryAddSingleton<RequireUserInfoRequest>();
builder.Services.TryAddSingleton<RequireUserInfoTokenExtracted>();
builder.Services.TryAddSingleton<RequireUserInfoTokenPrincipal>();
builder.Services.TryAddSingleton<RequireUserInfoValidationEnabled>();
builder.Services.TryAddSingleton<RequireWebServicesFederationClaimMappingEnabled>();
// Register the built-in client event handlers used by the OpenIddict client components.

16
src/OpenIddict.Client/OpenIddictClientHandlerFilters.cs

@ -561,7 +561,7 @@ public static class OpenIddictClientHandlerFilters
/// <summary>
/// Represents a filter that excludes the associated handlers if no userinfo request is expected to be sent.
/// </summary>
public sealed class RequireUserinfoRequest : IOpenIddictClientHandlerFilter<ProcessAuthenticationContext>
public sealed class RequireUserInfoRequest : IOpenIddictClientHandlerFilter<ProcessAuthenticationContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(ProcessAuthenticationContext context)
@ -571,14 +571,14 @@ public static class OpenIddictClientHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(context.SendUserinfoRequest);
return new(context.SendUserInfoRequest);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if no userinfo token is extracted.
/// </summary>
public sealed class RequireUserinfoTokenExtracted : IOpenIddictClientHandlerFilter<ProcessAuthenticationContext>
public sealed class RequireUserInfoTokenExtracted : IOpenIddictClientHandlerFilter<ProcessAuthenticationContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(ProcessAuthenticationContext context)
@ -588,14 +588,14 @@ public static class OpenIddictClientHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(context.ExtractUserinfoToken);
return new(context.ExtractUserInfoToken);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if no userinfo token principal is available.
/// </summary>
public sealed class RequireUserinfoTokenPrincipal : IOpenIddictClientHandlerFilter<ProcessAuthenticationContext>
public sealed class RequireUserInfoTokenPrincipal : IOpenIddictClientHandlerFilter<ProcessAuthenticationContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(ProcessAuthenticationContext context)
@ -605,14 +605,14 @@ public static class OpenIddictClientHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(context.UserinfoTokenPrincipal is not null);
return new(context.UserInfoTokenPrincipal is not null);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if userinfo validation was disabled.
/// </summary>
public sealed class RequireUserinfoValidationEnabled : IOpenIddictClientHandlerFilter<ProcessAuthenticationContext>
public sealed class RequireUserInfoValidationEnabled : IOpenIddictClientHandlerFilter<ProcessAuthenticationContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(ProcessAuthenticationContext context)
@ -622,7 +622,7 @@ public static class OpenIddictClientHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(!context.DisableUserinfoValidation);
return new(!context.DisableUserInfoValidation);
}
}

46
src/OpenIddict.Client/OpenIddictClientHandlers.Discovery.cs

@ -30,7 +30,7 @@ public static partial class OpenIddictClientHandlers
ExtractLogoutEndpoint.Descriptor,
ExtractRevocationEndpoint.Descriptor,
ExtractTokenEndpoint.Descriptor,
ExtractUserinfoEndpoint.Descriptor,
ExtractUserInfoEndpoint.Descriptor,
ExtractGrantTypes.Descriptor,
ExtractResponseModes.Descriptor,
ExtractResponseTypes.Descriptor,
@ -108,7 +108,7 @@ public static partial class OpenIddictClientHandlers
Metadata.Issuer or
Metadata.JwksUri or
Metadata.TokenEndpoint or
Metadata.UserinfoEndpoint
Metadata.UserInfoEndpoint
=> ((JsonElement) value).ValueKind is JsonValueKind.String,
// The following parameters MUST be formatted as arrays of strings:
@ -293,7 +293,7 @@ public static partial class OpenIddictClientHandlers
}
/// <summary>
/// Contains the logic responsible for extracting the JWKS endpoint URI from the discovery document.
/// Contains the logic responsible for extracting the JSON Web Key Set endpoint URI from the discovery document.
/// </summary>
public sealed class ExtractCryptographyEndpoint : IOpenIddictClientHandler<HandleConfigurationResponseContext>
{
@ -431,7 +431,7 @@ public static partial class OpenIddictClientHandlers
}
/// <summary>
/// Contains the logic responsible for extracting the logout endpoint URI from the discovery document.
/// Contains the logic responsible for extracting the end session endpoint URI from the discovery document.
/// </summary>
public sealed class ExtractLogoutEndpoint : IOpenIddictClientHandler<HandleConfigurationResponseContext>
{
@ -562,14 +562,14 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for extracting the userinfo endpoint URI from the discovery document.
/// </summary>
public sealed class ExtractUserinfoEndpoint : IOpenIddictClientHandler<HandleConfigurationResponseContext>
public sealed class ExtractUserInfoEndpoint : IOpenIddictClientHandler<HandleConfigurationResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleConfigurationResponseContext>()
.UseSingletonHandler<ExtractUserinfoEndpoint>()
.UseSingletonHandler<ExtractUserInfoEndpoint>()
.SetOrder(ExtractTokenEndpoint.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -582,20 +582,20 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
var endpoint = (string?) context.Response[Metadata.UserinfoEndpoint];
var endpoint = (string?) context.Response[Metadata.UserInfoEndpoint];
if (!string.IsNullOrEmpty(endpoint))
{
if (!Uri.TryCreate(endpoint, UriKind.Absolute, out Uri? uri) || OpenIddictHelpers.IsImplicitFileUri(uri))
{
context.Reject(
error: Errors.ServerError,
description: SR.FormatID2100(Metadata.UserinfoEndpoint),
description: SR.FormatID2100(Metadata.UserInfoEndpoint),
uri: SR.FormatID8000(SR.ID2100));
return default;
}
context.Configuration.UserinfoEndpoint = uri;
context.Configuration.UserInfoEndpoint = uri;
}
return default;
@ -1019,22 +1019,22 @@ public static partial class OpenIddictClientHandlers
}
/// <summary>
/// Contains the logic responsible for validating the well-known parameters contained in the JWKS response.
/// Contains the logic responsible for validating the well-known parameters contained in the JSON Web Key Set response.
/// </summary>
public sealed class ValidateWellKnownCryptographyParameters : IOpenIddictClientHandler<HandleCryptographyResponseContext>
public sealed class ValidateWellKnownCryptographyParameters : IOpenIddictClientHandler<HandleJsonWebKeySetResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleCryptographyResponseContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleJsonWebKeySetResponseContext>()
.UseSingletonHandler<ValidateWellKnownCryptographyParameters>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleCryptographyResponseContext context)
public ValueTask HandleAsync(HandleJsonWebKeySetResponseContext context)
{
if (context is null)
{
@ -1093,22 +1093,22 @@ public static partial class OpenIddictClientHandlers
}
/// <summary>
/// Contains the logic responsible for surfacing potential errors from the cryptography response.
/// Contains the logic responsible for surfacing potential errors from the JSON Web Key Set response.
/// </summary>
public sealed class HandleCryptographyErrorResponse : IOpenIddictClientHandler<HandleCryptographyResponseContext>
public sealed class HandleCryptographyErrorResponse : IOpenIddictClientHandler<HandleJsonWebKeySetResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleCryptographyResponseContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleJsonWebKeySetResponseContext>()
.UseSingletonHandler<HandleCryptographyErrorResponse>()
.SetOrder(ValidateWellKnownCryptographyParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleCryptographyResponseContext context)
public ValueTask HandleAsync(HandleJsonWebKeySetResponseContext context)
{
if (context is null)
{
@ -1136,22 +1136,22 @@ public static partial class OpenIddictClientHandlers
}
/// <summary>
/// Contains the logic responsible for extracting the signing keys from the JWKS document.
/// Contains the logic responsible for extracting the signing keys from the JSON Web Key Set document.
/// </summary>
public sealed class ExtractSigningKeys : IOpenIddictClientHandler<HandleCryptographyResponseContext>
public sealed class ExtractSigningKeys : IOpenIddictClientHandler<HandleJsonWebKeySetResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleCryptographyResponseContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleJsonWebKeySetResponseContext>()
.UseSingletonHandler<ExtractSigningKeys>()
.SetOrder(HandleCryptographyErrorResponse.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleCryptographyResponseContext context)
public ValueTask HandleAsync(HandleJsonWebKeySetResponseContext context)
{
if (context is null)
{
@ -1171,7 +1171,7 @@ public static partial class OpenIddictClientHandlers
for (var index = 0; index < keys.Count; index++)
{
// Note: the "use" parameter is defined as optional by the JWKS specification
// Note: the "use" parameter is defined as optional by the JSON Web Key Set specification
// but is required by the OpenID Connect discovery specification if both signing
// and encryption keys are present in the returned list. If the "use" parameter
// is not explicitly specified or has an empty value, assume it is a signing key.
@ -1261,7 +1261,7 @@ public static partial class OpenIddictClientHandlers
}
}
context.SecurityKeys.Keys.Add(key);
context.JsonWebKeySet.Keys.Add(key);
}
return default;

36
src/OpenIddict.Client/OpenIddictClientHandlers.Session.cs

@ -16,15 +16,15 @@ public static partial class OpenIddictClientHandlers
{
public static ImmutableArray<OpenIddictClientHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create([
/*
* Logout request top-level processing:
* EndSession request top-level processing:
*/
PrepareLogoutRequest.Descriptor,
ApplyLogoutRequest.Descriptor,
PrepareEndSessionRequest.Descriptor,
ApplyEndSessionRequest.Descriptor,
/*
* Logout request processing:
* EndSession request processing:
*/
AttachLogoutEndpoint.Descriptor,
AttachEndSessionEndpoint.Descriptor,
/*
* Post-logout redirection request top-level processing:
@ -44,11 +44,11 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for preparing authorization requests and invoking the corresponding event handlers.
/// </summary>
public sealed class PrepareLogoutRequest : IOpenIddictClientHandler<ProcessSignOutContext>
public sealed class PrepareEndSessionRequest : IOpenIddictClientHandler<ProcessSignOutContext>
{
private readonly IOpenIddictClientDispatcher _dispatcher;
public PrepareLogoutRequest(IOpenIddictClientDispatcher dispatcher)
public PrepareEndSessionRequest(IOpenIddictClientDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -56,7 +56,7 @@ public static partial class OpenIddictClientHandlers
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessSignOutContext>()
.UseScopedHandler<PrepareLogoutRequest>()
.UseScopedHandler<PrepareEndSessionRequest>()
.SetOrder(int.MaxValue - 100_000)
.Build();
@ -68,7 +68,7 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new PrepareLogoutRequestContext(context.Transaction);
var notification = new PrepareEndSessionRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -88,11 +88,11 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for applying authorization requests and invoking the corresponding event handlers.
/// </summary>
public sealed class ApplyLogoutRequest : IOpenIddictClientHandler<ProcessSignOutContext>
public sealed class ApplyEndSessionRequest : IOpenIddictClientHandler<ProcessSignOutContext>
{
private readonly IOpenIddictClientDispatcher _dispatcher;
public ApplyLogoutRequest(IOpenIddictClientDispatcher dispatcher)
public ApplyEndSessionRequest(IOpenIddictClientDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -100,8 +100,8 @@ public static partial class OpenIddictClientHandlers
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessSignOutContext>()
.UseScopedHandler<ApplyLogoutRequest>()
.SetOrder(PrepareLogoutRequest.Descriptor.Order + 1_000)
.UseScopedHandler<ApplyEndSessionRequest>()
.SetOrder(PrepareEndSessionRequest.Descriptor.Order + 1_000)
.Build();
/// <inheritdoc/>
@ -112,7 +112,7 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ApplyLogoutRequestContext(context.Transaction)
var notification = new ApplyEndSessionRequestContext(context.Transaction)
{
// Note: the endpoint URI is automatically set by a specialized handler if it's not set here.
EndSessionEndpoint = context.EndSessionEndpoint?.AbsoluteUri!,
@ -147,19 +147,19 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for attaching the URI of the authorization request to the request.
/// </summary>
public sealed class AttachLogoutEndpoint : IOpenIddictClientHandler<ApplyLogoutRequestContext>
public sealed class AttachEndSessionEndpoint : IOpenIddictClientHandler<ApplyEndSessionRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyLogoutRequestContext>()
.UseSingletonHandler<AttachLogoutEndpoint>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<ApplyEndSessionRequestContext>()
.UseSingletonHandler<AttachEndSessionEndpoint>()
.SetOrder(int.MinValue + 100_000)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyLogoutRequestContext context)
public ValueTask HandleAsync(ApplyEndSessionRequestContext context)
{
if (context is null)
{

26
src/OpenIddict.Client/OpenIddictClientHandlers.Userinfo.cs

@ -14,11 +14,11 @@ namespace OpenIddict.Client;
public static partial class OpenIddictClientHandlers
{
public static class Userinfo
public static class UserInfo
{
public static ImmutableArray<OpenIddictClientHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create([
/*
* Userinfo response handling:
* UserInfo response handling:
*/
ValidateWellKnownParameters.Descriptor,
HandleErrorResponse.Descriptor,
@ -28,20 +28,20 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for validating the well-known parameters contained in the userinfo response.
/// </summary>
public sealed class ValidateWellKnownParameters : IOpenIddictClientHandler<HandleUserinfoResponseContext>
public sealed class ValidateWellKnownParameters : IOpenIddictClientHandler<HandleUserInfoResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleUserinfoResponseContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleUserInfoResponseContext>()
.UseSingletonHandler<ValidateWellKnownParameters>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleUserinfoResponseContext context)
public ValueTask HandleAsync(HandleUserInfoResponseContext context)
{
if (context is null)
{
@ -49,7 +49,7 @@ public static partial class OpenIddictClientHandlers
}
// Ignore the response instance if a userinfo token was extracted.
if (!string.IsNullOrEmpty(context.UserinfoToken))
if (!string.IsNullOrEmpty(context.UserInfoToken))
{
return default;
}
@ -94,20 +94,20 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for surfacing potential errors from the userinfo response.
/// </summary>
public sealed class HandleErrorResponse : IOpenIddictClientHandler<HandleUserinfoResponseContext>
public sealed class HandleErrorResponse : IOpenIddictClientHandler<HandleUserInfoResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleUserinfoResponseContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleUserInfoResponseContext>()
.UseSingletonHandler<HandleErrorResponse>()
.SetOrder(ValidateWellKnownParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleUserinfoResponseContext context)
public ValueTask HandleAsync(HandleUserInfoResponseContext context)
{
if (context is null)
{
@ -140,20 +140,20 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for extracting the claims from the introspection response.
/// </summary>
public sealed class PopulateClaims : IOpenIddictClientHandler<HandleUserinfoResponseContext>
public sealed class PopulateClaims : IOpenIddictClientHandler<HandleUserInfoResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleUserinfoResponseContext>()
= OpenIddictClientHandlerDescriptor.CreateBuilder<HandleUserInfoResponseContext>()
.UseSingletonHandler<PopulateClaims>()
.SetOrder(HandleErrorResponse.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleUserinfoResponseContext context)
public ValueTask HandleAsync(HandleUserInfoResponseContext context)
{
if (context is null)
{
@ -163,7 +163,7 @@ public static partial class OpenIddictClientHandlers
Debug.Assert(context.Registration.Issuer is { IsAbsoluteUri: true }, SR.GetResourceString(SR.ID4013));
// Ignore the response instance if a userinfo token was extracted.
if (!string.IsNullOrEmpty(context.UserinfoToken))
if (!string.IsNullOrEmpty(context.UserInfoToken))
{
return default;
}

180
src/OpenIddict.Client/OpenIddictClientHandlers.cs

@ -86,15 +86,15 @@ public static partial class OpenIddictClientHandlers
ValidateBackchannelAccessToken.Descriptor,
ValidateRefreshToken.Descriptor,
ResolveUserinfoEndpoint.Descriptor,
EvaluateUserinfoRequest.Descriptor,
AttachUserinfoRequestParameters.Descriptor,
SendUserinfoRequest.Descriptor,
EvaluateValidatedUserinfoToken.Descriptor,
ValidateRequiredUserinfoToken.Descriptor,
ValidateUserinfoToken.Descriptor,
ValidateUserinfoTokenWellknownClaims.Descriptor,
ValidateUserinfoTokenSubject.Descriptor,
ResolveUserInfoEndpoint.Descriptor,
EvaluateUserInfoRequest.Descriptor,
AttachUserInfoRequestParameters.Descriptor,
SendUserInfoRequest.Descriptor,
EvaluateValidatedUserInfoToken.Descriptor,
ValidateRequiredUserInfoToken.Descriptor,
ValidateUserInfoToken.Descriptor,
ValidateUserInfoTokenWellknownClaims.Descriptor,
ValidateUserInfoTokenSubject.Descriptor,
PopulateMergedPrincipal.Descriptor,
MapStandardWebServicesFederationClaims.Descriptor,
@ -172,7 +172,7 @@ public static partial class OpenIddictClientHandlers
EvaluateGeneratedLogoutTokens.Descriptor,
AttachSignOutHostProperties.Descriptor,
AttachLogoutNonce.Descriptor,
AttachLogoutRequestForgeryProtection.Descriptor,
AttachEndSessionRequestForgeryProtection.Descriptor,
PrepareLogoutStateTokenPrincipal.Descriptor,
GenerateLogoutStateToken.Descriptor,
AttachSignOutParameters.Descriptor,
@ -192,7 +192,7 @@ public static partial class OpenIddictClientHandlers
.. Protection.DefaultHandlers,
.. Revocation.DefaultHandlers,
.. Session.DefaultHandlers,
.. Userinfo.DefaultHandlers
.. UserInfo.DefaultHandlers
]);
/// <summary>
@ -534,7 +534,7 @@ public static partial class OpenIddictClientHandlers
OpenIddictClientEndpointType.Redirection => (true, true, true, true),
// While the OpenID Connect RP-initiated logout specification doesn't require sending
// a state as part of logout requests, the identity provider MUST return the state
// a state as part of end session requests, the identity provider MUST return the state
// if one was initially specified. Since OpenIddict always sends a state (used as a
// way to mitigate CSRF attacks and store per-logout values like the identity of the
// chosen authorization server), the state is always considered required at this point.
@ -997,7 +997,7 @@ public static partial class OpenIddictClientHandlers
};
// If the endpoint URI cannot be resolved, this likely means the authorization or
// logout request was sent without a redirect_uri/post_logout_redirect_uri attached
// end session request was sent without a redirect_uri/post_logout_redirect_uri attached
// (by default, OpenIddict throws an exception when sending an authorization request
// that doesn't include a redirect_uri for security reasons, but a custom handler can
// remove the redirect_uri from the state token principal to disable this security check).
@ -3569,14 +3569,14 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for resolving the URI of the userinfo endpoint.
/// </summary>
public sealed class ResolveUserinfoEndpoint : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class ResolveUserInfoEndpoint : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.UseSingletonHandler<ResolveUserinfoEndpoint>()
.UseSingletonHandler<ResolveUserInfoEndpoint>()
.SetOrder(ValidateRefreshToken.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -3591,7 +3591,7 @@ public static partial class OpenIddictClientHandlers
// If the URI of the userinfo endpoint wasn't explicitly set at
// this stage, try to extract it from the server configuration.
context.UserinfoEndpoint ??= context.Configuration.UserinfoEndpoint switch
context.UserInfoEndpoint ??= context.Configuration.UserInfoEndpoint switch
{
{ IsAbsoluteUri: true } uri when !OpenIddictHelpers.IsImplicitFileUri(uri) => uri,
@ -3605,15 +3605,15 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for determining whether a userinfo request should be sent.
/// </summary>
public sealed class EvaluateUserinfoRequest : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class EvaluateUserInfoRequest : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.UseSingletonHandler<EvaluateUserinfoRequest>()
.SetOrder(ResolveUserinfoEndpoint.Descriptor.Order + 1_000)
.UseSingletonHandler<EvaluateUserInfoRequest>()
.SetOrder(ResolveUserInfoEndpoint.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -3625,7 +3625,7 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
context.SendUserinfoRequest = context.GrantType switch
context.SendUserInfoRequest = context.GrantType switch
{
// Never send a userinfo request when using the client credentials grant.
GrantTypes.ClientCredentials => false,
@ -3638,7 +3638,7 @@ public static partial class OpenIddictClientHandlers
// is available, unless userinfo retrieval was explicitly disabled by the user.
GrantTypes.AuthorizationCode or GrantTypes.DeviceCode or GrantTypes.Implicit or
GrantTypes.Password or GrantTypes.RefreshToken
when !context.DisableUserinfoRetrieval && context.UserinfoEndpoint is not null &&
when !context.DisableUserInfoRetrieval && context.UserInfoEndpoint is not null &&
(!string.IsNullOrEmpty(context.BackchannelAccessToken) ||
!string.IsNullOrEmpty(context.FrontchannelAccessToken)) => true,
@ -3646,7 +3646,7 @@ public static partial class OpenIddictClientHandlers
not null and not (GrantTypes.AuthorizationCode or GrantTypes.ClientCredentials or
GrantTypes.DeviceCode or GrantTypes.Implicit or
GrantTypes.Password or GrantTypes.RefreshToken)
when !context.DisableUserinfoRetrieval && context.UserinfoEndpoint is not null &&
when !context.DisableUserInfoRetrieval && context.UserInfoEndpoint is not null &&
(!string.IsNullOrEmpty(context.BackchannelAccessToken) ||
!string.IsNullOrEmpty(context.FrontchannelAccessToken)) => true,
@ -3657,7 +3657,7 @@ public static partial class OpenIddictClientHandlers
// but must also support non-standard implementations, that are common with OAuth 2.0-only servers.
//
// As such, protocol requirements are, by default, only enforced if the openid scope was requested.
context.DisableUserinfoValidation = context.GrantType switch
context.DisableUserInfoValidation = context.GrantType switch
{
GrantTypes.AuthorizationCode or GrantTypes.Implicit
when context.StateTokenPrincipal is ClaimsPrincipal principal
@ -3690,16 +3690,16 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for attaching the parameters to the userinfo request, if applicable.
/// </summary>
public sealed class AttachUserinfoRequestParameters : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class AttachUserInfoRequestParameters : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireUserinfoRequest>()
.UseSingletonHandler<AttachUserinfoRequestParameters>()
.SetOrder(EvaluateUserinfoRequest.Descriptor.Order + 1_000)
.AddFilter<RequireUserInfoRequest>()
.UseSingletonHandler<AttachUserInfoRequestParameters>()
.SetOrder(EvaluateUserInfoRequest.Descriptor.Order + 1_000)
.Build();
/// <inheritdoc/>
@ -3711,11 +3711,11 @@ public static partial class OpenIddictClientHandlers
}
// Attach a new request instance if necessary.
context.UserinfoRequest ??= new OpenIddictRequest();
context.UserInfoRequest ??= new OpenIddictRequest();
// Note: the backchannel access token (retrieved from the token endpoint) is always preferred to
// the frontchannel access token if available, as it may grant a greater access to user's resources.
context.UserinfoRequest.AccessToken = context.BackchannelAccessToken ?? context.FrontchannelAccessToken ??
context.UserInfoRequest.AccessToken = context.BackchannelAccessToken ?? context.FrontchannelAccessToken ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0162));
return default;
@ -3725,11 +3725,11 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for sending the userinfo request, if applicable.
/// </summary>
public sealed class SendUserinfoRequest : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class SendUserInfoRequest : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
private readonly OpenIddictClientService _service;
public SendUserinfoRequest(OpenIddictClientService service)
public SendUserInfoRequest(OpenIddictClientService service)
=> _service = service ?? throw new ArgumentNullException(nameof(service));
/// <summary>
@ -3737,9 +3737,9 @@ public static partial class OpenIddictClientHandlers
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireUserinfoRequest>()
.UseSingletonHandler<SendUserinfoRequest>()
.SetOrder(AttachUserinfoRequestParameters.Descriptor.Order + 1_000)
.AddFilter<RequireUserInfoRequest>()
.UseSingletonHandler<SendUserInfoRequest>()
.SetOrder(AttachUserInfoRequestParameters.Descriptor.Order + 1_000)
.Build();
/// <inheritdoc/>
@ -3750,13 +3750,13 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
Debug.Assert(context.UserinfoRequest is not null, SR.GetResourceString(SR.ID4008));
Debug.Assert(context.UserInfoRequest is not null, SR.GetResourceString(SR.ID4008));
// Ensure the userinfo endpoint is present and is a valid absolute URI.
if (context.UserinfoEndpoint is not { IsAbsoluteUri: true } ||
OpenIddictHelpers.IsImplicitFileUri(context.UserinfoEndpoint))
if (context.UserInfoEndpoint is not { IsAbsoluteUri: true } ||
OpenIddictHelpers.IsImplicitFileUri(context.UserInfoEndpoint))
{
throw new InvalidOperationException(SR.FormatID0301(Metadata.UserinfoEndpoint));
throw new InvalidOperationException(SR.FormatID0301(Metadata.UserInfoEndpoint));
}
// Note: userinfo responses can be of two types:
@ -3765,10 +3765,10 @@ public static partial class OpenIddictClientHandlers
try
{
(context.UserinfoResponse, (context.UserinfoTokenPrincipal, context.UserinfoToken)) =
await _service.SendUserinfoRequestAsync(
(context.UserInfoResponse, (context.UserInfoTokenPrincipal, context.UserInfoToken)) =
await _service.SendUserInfoRequestAsync(
context.Registration, context.Configuration,
context.UserinfoRequest, context.UserinfoEndpoint, context.CancellationToken);
context.UserInfoRequest, context.UserInfoEndpoint, context.CancellationToken);
}
catch (ProtocolException exception)
@ -3786,15 +3786,15 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for determining whether a userinfo token should be validated.
/// </summary>
public sealed class EvaluateValidatedUserinfoToken : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class EvaluateValidatedUserInfoToken : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.UseSingletonHandler<EvaluateValidatedUserinfoToken>()
.SetOrder(SendUserinfoRequest.Descriptor.Order + 1_000)
.UseSingletonHandler<EvaluateValidatedUserInfoToken>()
.SetOrder(SendUserInfoRequest.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -3806,20 +3806,20 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
(context.ExtractUserinfoToken,
context.RequireUserinfoToken,
context.ValidateUserinfoToken,
context.RejectUserinfoToken) = context.GrantType switch
(context.ExtractUserInfoToken,
context.RequireUserInfoToken,
context.ValidateUserInfoToken,
context.RejectUserInfoToken) = context.GrantType switch
{
// By default, OpenIddict doesn't require that userinfo tokens be used even for
// user flows but they are extracted and validated when a userinfo request was sent.
GrantTypes.AuthorizationCode or GrantTypes.Implicit or
GrantTypes.DeviceCode or GrantTypes.Password or GrantTypes.RefreshToken
when context.SendUserinfoRequest => (true, false, true, true),
when context.SendUserInfoRequest => (true, false, true, true),
// Userinfo tokens are typically not used with the client credentials grant,
// UserInfo tokens are typically not used with the client credentials grant,
// but they are extracted and validated when a userinfo request was sent.
GrantTypes.ClientCredentials when context.SendUserinfoRequest
GrantTypes.ClientCredentials when context.SendUserInfoRequest
=> (true, false, true, true),
// By default, don't require userinfo tokens for custom grants
@ -3827,7 +3827,7 @@ public static partial class OpenIddictClientHandlers
not null and not (GrantTypes.AuthorizationCode or GrantTypes.ClientCredentials or
GrantTypes.DeviceCode or GrantTypes.Implicit or
GrantTypes.Password or GrantTypes.RefreshToken)
when context.SendUserinfoRequest => (true, false, true, true),
when context.SendUserInfoRequest => (true, false, true, true),
_ => (false, false, false, false),
};
@ -3839,17 +3839,17 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for rejecting authentication demands that lack the required userinfo token.
/// </summary>
public sealed class ValidateRequiredUserinfoToken : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class ValidateRequiredUserInfoToken : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.UseSingletonHandler<ValidateRequiredUserinfoToken>()
.UseSingletonHandler<ValidateRequiredUserInfoToken>()
// Note: this handler is registered with a high gap to allow handlers
// that do token extraction to be executed before this handler runs.
.SetOrder(EvaluateValidatedUserinfoToken.Descriptor.Order + 50_000)
.SetOrder(EvaluateValidatedUserInfoToken.Descriptor.Order + 50_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -3861,7 +3861,7 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
if (context.RequireUserinfoToken && string.IsNullOrEmpty(context.UserinfoToken))
if (context.RequireUserInfoToken && string.IsNullOrEmpty(context.UserInfoToken))
{
context.Reject(
error: Errors.MissingToken,
@ -3878,11 +3878,11 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for validating the userinfo token resolved from the context.
/// </summary>
public sealed class ValidateUserinfoToken : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class ValidateUserInfoToken : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
private readonly IOpenIddictClientDispatcher _dispatcher;
public ValidateUserinfoToken(IOpenIddictClientDispatcher dispatcher)
public ValidateUserInfoToken(IOpenIddictClientDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -3890,9 +3890,9 @@ public static partial class OpenIddictClientHandlers
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireUserinfoTokenExtracted>()
.UseScopedHandler<ValidateUserinfoToken>()
.SetOrder(ValidateRequiredUserinfoToken.Descriptor.Order + 1_000)
.AddFilter<RequireUserInfoTokenExtracted>()
.UseScopedHandler<ValidateUserInfoToken>()
.SetOrder(ValidateRequiredUserInfoToken.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -3904,15 +3904,15 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
if (string.IsNullOrEmpty(context.UserinfoToken))
if (string.IsNullOrEmpty(context.UserInfoToken))
{
return;
}
var notification = new ValidateTokenContext(context.Transaction)
{
Token = context.UserinfoToken,
ValidTokenTypes = { TokenTypeHints.UserinfoToken }
Token = context.UserInfoToken,
ValidTokenTypes = { TokenTypeHints.UserInfoToken }
};
await _dispatcher.DispatchAsync(notification);
@ -3931,7 +3931,7 @@ public static partial class OpenIddictClientHandlers
else if (notification.IsRejected)
{
if (context.RejectUserinfoToken)
if (context.RejectUserInfoToken)
{
context.Reject(
error: notification.Error ?? Errors.InvalidRequest,
@ -3943,24 +3943,24 @@ public static partial class OpenIddictClientHandlers
return;
}
context.UserinfoTokenPrincipal = notification.Principal;
context.UserInfoTokenPrincipal = notification.Principal;
}
}
/// <summary>
/// Contains the logic responsible for validating the well-known claims contained in the userinfo token.
/// </summary>
public sealed class ValidateUserinfoTokenWellknownClaims : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class ValidateUserInfoTokenWellknownClaims : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireUserinfoValidationEnabled>()
.AddFilter<RequireUserinfoTokenPrincipal>()
.UseSingletonHandler<ValidateUserinfoTokenWellknownClaims>()
.SetOrder(ValidateUserinfoToken.Descriptor.Order + 1_000)
.AddFilter<RequireUserInfoValidationEnabled>()
.AddFilter<RequireUserInfoTokenPrincipal>()
.UseSingletonHandler<ValidateUserInfoTokenWellknownClaims>()
.SetOrder(ValidateUserInfoToken.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -3972,9 +3972,9 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
Debug.Assert(context.UserinfoTokenPrincipal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
Debug.Assert(context.UserInfoTokenPrincipal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
foreach (var group in context.UserinfoTokenPrincipal.Claims
foreach (var group in context.UserInfoTokenPrincipal.Claims
.GroupBy(static claim => claim.Type)
.ToDictionary(static group => group.Key, group => group.ToList())
.Where(static group => !ValidateClaimGroup(group.Key, group.Value)))
@ -4003,17 +4003,17 @@ public static partial class OpenIddictClientHandlers
/// <summary>
/// Contains the logic responsible for validating the subject claim contained in the userinfo token.
/// </summary>
public sealed class ValidateUserinfoTokenSubject : IOpenIddictClientHandler<ProcessAuthenticationContext>
public sealed class ValidateUserInfoTokenSubject : IOpenIddictClientHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireUserinfoValidationEnabled>()
.AddFilter<RequireUserinfoTokenPrincipal>()
.UseSingletonHandler<ValidateUserinfoTokenSubject>()
.SetOrder(ValidateUserinfoTokenWellknownClaims.Descriptor.Order + 1_000)
.AddFilter<RequireUserInfoValidationEnabled>()
.AddFilter<RequireUserInfoTokenPrincipal>()
.UseSingletonHandler<ValidateUserInfoTokenSubject>()
.SetOrder(ValidateUserInfoTokenWellknownClaims.Descriptor.Order + 1_000)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
@ -4025,11 +4025,11 @@ public static partial class OpenIddictClientHandlers
throw new ArgumentNullException(nameof(context));
}
Debug.Assert(context.UserinfoTokenPrincipal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
Debug.Assert(context.UserInfoTokenPrincipal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
// Standard OpenID Connect userinfo responses/tokens MUST contain a "sub" claim. For more
// information, see https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse.
if (!context.UserinfoTokenPrincipal.HasClaim(Claims.Subject))
if (!context.UserInfoTokenPrincipal.HasClaim(Claims.Subject))
{
context.Reject(
error: Errors.InvalidRequest,
@ -4044,7 +4044,7 @@ public static partial class OpenIddictClientHandlers
// see https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse.
if (context.FrontchannelIdentityTokenPrincipal is not null && !string.Equals(
context.FrontchannelIdentityTokenPrincipal.GetClaim(Claims.Subject),
context.UserinfoTokenPrincipal.GetClaim(Claims.Subject), StringComparison.Ordinal))
context.UserInfoTokenPrincipal.GetClaim(Claims.Subject), StringComparison.Ordinal))
{
context.Reject(
error: Errors.InvalidRequest,
@ -4059,7 +4059,7 @@ public static partial class OpenIddictClientHandlers
// see https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse.
if (context.BackchannelIdentityTokenPrincipal is not null && !string.Equals(
context.BackchannelIdentityTokenPrincipal.GetClaim(Claims.Subject),
context.UserinfoTokenPrincipal.GetClaim(Claims.Subject), StringComparison.Ordinal))
context.UserInfoTokenPrincipal.GetClaim(Claims.Subject), StringComparison.Ordinal))
{
context.Reject(
error: Errors.InvalidRequest,
@ -4103,7 +4103,7 @@ public static partial class OpenIddictClientHandlers
context.MergedPrincipal = CreateMergedPrincipal(
context.FrontchannelIdentityTokenPrincipal,
context.BackchannelIdentityTokenPrincipal,
context.UserinfoTokenPrincipal);
context.UserInfoTokenPrincipal);
// Attach the registration identifier and identity of the authorization server to the returned principal to allow
// resolving it even if no other claim was added (e.g if no id_token was returned/no userinfo endpoint is available).
@ -4788,7 +4788,7 @@ public static partial class OpenIddictClientHandlers
{
{ Length: > 0 } value => value,
// Note: the client identifier is required for the authorization code/hybrid/implicit and device flows.
// Note: the client identifier is required for the authorization code/hybrid/implicit and device authorization flows.
// If no client identifier was attached to the registration, abort the challenge demand immediately.
_ when context.GrantType is GrantTypes.AuthorizationCode or GrantTypes.DeviceCode or GrantTypes.Implicit
=> throw new InvalidOperationException(SR.GetResourceString(SR.ID0418)),
@ -7423,16 +7423,16 @@ public static partial class OpenIddictClientHandlers
}
/// <summary>
/// Contains the logic responsible for attaching a request forgery protection to the logout request.
/// Contains the logic responsible for attaching a request forgery protection to the end session request.
/// </summary>
public sealed class AttachLogoutRequestForgeryProtection : IOpenIddictClientHandler<ProcessSignOutContext>
public sealed class AttachEndSessionRequestForgeryProtection : IOpenIddictClientHandler<ProcessSignOutContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessSignOutContext>()
.UseSingletonHandler<AttachLogoutRequestForgeryProtection>()
.UseSingletonHandler<AttachEndSessionRequestForgeryProtection>()
.SetOrder(AttachSignOutHostProperties.Descriptor.Order + 1_000)
.Build();
@ -7454,7 +7454,7 @@ public static partial class OpenIddictClientHandlers
}
/// <summary>
/// Contains the logic responsible for attaching a nonce to the logout request.
/// Contains the logic responsible for attaching a nonce to the end session request.
/// </summary>
public sealed class AttachLogoutNonce : IOpenIddictClientHandler<ProcessSignOutContext>
{
@ -7464,7 +7464,7 @@ public static partial class OpenIddictClientHandlers
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessSignOutContext>()
.UseSingletonHandler<AttachLogoutNonce>()
.SetOrder(AttachLogoutRequestForgeryProtection.Descriptor.Order + 1_000)
.SetOrder(AttachEndSessionRequestForgeryProtection.Descriptor.Order + 1_000)
.Build();
/// <inheritdoc/>
@ -7560,7 +7560,7 @@ public static partial class OpenIddictClientHandlers
.SetClaim(Claims.Private.ProviderName, context.Registration.ProviderName);
// Store the request forgery protection in the state token so it can be later used to
// ensure the logout response sent to the post-logout redirection endpoint is not forged.
// ensure the end session response sent to the post-logout redirection endpoint is not forged.
principal.SetClaim(Claims.RequestForgeryProtection, context.RequestForgeryProtection);
// Store the optional target link URI in the state token.

34
src/OpenIddict.Client/OpenIddictClientModels.cs

@ -124,7 +124,7 @@ public static class OpenIddictClientModels
/// Gets or sets the principal extracted from the userinfo token or response, if available.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public required ClaimsPrincipal? UserinfoTokenPrincipal { get; init; }
public required ClaimsPrincipal? UserInfoTokenPrincipal { get; init; }
}
/// <summary>
@ -243,9 +243,9 @@ public static class OpenIddictClientModels
public sealed record class InteractiveSignOutRequest
{
/// <summary>
/// Gets or sets the parameters that will be added to the logout request.
/// Gets or sets the parameters that will be added to the end session request.
/// </summary>
public Dictionary<string, OpenIddictParameter>? AdditionalLogoutRequestParameters { get; init; }
public Dictionary<string, OpenIddictParameter>? AdditionalEndSessionRequestParameters { get; init; }
/// <summary>
/// Gets or sets the cancellation token that will be
@ -418,7 +418,7 @@ public static class OpenIddictClientModels
/// <remarks>
/// Note: this property is generally not set, unless when dealing with non-standard providers.
/// </remarks>
public required string? UserinfoToken { get; init; }
public required string? UserInfoToken { get; init; }
/// <summary>
/// Gets or sets the principal extracted from the userinfo token or response, if available.
@ -427,7 +427,7 @@ public static class OpenIddictClientModels
/// Note: this property is generally not set, unless when dealing with non-standard providers.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public required ClaimsPrincipal? UserinfoTokenPrincipal { get; init; }
public required ClaimsPrincipal? UserInfoTokenPrincipal { get; init; }
}
/// <summary>
@ -449,7 +449,7 @@ public static class OpenIddictClientModels
/// <summary>
/// Gets or sets a boolean indicating whether userinfo should be disabled.
/// </summary>
public bool DisableUserinfo { get; set; }
public bool DisableUserInfo { get; set; }
/// <summary>
/// Gets or sets the custom grant type that will be used for the authentication request.
@ -540,13 +540,13 @@ public static class OpenIddictClientModels
/// <summary>
/// Gets or sets the userinfo token, if available.
/// </summary>
public required string? UserinfoToken { get; init; }
public required string? UserInfoToken { get; init; }
/// <summary>
/// Gets or sets the principal extracted from the userinfo token or response, if available.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public required ClaimsPrincipal? UserinfoTokenPrincipal { get; init; }
public required ClaimsPrincipal? UserInfoTokenPrincipal { get; init; }
}
/// <summary>
@ -573,7 +573,7 @@ public static class OpenIddictClientModels
/// <summary>
/// Gets or sets a boolean indicating whether userinfo should be disabled.
/// </summary>
public bool DisableUserinfo { get; set; }
public bool DisableUserInfo { get; set; }
/// <summary>
/// Gets or sets the maximum duration during which token requests will be sent
@ -673,13 +673,13 @@ public static class OpenIddictClientModels
/// <summary>
/// Gets or sets the userinfo token, if available.
/// </summary>
public required string? UserinfoToken { get; init; }
public required string? UserInfoToken { get; init; }
/// <summary>
/// Gets or sets the principal extracted from the userinfo token or response, if available.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public required ClaimsPrincipal? UserinfoTokenPrincipal { get; init; }
public required ClaimsPrincipal? UserInfoTokenPrincipal { get; init; }
}
/// <summary>
@ -878,7 +878,7 @@ public static class OpenIddictClientModels
/// <summary>
/// Gets or sets a boolean indicating whether userinfo should be disabled.
/// </summary>
public bool DisableUserinfo { get; set; }
public bool DisableUserInfo { get; set; }
/// <summary>
/// Gets or sets the password that will be sent to the authorization server.
@ -974,13 +974,13 @@ public static class OpenIddictClientModels
/// <summary>
/// Gets or sets the userinfo token, if available.
/// </summary>
public required string? UserinfoToken { get; init; }
public required string? UserInfoToken { get; init; }
/// <summary>
/// Gets or sets the principal extracted from the userinfo token or response, if available.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public required ClaimsPrincipal? UserinfoTokenPrincipal { get; init; }
public required ClaimsPrincipal? UserInfoTokenPrincipal { get; init; }
}
/// <summary>
@ -1003,7 +1003,7 @@ public static class OpenIddictClientModels
/// Gets or sets a boolean indicating whether userinfo should be disabled, which may be required
/// when sending a refresh token that was acquired using a user-less flow (e.g client credentials).
/// </summary>
public bool DisableUserinfo { get; set; }
public bool DisableUserInfo { get; set; }
/// <summary>
/// Gets or sets the application-specific properties that will be added to the context.
@ -1094,13 +1094,13 @@ public static class OpenIddictClientModels
/// <summary>
/// Gets or sets the userinfo token, if available.
/// </summary>
public required string? UserinfoToken { get; init; }
public required string? UserInfoToken { get; init; }
/// <summary>
/// Gets or sets the principal extracted from the userinfo token or response, if available.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public required ClaimsPrincipal? UserinfoTokenPrincipal { get; init; }
public required ClaimsPrincipal? UserInfoTokenPrincipal { get; init; }
}
/// <summary>

8
src/OpenIddict.Client/OpenIddictClientOptions.cs

@ -86,14 +86,14 @@ public sealed class OpenIddictClientOptions
};
/// <summary>
/// Gets the absolute and relative URIs associated to the redirection endpoint.
/// Gets the absolute and relative URIs associated to the post-logout redirection endpoint.
/// </summary>
public List<Uri> RedirectionEndpointUris { get; } = [];
public List<Uri> PostLogoutRedirectionEndpointUris { get; } = [];
/// <summary>
/// Gets the absolute and relative URIs associated to the post-logout redirection endpoint.
/// Gets the absolute and relative URIs associated to the redirection endpoint.
/// </summary>
public List<Uri> PostLogoutRedirectionEndpointUris { get; } = [];
public List<Uri> RedirectionEndpointUris { get; } = [];
/// <summary>
/// Gets the static client registrations used by the OpenIddict client services.

100
src/OpenIddict.Client/OpenIddictClientService.cs

@ -337,7 +337,7 @@ public class OpenIddictClientService
RefreshToken = context.RefreshToken,
StateTokenPrincipal = context.StateTokenPrincipal,
TokenResponse = context.TokenResponse ?? new(),
UserinfoTokenPrincipal = context.UserinfoTokenPrincipal
UserInfoTokenPrincipal = context.UserInfoTokenPrincipal
};
}
}
@ -521,8 +521,8 @@ public class OpenIddictClientService
Properties = context.Properties,
RefreshToken = context.RefreshToken,
TokenResponse = context.TokenResponse,
UserinfoToken = context.UserinfoToken,
UserinfoTokenPrincipal = context.UserinfoTokenPrincipal
UserInfoToken = context.UserInfoToken,
UserInfoTokenPrincipal = context.UserInfoTokenPrincipal
};
}
@ -579,8 +579,8 @@ public class OpenIddictClientService
var context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = request.CancellationToken,
DisableUserinfoRetrieval = request.DisableUserinfo,
DisableUserinfoValidation = request.DisableUserinfo,
DisableUserInfoRetrieval = request.DisableUserInfo,
DisableUserInfoValidation = request.DisableUserInfo,
GrantType = request.GrantType,
ProviderName = request.ProviderName,
RegistrationId = request.RegistrationId,
@ -623,8 +623,8 @@ public class OpenIddictClientService
Properties = context.Properties,
RefreshToken = context.RefreshToken,
TokenResponse = context.TokenResponse,
UserinfoToken = context.UserinfoToken,
UserinfoTokenPrincipal = context.UserinfoTokenPrincipal
UserInfoToken = context.UserInfoToken,
UserInfoTokenPrincipal = context.UserInfoTokenPrincipal
};
}
@ -683,8 +683,8 @@ public class OpenIddictClientService
{
CancellationToken = source.Token,
DeviceCode = request.DeviceCode,
DisableUserinfoRetrieval = request.DisableUserinfo,
DisableUserinfoValidation = request.DisableUserinfo,
DisableUserInfoRetrieval = request.DisableUserInfo,
DisableUserInfoValidation = request.DisableUserInfo,
GrantType = GrantTypes.DeviceCode,
Issuer = request.Issuer,
ProviderName = request.ProviderName,
@ -729,8 +729,8 @@ public class OpenIddictClientService
Properties = context.Properties,
RefreshToken = context.RefreshToken,
TokenResponse = context.TokenResponse ?? new(),
UserinfoToken = context.UserinfoToken,
UserinfoTokenPrincipal = context.UserinfoTokenPrincipal
UserInfoToken = context.UserInfoToken,
UserInfoTokenPrincipal = context.UserInfoTokenPrincipal
};
}
}
@ -887,8 +887,8 @@ public class OpenIddictClientService
var context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = request.CancellationToken,
DisableUserinfoRetrieval = request.DisableUserinfo,
DisableUserinfoValidation = request.DisableUserinfo,
DisableUserInfoRetrieval = request.DisableUserInfo,
DisableUserInfoValidation = request.DisableUserInfo,
GrantType = GrantTypes.Password,
Issuer = request.Issuer,
Password = request.Password,
@ -934,8 +934,8 @@ public class OpenIddictClientService
Properties = context.Properties,
RefreshToken = context.RefreshToken,
TokenResponse = context.TokenResponse,
UserinfoToken = context.UserinfoToken,
UserinfoTokenPrincipal = context.UserinfoTokenPrincipal
UserInfoToken = context.UserInfoToken,
UserInfoTokenPrincipal = context.UserInfoTokenPrincipal
};
}
@ -984,8 +984,8 @@ public class OpenIddictClientService
var context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = request.CancellationToken,
DisableUserinfoRetrieval = request.DisableUserinfo,
DisableUserinfoValidation = request.DisableUserinfo,
DisableUserInfoRetrieval = request.DisableUserInfo,
DisableUserInfoValidation = request.DisableUserInfo,
GrantType = GrantTypes.RefreshToken,
Issuer = request.Issuer,
ProviderName = request.ProviderName,
@ -1030,8 +1030,8 @@ public class OpenIddictClientService
Properties = context.Properties,
RefreshToken = context.RefreshToken,
TokenResponse = context.TokenResponse,
UserinfoToken = context.UserinfoToken,
UserinfoTokenPrincipal = context.UserinfoTokenPrincipal
UserInfoToken = context.UserInfoToken,
UserInfoTokenPrincipal = context.UserInfoTokenPrincipal
};
}
@ -1403,7 +1403,7 @@ public class OpenIddictClientService
Principal = new ClaimsPrincipal(new ClaimsIdentity()),
ProviderName = request.ProviderName,
RegistrationId = request.RegistrationId,
Request = request.AdditionalLogoutRequestParameters
Request = request.AdditionalEndSessionRequestParameters
is Dictionary<string, OpenIddictParameter> parameters ? new(parameters) : new(),
};
@ -1451,7 +1451,7 @@ public class OpenIddictClientService
}
/// <summary>
/// Retrieves the security keys exposed by the specified JWKS endpoint.
/// Retrieves the security keys exposed by the specified JSON Web Key Set endpoint.
/// </summary>
/// <param name="registration">The client registration.</param>
/// <param name="uri">The uri of the remote metadata endpoint.</param>
@ -1491,17 +1491,17 @@ public class OpenIddictClientService
var transaction = await factory.CreateTransactionAsync();
var request = new OpenIddictRequest();
request = await PrepareCryptographyRequestAsync();
request = await ApplyCryptographyRequestAsync();
request = await PrepareJsonWebKeySetRequestAsync();
request = await ApplyJsonWebKeySetRequestAsync();
var response = await ExtractCryptographyResponseAsync();
var response = await ExtractJsonWebKeySetResponseAsync();
return await HandleCryptographyResponseAsync() ??
return await HandleJsonWebKeySetResponseAsync() ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0147));
async ValueTask<OpenIddictRequest> PrepareCryptographyRequestAsync()
async ValueTask<OpenIddictRequest> PrepareJsonWebKeySetRequestAsync()
{
var context = new PrepareCryptographyRequestContext(transaction)
var context = new PrepareJsonWebKeySetRequestContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
@ -1521,9 +1521,9 @@ public class OpenIddictClientService
return context.Request;
}
async ValueTask<OpenIddictRequest> ApplyCryptographyRequestAsync()
async ValueTask<OpenIddictRequest> ApplyJsonWebKeySetRequestAsync()
{
var context = new ApplyCryptographyRequestContext(transaction)
var context = new ApplyJsonWebKeySetRequestContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
@ -1545,9 +1545,9 @@ public class OpenIddictClientService
return context.Request;
}
async ValueTask<OpenIddictResponse> ExtractCryptographyResponseAsync()
async ValueTask<OpenIddictResponse> ExtractJsonWebKeySetResponseAsync()
{
var context = new ExtractCryptographyResponseContext(transaction)
var context = new ExtractJsonWebKeySetResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
@ -1571,9 +1571,9 @@ public class OpenIddictClientService
return context.Response;
}
async ValueTask<JsonWebKeySet> HandleCryptographyResponseAsync()
async ValueTask<JsonWebKeySet> HandleJsonWebKeySetResponseAsync()
{
var context = new HandleCryptographyResponseContext(transaction)
var context = new HandleJsonWebKeySetResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
@ -1591,7 +1591,7 @@ public class OpenIddictClientService
context.Error, context.ErrorDescription, context.ErrorUri);
}
return context.SecurityKeys;
return context.JsonWebKeySet;
}
}
@ -2306,7 +2306,7 @@ public class OpenIddictClientService
/// <param name="uri">The uri of the remote userinfo endpoint.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The response and the principal extracted from the userinfo response or the userinfo token.</returns>
internal async ValueTask<(OpenIddictResponse Response, (ClaimsPrincipal? Principal, string? Token))> SendUserinfoRequestAsync(
internal async ValueTask<(OpenIddictResponse Response, (ClaimsPrincipal? Principal, string? Token))> SendUserInfoRequestAsync(
OpenIddictClientRegistration registration, OpenIddictConfiguration configuration,
OpenIddictRequest request, Uri uri, CancellationToken cancellationToken = default)
{
@ -2345,16 +2345,16 @@ public class OpenIddictClientService
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
request = await PrepareUserinfoRequestAsync();
request = await ApplyUserinfoRequestAsync();
request = await PrepareUserInfoRequestAsync();
request = await ApplyUserInfoRequestAsync();
var (response, token) = await ExtractUserinfoResponseAsync();
var (response, token) = await ExtractUserInfoResponseAsync();
return await HandleUserinfoResponseAsync();
return await HandleUserInfoResponseAsync();
async ValueTask<OpenIddictRequest> PrepareUserinfoRequestAsync()
async ValueTask<OpenIddictRequest> PrepareUserInfoRequestAsync()
{
var context = new PrepareUserinfoRequestContext(transaction)
var context = new PrepareUserInfoRequestContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
@ -2375,9 +2375,9 @@ public class OpenIddictClientService
return context.Request;
}
async ValueTask<OpenIddictRequest> ApplyUserinfoRequestAsync()
async ValueTask<OpenIddictRequest> ApplyUserInfoRequestAsync()
{
var context = new ApplyUserinfoRequestContext(transaction)
var context = new ApplyUserInfoRequestContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
@ -2400,9 +2400,9 @@ public class OpenIddictClientService
return context.Request;
}
async ValueTask<(OpenIddictResponse, string?)> ExtractUserinfoResponseAsync()
async ValueTask<(OpenIddictResponse, string?)> ExtractUserInfoResponseAsync()
{
var context = new ExtractUserinfoResponseContext(transaction)
var context = new ExtractUserInfoResponseContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
@ -2424,12 +2424,12 @@ public class OpenIddictClientService
context.Logger.LogInformation(SR.GetResourceString(SR.ID6195), context.RemoteUri, context.Response);
return (context.Response, context.UserinfoToken);
return (context.Response, context.UserInfoToken);
}
async ValueTask<(OpenIddictResponse, (ClaimsPrincipal?, string?))> HandleUserinfoResponseAsync()
async ValueTask<(OpenIddictResponse, (ClaimsPrincipal?, string?))> HandleUserInfoResponseAsync()
{
var context = new HandleUserinfoResponseContext(transaction)
var context = new HandleUserInfoResponseContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
@ -2437,7 +2437,7 @@ public class OpenIddictClientService
RemoteUri = uri,
Request = request,
Response = response,
UserinfoToken = token
UserInfoToken = token
};
await dispatcher.DispatchAsync(context);
@ -2449,7 +2449,7 @@ public class OpenIddictClientService
context.Error, context.ErrorDescription, context.ErrorUri);
}
return (context.Response, (context.Principal, context.UserinfoToken));
return (context.Response, (context.Principal, context.UserInfoToken));
}
}

2
src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs

@ -1422,7 +1422,7 @@ public class OpenIddictApplicationManager<TApplication> : IOpenIddictApplication
/// <param name="application">The application.</param>
/// <param name="uri">The URI that should be compared to one of the post_logout_redirect_uri stored in the database.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <remarks>Note: if no client_id parameter is specified in logout requests, this method may not be called.</remarks>
/// <remarks>Note: if no client_id parameter is specified in end session requests, this method may not be called.</remarks>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation,
/// whose result returns a boolean indicating whether the post_logout_redirect_uri was valid.

58
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreBuilder.cs

@ -65,9 +65,29 @@ public sealed class OpenIddictServerAspNetCoreBuilder
public OpenIddictServerAspNetCoreBuilder EnableAuthorizationEndpointPassthrough()
=> Configure(options => options.EnableAuthorizationEndpointPassthrough = true);
/// <summary>
/// Enables the pass-through mode for the OpenID Connect end session endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
/// <returns>The <see cref="OpenIddictServerAspNetCoreBuilder"/> instance.</returns>
public OpenIddictServerAspNetCoreBuilder EnableEndSessionEndpointPassthrough()
=> Configure(options => options.EnableEndSessionEndpointPassthrough = true);
/// <summary>
/// Enables the pass-through mode for the OpenID Connect end-user verification endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
/// <returns>The <see cref="OpenIddictServerAspNetCoreBuilder"/> instance.</returns>
public OpenIddictServerAspNetCoreBuilder EnableEndUserVerificationEndpointPassthrough()
=> Configure(options => options.EnableEndUserVerificationEndpointPassthrough = true);
/// <summary>
/// Enables error pass-through support, so that the rest of the request processing pipeline is
/// automatically invoked when returning an error from the interactive authorization and logout endpoints.
/// automatically invoked when returning an error from the interactive authorization and end session endpoints.
/// When this option is enabled, special logic must be added to these actions to handle errors, that can be
/// retrieved using <see cref="OpenIddictServerAspNetCoreHelpers.GetOpenIddictServerResponse(HttpContext)"/>.
/// </summary>
@ -79,16 +99,6 @@ public sealed class OpenIddictServerAspNetCoreBuilder
public OpenIddictServerAspNetCoreBuilder EnableErrorPassthrough()
=> Configure(options => options.EnableErrorPassthrough = true);
/// <summary>
/// Enables the pass-through mode for the OpenID Connect logout endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
/// <returns>The <see cref="OpenIddictServerAspNetCoreBuilder"/> instance.</returns>
public OpenIddictServerAspNetCoreBuilder EnableLogoutEndpointPassthrough()
=> Configure(options => options.EnableLogoutEndpointPassthrough = true);
/// <summary>
/// Enables the pass-through mode for the OpenID Connect token endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
@ -106,18 +116,8 @@ public sealed class OpenIddictServerAspNetCoreBuilder
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
/// <returns>The <see cref="OpenIddictServerAspNetCoreBuilder"/> instance.</returns>
public OpenIddictServerAspNetCoreBuilder EnableUserinfoEndpointPassthrough()
=> Configure(options => options.EnableUserinfoEndpointPassthrough = true);
/// <summary>
/// Enables the pass-through mode for the OpenID Connect user verification endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
/// <returns>The <see cref="OpenIddictServerAspNetCoreBuilder"/> instance.</returns>
public OpenIddictServerAspNetCoreBuilder EnableVerificationEndpointPassthrough()
=> Configure(options => options.EnableVerificationEndpointPassthrough = true);
public OpenIddictServerAspNetCoreBuilder EnableUserInfoEndpointPassthrough()
=> Configure(options => options.EnableUserInfoEndpointPassthrough = true);
/// <summary>
/// Enables authorization request caching, so that authorization requests
@ -131,12 +131,12 @@ public sealed class OpenIddictServerAspNetCoreBuilder
=> Configure(options => options.EnableAuthorizationRequestCaching = true);
/// <summary>
/// Enables logout request caching, so that logout requests
/// Enables end session request caching, so that end session requests
/// are automatically stored in the distributed cache.
/// </summary>
/// <returns>The <see cref="OpenIddictServerAspNetCoreBuilder"/> instance.</returns>
public OpenIddictServerAspNetCoreBuilder EnableLogoutRequestCaching()
=> Configure(options => options.EnableLogoutRequestCaching = true);
public OpenIddictServerAspNetCoreBuilder EnableEndSessionRequestCaching()
=> Configure(options => options.EnableEndSessionRequestCaching = true);
/// <summary>
/// Enables status code pages integration support. Once enabled, errors
@ -185,19 +185,19 @@ public sealed class OpenIddictServerAspNetCoreBuilder
}
/// <summary>
/// Sets the caching policy used by the logout endpoint.
/// Sets the caching policy used by the end session endpoint.
/// Note: the specified policy is only used when caching is explicitly enabled.
/// </summary>
/// <param name="policy">The caching policy.</param>
/// <returns>The <see cref="OpenIddictServerAspNetCoreBuilder"/> instance.</returns>
public OpenIddictServerAspNetCoreBuilder SetLogoutRequestCachingPolicy(DistributedCacheEntryOptions policy)
public OpenIddictServerAspNetCoreBuilder SetEndSessionRequestCachingPolicy(DistributedCacheEntryOptions policy)
{
if (policy is null)
{
throw new ArgumentNullException(nameof(policy));
}
return Configure(options => options.LogoutRequestCachingPolicy = policy);
return Configure(options => options.EndSessionRequestCachingPolicy = policy);
}
/// <inheritdoc/>

4
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreConstants.cs

@ -14,7 +14,7 @@ public static class OpenIddictServerAspNetCoreConstants
public static class Cache
{
public const string AuthorizationRequest = "openiddict-authorization-request:";
public const string LogoutRequest = "openiddict-logout-request:";
public const string EndSessionRequest = "openiddict-end_session-request:";
}
public static class JsonWebTokenTypes
@ -22,7 +22,7 @@ public static class OpenIddictServerAspNetCoreConstants
public static class Private
{
public const string AuthorizationRequest = "oi_authrq+jwt";
public const string LogoutRequest = "oi_lgtrq+jwt";
public const string EndSessionRequest = "oi_endsessrq+jwt";
}
}

6
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreExtensions.cs

@ -40,14 +40,14 @@ public static class OpenIddictServerAspNetCoreExtensions
// Register the built-in filters used by the default OpenIddict ASP.NET Core server event handlers.
builder.Services.TryAddSingleton<RequireAuthorizationRequestCachingEnabled>();
builder.Services.TryAddSingleton<RequireAuthorizationEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireEndSessionRequestCachingEnabled>();
builder.Services.TryAddSingleton<RequireEndSessionEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireErrorPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireHttpRequest>();
builder.Services.TryAddSingleton<RequireLogoutRequestCachingEnabled>();
builder.Services.TryAddSingleton<RequireLogoutEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireTransportSecurityRequirementEnabled>();
builder.Services.TryAddSingleton<RequireStatusCodePagesIntegrationEnabled>();
builder.Services.TryAddSingleton<RequireTokenEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireUserinfoEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireUserInfoEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireVerificationEndpointPassthroughEnabled>();
// Register the option initializer used by the OpenIddict ASP.NET Core server integration services.

8
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs

@ -174,9 +174,11 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Op
// are attached to the authentication properties bag so they can be accessed from user code.
var principal = context.EndpointType switch
{
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Logout
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.EndSession
=> context.IdentityTokenPrincipal,
OpenIddictServerEndpointType.EndUserVerification => context.UserCodePrincipal,
OpenIddictServerEndpointType.Introspection or OpenIddictServerEndpointType.Revocation
=> context.AccessTokenPrincipal ??
context.RefreshTokenPrincipal ??
@ -192,9 +194,7 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Op
OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType()
=> context.RefreshTokenPrincipal,
OpenIddictServerEndpointType.Userinfo => context.AccessTokenPrincipal,
OpenIddictServerEndpointType.Verification => context.UserCodePrincipal,
OpenIddictServerEndpointType.UserInfo => context.AccessTokenPrincipal,
_ => null
};

50
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlerFilters.cs

@ -62,13 +62,13 @@ public static class OpenIddictServerAspNetCoreHandlerFilters
}
/// <summary>
/// Represents a filter that excludes the associated handlers if error pass-through was not enabled.
/// Represents a filter that excludes the associated handlers if end session request caching was not enabled.
/// </summary>
public sealed class RequireErrorPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireEndSessionRequestCachingEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerAspNetCoreOptions> _options;
public RequireErrorPassthroughEnabled(IOptionsMonitor<OpenIddictServerAspNetCoreOptions> options)
public RequireEndSessionRequestCachingEnabled(IOptionsMonitor<OpenIddictServerAspNetCoreOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
@ -79,15 +79,21 @@ public static class OpenIddictServerAspNetCoreHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(_options.CurrentValue.EnableErrorPassthrough);
return new(_options.CurrentValue.EnableEndSessionRequestCaching);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if no ASP.NET Core request can be found.
/// Represents a filter that excludes the associated handlers if the
/// pass-through mode was not enabled for the end session endpoint.
/// </summary>
public sealed class RequireHttpRequest : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireEndSessionEndpointPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerAspNetCoreOptions> _options;
public RequireEndSessionEndpointPassthroughEnabled(IOptionsMonitor<OpenIddictServerAspNetCoreOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
@ -96,18 +102,18 @@ public static class OpenIddictServerAspNetCoreHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(context.Transaction.GetHttpRequest() is not null);
return new(_options.CurrentValue.EnableEndSessionEndpointPassthrough);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if logout request caching was not enabled.
/// Represents a filter that excludes the associated handlers if error pass-through was not enabled.
/// </summary>
public sealed class RequireLogoutRequestCachingEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireErrorPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerAspNetCoreOptions> _options;
public RequireLogoutRequestCachingEnabled(IOptionsMonitor<OpenIddictServerAspNetCoreOptions> options)
public RequireErrorPassthroughEnabled(IOptionsMonitor<OpenIddictServerAspNetCoreOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
@ -118,21 +124,15 @@ public static class OpenIddictServerAspNetCoreHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(_options.CurrentValue.EnableLogoutRequestCaching);
return new(_options.CurrentValue.EnableErrorPassthrough);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the
/// pass-through mode was not enabled for the logout endpoint.
/// Represents a filter that excludes the associated handlers if no ASP.NET Core request can be found.
/// </summary>
public sealed class RequireLogoutEndpointPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireHttpRequest : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerAspNetCoreOptions> _options;
public RequireLogoutEndpointPassthroughEnabled(IOptionsMonitor<OpenIddictServerAspNetCoreOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
@ -141,7 +141,7 @@ public static class OpenIddictServerAspNetCoreHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(_options.CurrentValue.EnableLogoutEndpointPassthrough);
return new(context.Transaction.GetHttpRequest() is not null);
}
}
@ -216,11 +216,11 @@ public static class OpenIddictServerAspNetCoreHandlerFilters
/// Represents a filter that excludes the associated handlers if the
/// pass-through mode was not enabled for the userinfo endpoint.
/// </summary>
public sealed class RequireUserinfoEndpointPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireUserInfoEndpointPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerAspNetCoreOptions> _options;
public RequireUserinfoEndpointPassthroughEnabled(IOptionsMonitor<OpenIddictServerAspNetCoreOptions> options)
public RequireUserInfoEndpointPassthroughEnabled(IOptionsMonitor<OpenIddictServerAspNetCoreOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
@ -231,13 +231,13 @@ public static class OpenIddictServerAspNetCoreHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(_options.CurrentValue.EnableUserinfoEndpointPassthrough);
return new(_options.CurrentValue.EnableUserInfoEndpointPassthrough);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the
/// pass-through mode was not enabled for the verification endpoint.
/// pass-through mode was not enabled for the end-user verification endpoint.
/// </summary>
public sealed class RequireVerificationEndpointPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
@ -254,7 +254,7 @@ public static class OpenIddictServerAspNetCoreHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(_options.CurrentValue.EnableVerificationEndpointPassthrough);
return new(_options.CurrentValue.EnableEndUserVerificationEndpointPassthrough);
}
}
}

38
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Device.cs

@ -18,38 +18,38 @@ public static partial class OpenIddictServerAspNetCoreHandlers
/*
* Device request extraction:
*/
ExtractPostRequest<ExtractDeviceRequestContext>.Descriptor,
ValidateClientAuthenticationMethod<ExtractDeviceRequestContext>.Descriptor,
ExtractBasicAuthenticationCredentials<ExtractDeviceRequestContext>.Descriptor,
ExtractPostRequest<ExtractDeviceAuthorizationRequestContext>.Descriptor,
ValidateClientAuthenticationMethod<ExtractDeviceAuthorizationRequestContext>.Descriptor,
ExtractBasicAuthenticationCredentials<ExtractDeviceAuthorizationRequestContext>.Descriptor,
/*
* Device response processing:
*/
AttachHttpResponseCode<ApplyDeviceResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyDeviceResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyDeviceResponseContext>.Descriptor,
ProcessJsonResponse<ApplyDeviceResponseContext>.Descriptor,
AttachHttpResponseCode<ApplyDeviceAuthorizationResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyDeviceAuthorizationResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyDeviceAuthorizationResponseContext>.Descriptor,
ProcessJsonResponse<ApplyDeviceAuthorizationResponseContext>.Descriptor,
/*
* Verification request extraction:
*/
ExtractGetOrPostRequest<ExtractVerificationRequestContext>.Descriptor,
ExtractGetOrPostRequest<ExtractEndUserVerificationRequestContext>.Descriptor,
/*
* Verification request handling:
*/
EnablePassthroughMode<HandleVerificationRequestContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor,
EnablePassthroughMode<HandleEndUserVerificationRequestContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor,
/*
* Verification response processing:
*/
AttachHttpResponseCode<ApplyVerificationResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyVerificationResponseContext>.Descriptor,
AttachHttpResponseCode<ApplyEndUserVerificationResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyEndUserVerificationResponseContext>.Descriptor,
ProcessHostRedirectionResponse.Descriptor,
ProcessPassthroughErrorResponse<ApplyVerificationResponseContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor,
ProcessStatusCodePagesErrorResponse<ApplyVerificationResponseContext>.Descriptor,
ProcessLocalErrorResponse<ApplyVerificationResponseContext>.Descriptor,
ProcessEmptyResponse<ApplyVerificationResponseContext>.Descriptor
ProcessPassthroughErrorResponse<ApplyEndUserVerificationResponseContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor,
ProcessStatusCodePagesErrorResponse<ApplyEndUserVerificationResponseContext>.Descriptor,
ProcessLocalErrorResponse<ApplyEndUserVerificationResponseContext>.Descriptor,
ProcessEmptyResponse<ApplyEndUserVerificationResponseContext>.Descriptor
]);
}
@ -57,21 +57,21 @@ public static partial class OpenIddictServerAspNetCoreHandlers
/// Contains the logic responsible for processing verification responses that should trigger a host redirection.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary>
public sealed class ProcessHostRedirectionResponse : IOpenIddictServerHandler<ApplyVerificationResponseContext>
public sealed class ProcessHostRedirectionResponse : IOpenIddictServerHandler<ApplyEndUserVerificationResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyVerificationResponseContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyEndUserVerificationResponseContext>()
.AddFilter<RequireHttpRequest>()
.UseSingletonHandler<ProcessHostRedirectionResponse>()
.SetOrder(ProcessPassthroughErrorResponse<ApplyVerificationResponseContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor.Order - 1_000)
.SetOrder(ProcessPassthroughErrorResponse<ApplyEndUserVerificationResponseContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor.Order - 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyVerificationResponseContext context)
public ValueTask HandleAsync(ApplyEndUserVerificationResponseContext context)
{
if (context is null)
{

8
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Discovery.cs

@ -28,14 +28,14 @@ public static partial class OpenIddictServerAspNetCoreHandlers
/*
* Cryptography request extraction:
*/
ExtractGetRequest<ExtractCryptographyRequestContext>.Descriptor,
ExtractGetRequest<ExtractJsonWebKeySetRequestContext>.Descriptor,
/*
* Cryptography response processing:
*/
AttachHttpResponseCode<ApplyCryptographyResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyCryptographyResponseContext>.Descriptor,
ProcessJsonResponse<ApplyCryptographyResponseContext>.Descriptor
AttachHttpResponseCode<ApplyJsonWebKeySetResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyJsonWebKeySetResponseContext>.Descriptor,
ProcessJsonResponse<ApplyJsonWebKeySetResponseContext>.Descriptor
]);
}
}

92
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs

@ -29,34 +29,34 @@ public static partial class OpenIddictServerAspNetCoreHandlers
/*
* Logout request extraction:
*/
ExtractGetOrPostRequest<ExtractLogoutRequestContext>.Descriptor,
ExtractGetOrPostRequest<ExtractEndSessionRequestContext>.Descriptor,
RestoreCachedRequestParameters.Descriptor,
CacheRequestParameters.Descriptor,
/*
* Logout request handling:
*/
EnablePassthroughMode<HandleLogoutRequestContext, RequireLogoutEndpointPassthroughEnabled>.Descriptor,
EnablePassthroughMode<HandleEndSessionRequestContext, RequireEndSessionEndpointPassthroughEnabled>.Descriptor,
/*
* Logout response processing:
*/
RemoveCachedRequest.Descriptor,
AttachHttpResponseCode<ApplyLogoutResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyLogoutResponseContext>.Descriptor,
AttachHttpResponseCode<ApplyEndSessionResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyEndSessionResponseContext>.Descriptor,
ProcessHostRedirectionResponse.Descriptor,
ProcessPassthroughErrorResponse<ApplyLogoutResponseContext, RequireLogoutEndpointPassthroughEnabled>.Descriptor,
ProcessStatusCodePagesErrorResponse<ApplyLogoutResponseContext>.Descriptor,
ProcessLocalErrorResponse<ApplyLogoutResponseContext>.Descriptor,
ProcessPassthroughErrorResponse<ApplyEndSessionResponseContext, RequireEndSessionEndpointPassthroughEnabled>.Descriptor,
ProcessStatusCodePagesErrorResponse<ApplyEndSessionResponseContext>.Descriptor,
ProcessLocalErrorResponse<ApplyEndSessionResponseContext>.Descriptor,
ProcessQueryResponse.Descriptor,
ProcessEmptyResponse<ApplyLogoutResponseContext>.Descriptor
ProcessEmptyResponse<ApplyEndSessionResponseContext>.Descriptor
]);
/// <summary>
/// Contains the logic responsible for restoring cached requests from the request_id, if specified.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary>
public sealed class RestoreCachedRequestParameters : IOpenIddictServerHandler<ExtractLogoutRequestContext>
public sealed class RestoreCachedRequestParameters : IOpenIddictServerHandler<ExtractEndSessionRequestContext>
{
private readonly IDistributedCache _cache;
@ -69,16 +69,16 @@ public static partial class OpenIddictServerAspNetCoreHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ExtractLogoutRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ExtractEndSessionRequestContext>()
.AddFilter<RequireHttpRequest>()
.AddFilter<RequireLogoutRequestCachingEnabled>()
.AddFilter<RequireEndSessionRequestCachingEnabled>()
.UseSingletonHandler<RestoreCachedRequestParameters>()
.SetOrder(ExtractGetOrPostRequest<ExtractLogoutRequestContext>.Descriptor.Order + 1_000)
.SetOrder(ExtractGetOrPostRequest<ExtractEndSessionRequestContext>.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ExtractLogoutRequestContext context)
public async ValueTask HandleAsync(ExtractEndSessionRequestContext context)
{
if (context is null)
{
@ -87,8 +87,8 @@ public static partial class OpenIddictServerAspNetCoreHandlers
Debug.Assert(context.Request is not null, SR.GetResourceString(SR.ID4008));
// If a request_id parameter can be found in the logout request,
// restore the complete logout request from the distributed cache.
// If a request_id parameter can be found in the end session request,
// restore the complete end session request from the distributed cache.
if (string.IsNullOrEmpty(context.Request.RequestId))
{
@ -97,7 +97,7 @@ public static partial class OpenIddictServerAspNetCoreHandlers
// Note: the cache key is always prefixed with a specific marker
// to avoid collisions with the other types of cached payloads.
var token = await _cache.GetStringAsync(Cache.LogoutRequest + context.Request.RequestId);
var token = await _cache.GetStringAsync(Cache.EndSessionRequest + context.Request.RequestId);
if (token is null || !context.Options.JsonWebTokenHandler.CanReadToken(token))
{
context.Logger.LogInformation(SR.GetResourceString(SR.ID6150), Parameters.RequestId);
@ -113,7 +113,7 @@ public static partial class OpenIddictServerAspNetCoreHandlers
var parameters = context.Options.TokenValidationParameters.Clone();
parameters.ValidIssuer ??= (context.Options.Issuer ?? context.BaseUri)?.AbsoluteUri;
parameters.ValidAudience ??= parameters.ValidIssuer;
parameters.ValidTypes = [JsonWebTokenTypes.Private.LogoutRequest];
parameters.ValidTypes = [JsonWebTokenTypes.Private.EndSessionRequest];
var result = await context.Options.JsonWebTokenHandler.ValidateTokenAsync(token, parameters);
if (!result.IsValid)
@ -147,10 +147,10 @@ public static partial class OpenIddictServerAspNetCoreHandlers
}
/// <summary>
/// Contains the logic responsible for caching logout requests, if applicable.
/// Contains the logic responsible for caching end session requests, if applicable.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary>
public sealed class CacheRequestParameters : IOpenIddictServerHandler<ExtractLogoutRequestContext>
public sealed class CacheRequestParameters : IOpenIddictServerHandler<ExtractEndSessionRequestContext>
{
private readonly IDistributedCache _cache;
private readonly IOptionsMonitor<OpenIddictServerAspNetCoreOptions> _options;
@ -169,16 +169,16 @@ public static partial class OpenIddictServerAspNetCoreHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ExtractLogoutRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ExtractEndSessionRequestContext>()
.AddFilter<RequireHttpRequest>()
.AddFilter<RequireLogoutRequestCachingEnabled>()
.AddFilter<RequireEndSessionRequestCachingEnabled>()
.UseSingletonHandler<CacheRequestParameters>()
.SetOrder(RestoreCachedRequestParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ExtractLogoutRequestContext context)
public async ValueTask HandleAsync(ExtractEndSessionRequestContext context)
{
if (context is null)
{
@ -198,7 +198,7 @@ public static partial class OpenIddictServerAspNetCoreHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0114));
// Don't cache the request if the request doesn't include any parameter.
// If a request_id parameter can be found in the logout request,
// If a request_id parameter can be found in the end session request,
// ignore the following logic to prevent an infinite redirect loop.
if (context.Request.Count is 0 || !string.IsNullOrEmpty(context.Request.RequestId))
{
@ -228,7 +228,7 @@ public static partial class OpenIddictServerAspNetCoreHandlers
}
select new Claim(parameter.Key, element.ToString()!, type);
// Store the serialized logout request parameters in the distributed cache.
// Store the serialized end session request parameters in the distributed cache.
var token = context.Options.JsonWebTokenHandler.CreateToken(new SecurityTokenDescriptor
{
Audience = (context.Options.Issuer ?? context.BaseUri)?.AbsoluteUri,
@ -236,15 +236,15 @@ public static partial class OpenIddictServerAspNetCoreHandlers
Issuer = (context.Options.Issuer ?? context.BaseUri)?.AbsoluteUri,
SigningCredentials = context.Options.SigningCredentials.First(),
Subject = new ClaimsIdentity(claims, TokenValidationParameters.DefaultAuthenticationType),
TokenType = JsonWebTokenTypes.Private.LogoutRequest
TokenType = JsonWebTokenTypes.Private.EndSessionRequest
});
// Note: the cache key is always prefixed with a specific marker
// to avoid collisions with the other types of cached payloads.
await _cache.SetStringAsync(Cache.LogoutRequest + context.Request.RequestId,
token, _options.CurrentValue.LogoutRequestCachingPolicy);
await _cache.SetStringAsync(Cache.EndSessionRequest + context.Request.RequestId,
token, _options.CurrentValue.EndSessionRequestCachingPolicy);
// Create a new GET logout request containing only the request_id parameter.
// Create a new GET end session request containing only the request_id parameter.
var location = QueryHelpers.AddQueryString(
uri: new UriBuilder(context.RequestUri) { Query = null }.Uri.AbsoluteUri,
name: Parameters.RequestId,
@ -258,10 +258,10 @@ public static partial class OpenIddictServerAspNetCoreHandlers
}
/// <summary>
/// Contains the logic responsible for removing cached logout requests from the distributed cache.
/// Contains the logic responsible for removing cached end session requests from the distributed cache.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary>
public sealed class RemoveCachedRequest : IOpenIddictServerHandler<ApplyLogoutResponseContext>
public sealed class RemoveCachedRequest : IOpenIddictServerHandler<ApplyEndSessionResponseContext>
{
private readonly IDistributedCache _cache;
@ -274,16 +274,16 @@ public static partial class OpenIddictServerAspNetCoreHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyLogoutResponseContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyEndSessionResponseContext>()
.AddFilter<RequireHttpRequest>()
.AddFilter<RequireLogoutRequestCachingEnabled>()
.AddFilter<RequireEndSessionRequestCachingEnabled>()
.UseSingletonHandler<RemoveCachedRequest>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyLogoutResponseContext context)
public ValueTask HandleAsync(ApplyEndSessionResponseContext context)
{
if (context is null)
{
@ -295,27 +295,27 @@ public static partial class OpenIddictServerAspNetCoreHandlers
return default;
}
// Note: the ApplyLogoutResponse event is called for both successful
// and errored logout responses but discrimination is not necessary here,
// as the logout request must be removed from the distributed cache in both cases.
// Note: the ApplyEndSessionResponse event is called for both successful
// and errored end session responses but discrimination is not necessary here,
// as the end session request must be removed from the distributed cache in both cases.
// Note: the cache key is always prefixed with a specific marker
// to avoid collisions with the other types of cached payloads.
return new(_cache.RemoveAsync(Cache.LogoutRequest + context.Request.RequestId));
return new(_cache.RemoveAsync(Cache.EndSessionRequest + context.Request.RequestId));
}
}
/// <summary>
/// Contains the logic responsible for processing logout responses.
/// Contains the logic responsible for processing end session responses.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary>
public sealed class ProcessQueryResponse : IOpenIddictServerHandler<ApplyLogoutResponseContext>
public sealed class ProcessQueryResponse : IOpenIddictServerHandler<ApplyEndSessionResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyLogoutResponseContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyEndSessionResponseContext>()
.AddFilter<RequireHttpRequest>()
.UseSingletonHandler<ProcessQueryResponse>()
.SetOrder(250_000)
@ -323,7 +323,7 @@ public static partial class OpenIddictServerAspNetCoreHandlers
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyLogoutResponseContext context)
public ValueTask HandleAsync(ApplyEndSessionResponseContext context)
{
if (context is null)
{
@ -376,24 +376,24 @@ public static partial class OpenIddictServerAspNetCoreHandlers
}
/// <summary>
/// Contains the logic responsible for processing logout responses that should trigger a host redirection.
/// Contains the logic responsible for processing end session responses that should trigger a host redirection.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary>
public sealed class ProcessHostRedirectionResponse : IOpenIddictServerHandler<ApplyLogoutResponseContext>
public sealed class ProcessHostRedirectionResponse : IOpenIddictServerHandler<ApplyEndSessionResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyLogoutResponseContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyEndSessionResponseContext>()
.AddFilter<RequireHttpRequest>()
.UseSingletonHandler<ProcessHostRedirectionResponse>()
.SetOrder(ProcessPassthroughErrorResponse<ApplyLogoutResponseContext, RequireLogoutEndpointPassthroughEnabled>.Descriptor.Order + 250)
.SetOrder(ProcessPassthroughErrorResponse<ApplyEndSessionResponseContext, RequireEndSessionEndpointPassthroughEnabled>.Descriptor.Order + 250)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyLogoutResponseContext context)
public ValueTask HandleAsync(ApplyEndSessionResponseContext context)
{
if (context is null)
{

22
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Userinfo.cs

@ -10,27 +10,27 @@ namespace OpenIddict.Server.AspNetCore;
public static partial class OpenIddictServerAspNetCoreHandlers
{
public static class Userinfo
public static class UserInfo
{
public static ImmutableArray<OpenIddictServerHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create([
/*
* Userinfo request extraction:
* UserInfo request extraction:
*/
ExtractGetOrPostRequest<ExtractUserinfoRequestContext>.Descriptor,
ExtractAccessToken<ExtractUserinfoRequestContext>.Descriptor,
ExtractGetOrPostRequest<ExtractUserInfoRequestContext>.Descriptor,
ExtractAccessToken<ExtractUserInfoRequestContext>.Descriptor,
/*
* Userinfo request handling:
* UserInfo request handling:
*/
EnablePassthroughMode<HandleUserinfoRequestContext, RequireUserinfoEndpointPassthroughEnabled>.Descriptor,
EnablePassthroughMode<HandleUserInfoRequestContext, RequireUserInfoEndpointPassthroughEnabled>.Descriptor,
/*
* Userinfo response processing:
* UserInfo response processing:
*/
AttachHttpResponseCode<ApplyUserinfoResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyUserinfoResponseContext>.Descriptor,
ProcessChallengeErrorResponse<ApplyUserinfoResponseContext>.Descriptor,
ProcessJsonResponse<ApplyUserinfoResponseContext>.Descriptor
AttachHttpResponseCode<ApplyUserInfoResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyUserInfoResponseContext>.Descriptor,
ProcessChallengeErrorResponse<ApplyUserInfoResponseContext>.Descriptor,
ProcessJsonResponse<ApplyUserInfoResponseContext>.Descriptor
]);
}
}

10
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs

@ -59,7 +59,7 @@ public static partial class OpenIddictServerAspNetCoreHandlers
.. Introspection.DefaultHandlers,
.. Revocation.DefaultHandlers,
.. Session.DefaultHandlers,
.. Userinfo.DefaultHandlers
.. UserInfo.DefaultHandlers
]);
/// <summary>
@ -933,15 +933,15 @@ public static partial class OpenIddictServerAspNetCoreHandlers
// errors returned by API endpoints implementing bearer token authentication and MUST be returned
// as part of the standard WWW-Authenticate header. For more information, see
// https://openid.net/specs/openid-connect-core-1_0.html#UserInfoError.
(OpenIddictServerEndpointType.Userinfo, Errors.InvalidToken or Errors.MissingToken) => 401,
(OpenIddictServerEndpointType.Userinfo, Errors.InsufficientAccess or Errors.InsufficientScope) => 403,
(OpenIddictServerEndpointType.UserInfo, Errors.InvalidToken or Errors.MissingToken) => 401,
(OpenIddictServerEndpointType.UserInfo, Errors.InsufficientAccess or Errors.InsufficientScope) => 403,
// When client authentication is made using basic authentication, the authorization server
// MUST return a 401 response with a valid WWW-Authenticate header containing the HTTP Basic
// authentication scheme. A similar error MAY be returned even when using client_secret_post.
// To simplify the logic, a 401 response with the Basic scheme is returned for invalid_client
// errors, even if credentials were specified in the form, as allowed by the specification.
(not OpenIddictServerEndpointType.Userinfo, Errors.InvalidClient) => 401,
(not OpenIddictServerEndpointType.UserInfo, Errors.InvalidClient) => 401,
(_, Errors.ServerError) => 500,
@ -1041,7 +1041,7 @@ public static partial class OpenIddictServerAspNetCoreHandlers
// logic as errors returned by API endpoints implementing bearer token authentication and
// MUST be returned as part of the standard WWW-Authenticate header. For more information,
// see https://openid.net/specs/openid-connect-core-1_0.html#UserInfoError.
(OpenIddictServerEndpointType.Userinfo, _) => Schemes.Bearer,
(OpenIddictServerEndpointType.UserInfo, _) => Schemes.Bearer,
// When client authentication is made using basic authentication, the authorization server
// MUST return a 401 response with a valid WWW-Authenticate header containing the HTTP Basic

44
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreOptions.cs

@ -28,9 +28,25 @@ public sealed class OpenIddictServerAspNetCoreOptions : AuthenticationSchemeOpti
/// </summary>
public bool EnableAuthorizationEndpointPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the end session endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
public bool EnableEndSessionEndpointPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the end-user verification endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
public bool EnableEndUserVerificationEndpointPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether OpenIddict should allow the rest of the request processing pipeline
/// to be invoked when returning an error from the interactive authorization and logout endpoints.
/// to be invoked when returning an error from the interactive authorization and end session endpoints.
/// When this option is enabled, special logic must be added to these actions to handle errors, that can be
/// retrieved using <see cref="OpenIddictServerAspNetCoreHelpers.GetOpenIddictServerResponse(HttpContext)"/>.
/// </summary>
@ -39,14 +55,6 @@ public sealed class OpenIddictServerAspNetCoreOptions : AuthenticationSchemeOpti
/// </remarks>
public bool EnableErrorPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the logout endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
public bool EnableLogoutEndpointPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the token endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
@ -61,15 +69,7 @@ public sealed class OpenIddictServerAspNetCoreOptions : AuthenticationSchemeOpti
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
public bool EnableUserinfoEndpointPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the user verification endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
public bool EnableVerificationEndpointPassthrough { get; set; }
public bool EnableUserInfoEndpointPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether requests received by the authorization endpoint
@ -81,10 +81,10 @@ public sealed class OpenIddictServerAspNetCoreOptions : AuthenticationSchemeOpti
public bool EnableAuthorizationRequestCaching { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether requests received by the logout endpoint should be cached.
/// Gets or sets a boolean indicating whether requests received by the end session endpoint should be cached.
/// When enabled, authorization requests are automatically stored in the distributed cache.
/// </summary>
public bool EnableLogoutRequestCaching { get; set; }
public bool EnableEndSessionRequestCaching { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether integration with the status code pages
@ -113,9 +113,9 @@ public sealed class OpenIddictServerAspNetCoreOptions : AuthenticationSchemeOpti
};
/// <summary>
/// Gets or sets the caching policy used by the logout endpoint.
/// Gets or sets the caching policy used by the end session endpoint.
/// </summary>
public DistributedCacheEntryOptions LogoutRequestCachingPolicy { get; set; } = new()
public DistributedCacheEntryOptions EndSessionRequestCachingPolicy { get; set; } = new()
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1),
SlidingExpiration = TimeSpan.FromMinutes(30)

56
src/OpenIddict.Server.Owin/OpenIddictServerOwinBuilder.cs

@ -66,55 +66,55 @@ public sealed class OpenIddictServerOwinBuilder
=> Configure(options => options.EnableAuthorizationEndpointPassthrough = true);
/// <summary>
/// Enables error pass-through support, so that the rest of the request processing pipeline is
/// automatically invoked when returning an error from the interactive authorization and logout endpoints.
/// When this option is enabled, special logic must be added to these actions to handle errors, that can be
/// retrieved using <see cref="OpenIddictServerOwinHelpers.GetOpenIddictServerResponse(IOwinContext)"/>
/// Enables the pass-through mode for the OpenID Connect end session endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
/// <returns>The <see cref="OpenIddictServerOwinBuilder"/> instance.</returns>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public OpenIddictServerOwinBuilder EnableErrorPassthrough()
=> Configure(options => options.EnableErrorPassthrough = true);
public OpenIddictServerOwinBuilder EnableEndSessionEndpointPassthrough()
=> Configure(options => options.EnableEndSessionEndpointPassthrough = true);
/// <summary>
/// Enables the pass-through mode for the OpenID Connect logout endpoint.
/// Enables the pass-through mode for the OpenID Connect end-user verification endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
/// <returns>The <see cref="OpenIddictServerOwinBuilder"/> instance.</returns>
public OpenIddictServerOwinBuilder EnableLogoutEndpointPassthrough()
=> Configure(options => options.EnableLogoutEndpointPassthrough = true);
public OpenIddictServerOwinBuilder EnableEndUserVerificationEndpointPassthrough()
=> Configure(options => options.EnableEndUserVerificationEndpointPassthrough = true);
/// <summary>
/// Enables the pass-through mode for the OpenID Connect token endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// Enables error pass-through support, so that the rest of the request processing pipeline is
/// automatically invoked when returning an error from the interactive authorization and end session endpoints.
/// When this option is enabled, special logic must be added to these actions to handle errors, that can be
/// retrieved using <see cref="OpenIddictServerOwinHelpers.GetOpenIddictServerResponse(IOwinContext)"/>
/// </summary>
/// <returns>The <see cref="OpenIddictServerOwinBuilder"/> instance.</returns>
public OpenIddictServerOwinBuilder EnableTokenEndpointPassthrough()
=> Configure(options => options.EnableTokenEndpointPassthrough = true);
[EditorBrowsable(EditorBrowsableState.Advanced)]
public OpenIddictServerOwinBuilder EnableErrorPassthrough()
=> Configure(options => options.EnableErrorPassthrough = true);
/// <summary>
/// Enables the pass-through mode for the OpenID Connect userinfo endpoint.
/// Enables the pass-through mode for the OpenID Connect token endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
/// <returns>The <see cref="OpenIddictServerOwinBuilder"/> instance.</returns>
public OpenIddictServerOwinBuilder EnableUserinfoEndpointPassthrough()
=> Configure(options => options.EnableUserinfoEndpointPassthrough = true);
public OpenIddictServerOwinBuilder EnableTokenEndpointPassthrough()
=> Configure(options => options.EnableTokenEndpointPassthrough = true);
/// <summary>
/// Enables the pass-through mode for the OpenID Connect user verification endpoint.
/// Enables the pass-through mode for the OpenID Connect userinfo endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
/// <returns>The <see cref="OpenIddictServerOwinBuilder"/> instance.</returns>
public OpenIddictServerOwinBuilder EnableVerificationEndpointPassthrough()
=> Configure(options => options.EnableVerificationEndpointPassthrough = true);
public OpenIddictServerOwinBuilder EnableUserInfoEndpointPassthrough()
=> Configure(options => options.EnableUserInfoEndpointPassthrough = true);
/// <summary>
/// Enables authorization request caching, so that authorization requests
@ -128,12 +128,12 @@ public sealed class OpenIddictServerOwinBuilder
=> Configure(options => options.EnableAuthorizationRequestCaching = true);
/// <summary>
/// Enables logout request caching, so that logout requests
/// Enables end session request caching, so that end session requests
/// are automatically stored in the distributed cache.
/// </summary>
/// <returns>The <see cref="OpenIddictServerOwinBuilder"/> instance.</returns>
public OpenIddictServerOwinBuilder EnableLogoutRequestCaching()
=> Configure(options => options.EnableLogoutRequestCaching = true);
public OpenIddictServerOwinBuilder EnableEndSessionRequestCaching()
=> Configure(options => options.EnableEndSessionRequestCaching = true);
/// <summary>
/// Suppresses indentation for the JSON responses returned by the OWIN host.
@ -174,19 +174,19 @@ public sealed class OpenIddictServerOwinBuilder
}
/// <summary>
/// Sets the caching policy used by the logout endpoint.
/// Sets the caching policy used by the end session endpoint.
/// Note: the specified policy is only used when caching is explicitly enabled.
/// </summary>
/// <param name="policy">The caching policy.</param>
/// <returns>The <see cref="OpenIddictServerOwinBuilder"/> instance.</returns>
public OpenIddictServerOwinBuilder SetLogoutRequestCachingPolicy(DistributedCacheEntryOptions policy)
public OpenIddictServerOwinBuilder SetEndSessionRequestCachingPolicy(DistributedCacheEntryOptions policy)
{
if (policy is null)
{
throw new ArgumentNullException(nameof(policy));
}
return Configure(options => options.LogoutRequestCachingPolicy = policy);
return Configure(options => options.EndSessionRequestCachingPolicy = policy);
}
/// <inheritdoc/>

4
src/OpenIddict.Server.Owin/OpenIddictServerOwinConstants.cs

@ -14,7 +14,7 @@ public static class OpenIddictServerOwinConstants
public static class Cache
{
public const string AuthorizationRequest = "openiddict-authorization-request:";
public const string LogoutRequest = "openiddict-logout-request:";
public const string EndSessionRequest = "openiddict-end_session-request:";
}
public static class Headers
@ -33,7 +33,7 @@ public static class OpenIddictServerOwinConstants
public static class Private
{
public const string AuthorizationRequest = "oi_authrq+jwt";
public const string LogoutRequest = "oi_lgtrq+jwt";
public const string EndSessionRequest = "oi_endsessrq+jwt";
}
}

6
src/OpenIddict.Server.Owin/OpenIddictServerOwinExtensions.cs

@ -43,13 +43,13 @@ public static class OpenIddictServerOwinExtensions
// Register the built-in filters used by the default OpenIddict OWIN server event handlers.
builder.Services.TryAddSingleton<RequireAuthorizationRequestCachingEnabled>();
builder.Services.TryAddSingleton<RequireAuthorizationEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireEndSessionRequestCachingEnabled>();
builder.Services.TryAddSingleton<RequireEndSessionEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireErrorPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireLogoutRequestCachingEnabled>();
builder.Services.TryAddSingleton<RequireLogoutEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireTransportSecurityRequirementEnabled>();
builder.Services.TryAddSingleton<RequireOwinRequest>();
builder.Services.TryAddSingleton<RequireTokenEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireUserinfoEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireUserInfoEndpointPassthroughEnabled>();
builder.Services.TryAddSingleton<RequireVerificationEndpointPassthroughEnabled>();
// Register the option initializers used by the OpenIddict OWIN server integration services.

8
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs

@ -166,9 +166,11 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<OpenIddi
// A single main claims-based principal instance can be attached to an authentication ticket.
var principal = context.EndpointType switch
{
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Logout
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.EndSession
=> context.IdentityTokenPrincipal,
OpenIddictServerEndpointType.EndUserVerification => context.UserCodePrincipal,
OpenIddictServerEndpointType.Introspection or OpenIddictServerEndpointType.Revocation
=> context.AccessTokenPrincipal ??
context.RefreshTokenPrincipal ??
@ -184,9 +186,7 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<OpenIddi
OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType()
=> context.RefreshTokenPrincipal,
OpenIddictServerEndpointType.Userinfo => context.AccessTokenPrincipal,
OpenIddictServerEndpointType.Verification => context.UserCodePrincipal,
OpenIddictServerEndpointType.UserInfo => context.AccessTokenPrincipal,
_ => null
};

36
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlerFilters.cs

@ -60,13 +60,13 @@ public static class OpenIddictServerOwinHandlerFilters
}
/// <summary>
/// Represents a filter that excludes the associated handlers if error pass-through was not enabled.
/// Represents a filter that excludes the associated handlers if end session request caching was not enabled.
/// </summary>
public sealed class RequireErrorPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireEndSessionRequestCachingEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerOwinOptions> _options;
public RequireErrorPassthroughEnabled(IOptionsMonitor<OpenIddictServerOwinOptions> options)
public RequireEndSessionRequestCachingEnabled(IOptionsMonitor<OpenIddictServerOwinOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
@ -77,18 +77,19 @@ public static class OpenIddictServerOwinHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(_options.CurrentValue.EnableErrorPassthrough);
return new(_options.CurrentValue.EnableEndSessionRequestCaching);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if logout request caching was not enabled.
/// Represents a filter that excludes the associated handlers if the
/// pass-through mode was not enabled for the end session endpoint.
/// </summary>
public sealed class RequireLogoutRequestCachingEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireEndSessionEndpointPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerOwinOptions> _options;
public RequireLogoutRequestCachingEnabled(IOptionsMonitor<OpenIddictServerOwinOptions> options)
public RequireEndSessionEndpointPassthroughEnabled(IOptionsMonitor<OpenIddictServerOwinOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
@ -99,19 +100,18 @@ public static class OpenIddictServerOwinHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(_options.CurrentValue.EnableLogoutRequestCaching);
return new(_options.CurrentValue.EnableEndSessionEndpointPassthrough);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the
/// pass-through mode was not enabled for the logout endpoint.
/// Represents a filter that excludes the associated handlers if error pass-through was not enabled.
/// </summary>
public sealed class RequireLogoutEndpointPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireErrorPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerOwinOptions> _options;
public RequireLogoutEndpointPassthroughEnabled(IOptionsMonitor<OpenIddictServerOwinOptions> options)
public RequireErrorPassthroughEnabled(IOptionsMonitor<OpenIddictServerOwinOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
@ -122,7 +122,7 @@ public static class OpenIddictServerOwinHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(_options.CurrentValue.EnableLogoutEndpointPassthrough);
return new(_options.CurrentValue.EnableErrorPassthrough);
}
}
@ -192,11 +192,11 @@ public static class OpenIddictServerOwinHandlerFilters
/// Represents a filter that excludes the associated handlers if the
/// pass-through mode was not enabled for the userinfo endpoint.
/// </summary>
public sealed class RequireUserinfoEndpointPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireUserInfoEndpointPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerOwinOptions> _options;
public RequireUserinfoEndpointPassthroughEnabled(IOptionsMonitor<OpenIddictServerOwinOptions> options)
public RequireUserInfoEndpointPassthroughEnabled(IOptionsMonitor<OpenIddictServerOwinOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
@ -207,13 +207,13 @@ public static class OpenIddictServerOwinHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(_options.CurrentValue.EnableUserinfoEndpointPassthrough);
return new(_options.CurrentValue.EnableUserInfoEndpointPassthrough);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the
/// pass-through mode was not enabled for the verification endpoint.
/// pass-through mode was not enabled for the end-user verification endpoint.
/// </summary>
public sealed class RequireVerificationEndpointPassthroughEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
@ -230,7 +230,7 @@ public static class OpenIddictServerOwinHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(_options.CurrentValue.EnableVerificationEndpointPassthrough);
return new(_options.CurrentValue.EnableEndUserVerificationEndpointPassthrough);
}
}
}

44
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Device.cs

@ -18,41 +18,41 @@ public static partial class OpenIddictServerOwinHandlers
/*
* Device request extraction:
*/
ExtractPostRequest<ExtractDeviceRequestContext>.Descriptor,
ValidateClientAuthenticationMethod<ExtractDeviceRequestContext>.Descriptor,
ExtractBasicAuthenticationCredentials<ExtractDeviceRequestContext>.Descriptor,
ExtractPostRequest<ExtractDeviceAuthorizationRequestContext>.Descriptor,
ValidateClientAuthenticationMethod<ExtractDeviceAuthorizationRequestContext>.Descriptor,
ExtractBasicAuthenticationCredentials<ExtractDeviceAuthorizationRequestContext>.Descriptor,
/*
* Device response processing:
*/
AttachHttpResponseCode<ApplyDeviceResponseContext>.Descriptor,
AttachOwinResponseChallenge<ApplyDeviceResponseContext>.Descriptor,
SuppressFormsAuthenticationRedirect<ApplyDeviceResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyDeviceResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyDeviceResponseContext>.Descriptor,
ProcessJsonResponse<ApplyDeviceResponseContext>.Descriptor,
AttachHttpResponseCode<ApplyDeviceAuthorizationResponseContext>.Descriptor,
AttachOwinResponseChallenge<ApplyDeviceAuthorizationResponseContext>.Descriptor,
SuppressFormsAuthenticationRedirect<ApplyDeviceAuthorizationResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyDeviceAuthorizationResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyDeviceAuthorizationResponseContext>.Descriptor,
ProcessJsonResponse<ApplyDeviceAuthorizationResponseContext>.Descriptor,
/*
* Verification request extraction:
*/
ExtractGetOrPostRequest<ExtractVerificationRequestContext>.Descriptor,
ExtractGetOrPostRequest<ExtractEndUserVerificationRequestContext>.Descriptor,
/*
* Verification request handling:
*/
EnablePassthroughMode<HandleVerificationRequestContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor,
EnablePassthroughMode<HandleEndUserVerificationRequestContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor,
/*
* Verification response processing:
*/
AttachHttpResponseCode<ApplyVerificationResponseContext>.Descriptor,
AttachOwinResponseChallenge<ApplyVerificationResponseContext>.Descriptor,
SuppressFormsAuthenticationRedirect<ApplyVerificationResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyVerificationResponseContext>.Descriptor,
AttachHttpResponseCode<ApplyEndUserVerificationResponseContext>.Descriptor,
AttachOwinResponseChallenge<ApplyEndUserVerificationResponseContext>.Descriptor,
SuppressFormsAuthenticationRedirect<ApplyEndUserVerificationResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyEndUserVerificationResponseContext>.Descriptor,
ProcessHostRedirectionResponse.Descriptor,
ProcessPassthroughErrorResponse<ApplyVerificationResponseContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor,
ProcessLocalErrorResponse<ApplyVerificationResponseContext>.Descriptor,
ProcessEmptyResponse<ApplyVerificationResponseContext>.Descriptor
ProcessPassthroughErrorResponse<ApplyEndUserVerificationResponseContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor,
ProcessLocalErrorResponse<ApplyEndUserVerificationResponseContext>.Descriptor,
ProcessEmptyResponse<ApplyEndUserVerificationResponseContext>.Descriptor
]);
}
@ -60,21 +60,21 @@ public static partial class OpenIddictServerOwinHandlers
/// Contains the logic responsible for processing verification responses that should trigger a host redirection.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
/// </summary>
public sealed class ProcessHostRedirectionResponse : IOpenIddictServerHandler<ApplyVerificationResponseContext>
public sealed class ProcessHostRedirectionResponse : IOpenIddictServerHandler<ApplyEndUserVerificationResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyVerificationResponseContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyEndUserVerificationResponseContext>()
.AddFilter<RequireOwinRequest>()
.UseSingletonHandler<ProcessHostRedirectionResponse>()
.SetOrder(ProcessPassthroughErrorResponse<ApplyVerificationResponseContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor.Order - 1_000)
.SetOrder(ProcessPassthroughErrorResponse<ApplyEndUserVerificationResponseContext, RequireVerificationEndpointPassthroughEnabled>.Descriptor.Order - 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyVerificationResponseContext context)
public ValueTask HandleAsync(ApplyEndUserVerificationResponseContext context)
{
if (context is null)
{

12
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Discovery.cs

@ -30,16 +30,16 @@ public static partial class OpenIddictServerOwinHandlers
/*
* Cryptography request extraction:
*/
ExtractGetRequest<ExtractCryptographyRequestContext>.Descriptor,
ExtractGetRequest<ExtractJsonWebKeySetRequestContext>.Descriptor,
/*
* Cryptography response processing:
*/
AttachHttpResponseCode<ApplyCryptographyResponseContext>.Descriptor,
AttachOwinResponseChallenge<ApplyCryptographyResponseContext>.Descriptor,
SuppressFormsAuthenticationRedirect<ApplyCryptographyResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyCryptographyResponseContext>.Descriptor,
ProcessJsonResponse<ApplyCryptographyResponseContext>.Descriptor
AttachHttpResponseCode<ApplyJsonWebKeySetResponseContext>.Descriptor,
AttachOwinResponseChallenge<ApplyJsonWebKeySetResponseContext>.Descriptor,
SuppressFormsAuthenticationRedirect<ApplyJsonWebKeySetResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyJsonWebKeySetResponseContext>.Descriptor,
ProcessJsonResponse<ApplyJsonWebKeySetResponseContext>.Descriptor
]);
}
}

94
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs

@ -28,35 +28,35 @@ public static partial class OpenIddictServerOwinHandlers
/*
* Logout request extraction:
*/
ExtractGetOrPostRequest<ExtractLogoutRequestContext>.Descriptor,
ExtractGetOrPostRequest<ExtractEndSessionRequestContext>.Descriptor,
RestoreCachedRequestParameters.Descriptor,
CacheRequestParameters.Descriptor,
/*
* Logout request handling:
*/
EnablePassthroughMode<HandleLogoutRequestContext, RequireLogoutEndpointPassthroughEnabled>.Descriptor,
EnablePassthroughMode<HandleEndSessionRequestContext, RequireEndSessionEndpointPassthroughEnabled>.Descriptor,
/*
* Logout response processing:
*/
RemoveCachedRequest.Descriptor,
AttachHttpResponseCode<ApplyLogoutResponseContext>.Descriptor,
AttachOwinResponseChallenge<ApplyLogoutResponseContext>.Descriptor,
SuppressFormsAuthenticationRedirect<ApplyLogoutResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyLogoutResponseContext>.Descriptor,
AttachHttpResponseCode<ApplyEndSessionResponseContext>.Descriptor,
AttachOwinResponseChallenge<ApplyEndSessionResponseContext>.Descriptor,
SuppressFormsAuthenticationRedirect<ApplyEndSessionResponseContext>.Descriptor,
AttachCacheControlHeader<ApplyEndSessionResponseContext>.Descriptor,
ProcessHostRedirectionResponse.Descriptor,
ProcessPassthroughErrorResponse<ApplyLogoutResponseContext, RequireLogoutEndpointPassthroughEnabled>.Descriptor,
ProcessLocalErrorResponse<ApplyLogoutResponseContext>.Descriptor,
ProcessPassthroughErrorResponse<ApplyEndSessionResponseContext, RequireEndSessionEndpointPassthroughEnabled>.Descriptor,
ProcessLocalErrorResponse<ApplyEndSessionResponseContext>.Descriptor,
ProcessQueryResponse.Descriptor,
ProcessEmptyResponse<ApplyLogoutResponseContext>.Descriptor
ProcessEmptyResponse<ApplyEndSessionResponseContext>.Descriptor
]);
/// <summary>
/// Contains the logic responsible for restoring cached requests from the request_id, if specified.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
/// </summary>
public sealed class RestoreCachedRequestParameters : IOpenIddictServerHandler<ExtractLogoutRequestContext>
public sealed class RestoreCachedRequestParameters : IOpenIddictServerHandler<ExtractEndSessionRequestContext>
{
private readonly IDistributedCache _cache;
@ -69,16 +69,16 @@ public static partial class OpenIddictServerOwinHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ExtractLogoutRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ExtractEndSessionRequestContext>()
.AddFilter<RequireOwinRequest>()
.AddFilter<RequireLogoutRequestCachingEnabled>()
.AddFilter<RequireEndSessionRequestCachingEnabled>()
.UseSingletonHandler<RestoreCachedRequestParameters>()
.SetOrder(ExtractGetOrPostRequest<ExtractLogoutRequestContext>.Descriptor.Order + 1_000)
.SetOrder(ExtractGetOrPostRequest<ExtractEndSessionRequestContext>.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ExtractLogoutRequestContext context)
public async ValueTask HandleAsync(ExtractEndSessionRequestContext context)
{
if (context is null)
{
@ -87,8 +87,8 @@ public static partial class OpenIddictServerOwinHandlers
Debug.Assert(context.Request is not null, SR.GetResourceString(SR.ID4008));
// If a request_id parameter can be found in the logout request,
// restore the complete logout request from the distributed cache.
// If a request_id parameter can be found in the end session request,
// restore the complete end session request from the distributed cache.
if (string.IsNullOrEmpty(context.Request.RequestId))
{
@ -97,7 +97,7 @@ public static partial class OpenIddictServerOwinHandlers
// Note: the cache key is always prefixed with a specific marker
// to avoid collisions with the other types of cached payloads.
var token = await _cache.GetStringAsync(Cache.LogoutRequest + context.Request.RequestId);
var token = await _cache.GetStringAsync(Cache.EndSessionRequest + context.Request.RequestId);
if (token is null || !context.Options.JsonWebTokenHandler.CanReadToken(token))
{
context.Logger.LogInformation(SR.GetResourceString(SR.ID6150), Parameters.RequestId);
@ -113,7 +113,7 @@ public static partial class OpenIddictServerOwinHandlers
var parameters = context.Options.TokenValidationParameters.Clone();
parameters.ValidIssuer ??= (context.Options.Issuer ?? context.BaseUri)?.AbsoluteUri;
parameters.ValidAudience ??= parameters.ValidIssuer;
parameters.ValidTypes = [JsonWebTokenTypes.Private.LogoutRequest];
parameters.ValidTypes = [JsonWebTokenTypes.Private.EndSessionRequest];
var result = await context.Options.JsonWebTokenHandler.ValidateTokenAsync(token, parameters);
if (!result.IsValid)
@ -147,10 +147,10 @@ public static partial class OpenIddictServerOwinHandlers
}
/// <summary>
/// Contains the logic responsible for caching logout requests, if applicable.
/// Contains the logic responsible for caching end session requests, if applicable.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
/// </summary>
public sealed class CacheRequestParameters : IOpenIddictServerHandler<ExtractLogoutRequestContext>
public sealed class CacheRequestParameters : IOpenIddictServerHandler<ExtractEndSessionRequestContext>
{
private readonly IDistributedCache _cache;
private readonly IOptionsMonitor<OpenIddictServerOwinOptions> _options;
@ -169,16 +169,16 @@ public static partial class OpenIddictServerOwinHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ExtractLogoutRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ExtractEndSessionRequestContext>()
.AddFilter<RequireOwinRequest>()
.AddFilter<RequireLogoutRequestCachingEnabled>()
.AddFilter<RequireEndSessionRequestCachingEnabled>()
.UseSingletonHandler<CacheRequestParameters>()
.SetOrder(RestoreCachedRequestParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ExtractLogoutRequestContext context)
public async ValueTask HandleAsync(ExtractEndSessionRequestContext context)
{
if (context is null)
{
@ -198,7 +198,7 @@ public static partial class OpenIddictServerOwinHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0120));
// Don't cache the request if the request doesn't include any parameter.
// If a request_id parameter can be found in the logout request,
// If a request_id parameter can be found in the end session request,
// ignore the following logic to prevent an infinite redirect loop.
if (context.Request.Count is 0 || !string.IsNullOrEmpty(context.Request.RequestId))
{
@ -228,7 +228,7 @@ public static partial class OpenIddictServerOwinHandlers
}
select new Claim(parameter.Key, element.ToString()!, type);
// Store the serialized logout request parameters in the distributed cache.
// Store the serialized end session request parameters in the distributed cache.
var token = context.Options.JsonWebTokenHandler.CreateToken(new SecurityTokenDescriptor
{
Audience = (context.Options.Issuer ?? context.BaseUri)?.AbsoluteUri,
@ -236,15 +236,15 @@ public static partial class OpenIddictServerOwinHandlers
Issuer = (context.Options.Issuer ?? context.BaseUri)?.AbsoluteUri,
SigningCredentials = context.Options.SigningCredentials.First(),
Subject = new ClaimsIdentity(claims, TokenValidationParameters.DefaultAuthenticationType),
TokenType = JsonWebTokenTypes.Private.LogoutRequest
TokenType = JsonWebTokenTypes.Private.EndSessionRequest
});
// Note: the cache key is always prefixed with a specific marker
// to avoid collisions with the other types of cached payloads.
await _cache.SetStringAsync(Cache.LogoutRequest + context.Request.RequestId,
token, _options.CurrentValue.LogoutRequestCachingPolicy);
await _cache.SetStringAsync(Cache.EndSessionRequest + context.Request.RequestId,
token, _options.CurrentValue.EndSessionRequestCachingPolicy);
// Create a new GET logout request containing only the request_id parameter.
// Create a new GET end session request containing only the request_id parameter.
var location = WebUtilities.AddQueryString(
uri: new UriBuilder(context.RequestUri) { Query = null }.Uri.AbsoluteUri,
name: Parameters.RequestId,
@ -258,10 +258,10 @@ public static partial class OpenIddictServerOwinHandlers
}
/// <summary>
/// Contains the logic responsible for removing cached logout requests from the distributed cache.
/// Contains the logic responsible for removing cached end session requests from the distributed cache.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
/// </summary>
public sealed class RemoveCachedRequest : IOpenIddictServerHandler<ApplyLogoutResponseContext>
public sealed class RemoveCachedRequest : IOpenIddictServerHandler<ApplyEndSessionResponseContext>
{
private readonly IDistributedCache _cache;
@ -274,16 +274,16 @@ public static partial class OpenIddictServerOwinHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyLogoutResponseContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyEndSessionResponseContext>()
.AddFilter<RequireOwinRequest>()
.AddFilter<RequireLogoutRequestCachingEnabled>()
.AddFilter<RequireEndSessionRequestCachingEnabled>()
.UseSingletonHandler<RemoveCachedRequest>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyLogoutResponseContext context)
public ValueTask HandleAsync(ApplyEndSessionResponseContext context)
{
if (context is null)
{
@ -295,27 +295,27 @@ public static partial class OpenIddictServerOwinHandlers
return default;
}
// Note: the ApplyLogoutResponse event is called for both successful
// and errored logout responses but discrimination is not necessary here,
// as the logout request must be removed from the distributed cache in both cases.
// Note: the ApplyEndSessionResponse event is called for both successful
// and errored end session responses but discrimination is not necessary here,
// as the end session request must be removed from the distributed cache in both cases.
// Note: the cache key is always prefixed with a specific marker
// to avoid collisions with the other types of cached payloads.
return new(_cache.RemoveAsync(Cache.LogoutRequest + context.Request.RequestId));
return new(_cache.RemoveAsync(Cache.EndSessionRequest + context.Request.RequestId));
}
}
/// <summary>
/// Contains the logic responsible for processing logout responses.
/// Contains the logic responsible for processing end session responses.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
/// </summary>
public sealed class ProcessQueryResponse : IOpenIddictServerHandler<ApplyLogoutResponseContext>
public sealed class ProcessQueryResponse : IOpenIddictServerHandler<ApplyEndSessionResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyLogoutResponseContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyEndSessionResponseContext>()
.AddFilter<RequireOwinRequest>()
.UseSingletonHandler<ProcessQueryResponse>()
.SetOrder(250_000)
@ -323,7 +323,7 @@ public static partial class OpenIddictServerOwinHandlers
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyLogoutResponseContext context)
public ValueTask HandleAsync(ApplyEndSessionResponseContext context)
{
if (context is null)
{
@ -366,24 +366,24 @@ public static partial class OpenIddictServerOwinHandlers
}
/// <summary>
/// Contains the logic responsible for processing logout responses that should trigger a host redirection.
/// Contains the logic responsible for processing end session responses that should trigger a host redirection.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
/// </summary>
public sealed class ProcessHostRedirectionResponse : IOpenIddictServerHandler<ApplyLogoutResponseContext>
public sealed class ProcessHostRedirectionResponse : IOpenIddictServerHandler<ApplyEndSessionResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyLogoutResponseContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyEndSessionResponseContext>()
.AddFilter<RequireOwinRequest>()
.UseSingletonHandler<ProcessHostRedirectionResponse>()
.SetOrder(ProcessPassthroughErrorResponse<ApplyLogoutResponseContext, RequireLogoutEndpointPassthroughEnabled>.Descriptor.Order + 250)
.SetOrder(ProcessPassthroughErrorResponse<ApplyEndSessionResponseContext, RequireEndSessionEndpointPassthroughEnabled>.Descriptor.Order + 250)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyLogoutResponseContext context)
public ValueTask HandleAsync(ApplyEndSessionResponseContext context)
{
if (context is null)
{

26
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Userinfo.cs

@ -10,29 +10,29 @@ namespace OpenIddict.Server.Owin;
public static partial class OpenIddictServerOwinHandlers
{
public static class Userinfo
public static class UserInfo
{
public static ImmutableArray<OpenIddictServerHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create([
/*
* Userinfo request extraction:
* UserInfo request extraction:
*/
ExtractGetOrPostRequest<ExtractUserinfoRequestContext>.Descriptor,
ExtractAccessToken<ExtractUserinfoRequestContext>.Descriptor,
ExtractGetOrPostRequest<ExtractUserInfoRequestContext>.Descriptor,
ExtractAccessToken<ExtractUserInfoRequestContext>.Descriptor,
/*
* Userinfo request handling:
* UserInfo request handling:
*/
EnablePassthroughMode<HandleUserinfoRequestContext, RequireUserinfoEndpointPassthroughEnabled>.Descriptor,
EnablePassthroughMode<HandleUserInfoRequestContext, RequireUserInfoEndpointPassthroughEnabled>.Descriptor,
/*
* Userinfo response processing:
* UserInfo response processing:
*/
AttachHttpResponseCode<ApplyUserinfoResponseContext>.Descriptor,
AttachOwinResponseChallenge<ApplyUserinfoResponseContext>.Descriptor,
SuppressFormsAuthenticationRedirect<ApplyUserinfoResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyUserinfoResponseContext>.Descriptor,
ProcessChallengeErrorResponse<ApplyUserinfoResponseContext>.Descriptor,
ProcessJsonResponse<ApplyUserinfoResponseContext>.Descriptor
AttachHttpResponseCode<ApplyUserInfoResponseContext>.Descriptor,
AttachOwinResponseChallenge<ApplyUserInfoResponseContext>.Descriptor,
SuppressFormsAuthenticationRedirect<ApplyUserInfoResponseContext>.Descriptor,
AttachWwwAuthenticateHeader<ApplyUserInfoResponseContext>.Descriptor,
ProcessChallengeErrorResponse<ApplyUserInfoResponseContext>.Descriptor,
ProcessJsonResponse<ApplyUserInfoResponseContext>.Descriptor
]);
}
}

10
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs

@ -54,7 +54,7 @@ public static partial class OpenIddictServerOwinHandlers
.. Introspection.DefaultHandlers,
.. Revocation.DefaultHandlers,
.. Session.DefaultHandlers,
.. Userinfo.DefaultHandlers
.. UserInfo.DefaultHandlers
]);
/// <summary>
@ -983,15 +983,15 @@ public static partial class OpenIddictServerOwinHandlers
// errors returned by API endpoints implementing bearer token authentication and MUST be returned
// as part of the standard WWW-Authenticate header. For more information, see
// https://openid.net/specs/openid-connect-core-1_0.html#UserInfoError.
(OpenIddictServerEndpointType.Userinfo, Errors.InvalidToken or Errors.MissingToken) => 401,
(OpenIddictServerEndpointType.Userinfo, Errors.InsufficientAccess or Errors.InsufficientScope) => 403,
(OpenIddictServerEndpointType.UserInfo, Errors.InvalidToken or Errors.MissingToken) => 401,
(OpenIddictServerEndpointType.UserInfo, Errors.InsufficientAccess or Errors.InsufficientScope) => 403,
// When client authentication is made using basic authentication, the authorization server
// MUST return a 401 response with a valid WWW-Authenticate header containing the HTTP Basic
// authentication scheme. A similar error MAY be returned even when using client_secret_post.
// To simplify the logic, a 401 response with the Basic scheme is returned for invalid_client
// errors, even if credentials were specified in the form, as allowed by the specification.
(not OpenIddictServerEndpointType.Userinfo, Errors.InvalidClient) => 401,
(not OpenIddictServerEndpointType.UserInfo, Errors.InvalidClient) => 401,
(_, Errors.ServerError) => 500,
@ -1211,7 +1211,7 @@ public static partial class OpenIddictServerOwinHandlers
// logic as errors returned by API endpoints implementing bearer token authentication and
// MUST be returned as part of the standard WWW-Authenticate header. For more information,
// see https://openid.net/specs/openid-connect-core-1_0.html#UserInfoError.
(OpenIddictServerEndpointType.Userinfo, _) => Schemes.Bearer,
(OpenIddictServerEndpointType.UserInfo, _) => Schemes.Bearer,
// When client authentication is made using basic authentication, the authorization server
// MUST return a 401 response with a valid WWW-Authenticate header containing the HTTP Basic

40
src/OpenIddict.Server.Owin/OpenIddictServerOwinOptions.cs

@ -36,44 +36,44 @@ public sealed class OpenIddictServerOwinOptions : AuthenticationOptions
public bool EnableAuthorizationEndpointPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether OpenIddict should allow the rest of the request processing pipeline
/// to be invoked when returning an error from the interactive authorization and logout endpoints.
/// When this option is enabled, special logic must be added to these actions to handle errors, that can be
/// retrieved using <see cref="OpenIddictServerOwinHelpers.GetOpenIddictServerResponse(IOwinContext)"/>
/// </summary>
public bool EnableErrorPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the authorization endpoint.
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the end session endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
public bool EnableLogoutEndpointPassthrough { get; set; }
public bool EnableEndSessionEndpointPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the token endpoint.
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the end-user verification endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
public bool EnableTokenEndpointPassthrough { get; set; }
public bool EnableEndUserVerificationEndpointPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the userinfo endpoint.
/// Gets or sets a boolean indicating whether OpenIddict should allow the rest of the request processing pipeline
/// to be invoked when returning an error from the interactive authorization and end session endpoints.
/// When this option is enabled, special logic must be added to these actions to handle errors, that can be
/// retrieved using <see cref="OpenIddictServerOwinHelpers.GetOpenIddictServerResponse(IOwinContext)"/>
/// </summary>
public bool EnableErrorPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the token endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
public bool EnableUserinfoEndpointPassthrough { get; set; }
public bool EnableTokenEndpointPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the user verification endpoint.
/// Gets or sets a boolean indicating whether the pass-through mode is enabled for the userinfo endpoint.
/// When the pass-through mode is used, OpenID Connect requests are initially handled by OpenIddict.
/// Once validated, the rest of the request processing pipeline is invoked, so that OpenID Connect requests
/// can be handled at a later stage (in a custom middleware or in a MVC controller, for instance).
/// </summary>
public bool EnableVerificationEndpointPassthrough { get; set; }
public bool EnableUserInfoEndpointPassthrough { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether requests received by the authorization endpoint
@ -85,10 +85,10 @@ public sealed class OpenIddictServerOwinOptions : AuthenticationOptions
public bool EnableAuthorizationRequestCaching { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether requests received by the logout endpoint should be cached.
/// Gets or sets a boolean indicating whether requests received by the end session endpoint should be cached.
/// When enabled, authorization requests are automatically stored in the distributed cache.
/// </summary>
public bool EnableLogoutRequestCaching { get; set; }
public bool EnableEndSessionRequestCaching { get; set; }
/// <summary>
/// Gets or sets a boolean whether JSON response indentation should be suppressed or not.
@ -110,9 +110,9 @@ public sealed class OpenIddictServerOwinOptions : AuthenticationOptions
};
/// <summary>
/// Gets or sets the caching policy used by the logout endpoint.
/// Gets or sets the caching policy used by the end session endpoint.
/// </summary>
public DistributedCacheEntryOptions LogoutRequestCachingPolicy { get; set; } = new()
public DistributedCacheEntryOptions EndSessionRequestCachingPolicy { get; set; } = new()
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1),
SlidingExpiration = TimeSpan.FromMinutes(30)

74
src/OpenIddict.Server/OpenIddictServerBuilder.cs

@ -944,11 +944,11 @@ public sealed class OpenIddictServerBuilder
}
/// <summary>
/// Enables device code flow support. For more information about this
/// Enables device authorization flow support. For more information about this
/// specific OAuth 2.0 flow, visit https://tools.ietf.org/html/rfc8628.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/> instance.</returns>
public OpenIddictServerBuilder AllowDeviceCodeFlow()
public OpenIddictServerBuilder AllowDeviceAuthorizationFlow()
=> Configure(options => options.GrantTypes.Add(GrantTypes.DeviceCode));
/// <summary>
@ -1129,13 +1129,13 @@ public sealed class OpenIddictServerBuilder
}
/// <summary>
/// Sets the relative or absolute URIs associated to the cryptography endpoint.
/// Sets the relative or absolute URIs associated to the device authorization endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// Note: only the first URI will be returned as part of the discovery document.
/// </summary>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/> instance.</returns>
public OpenIddictServerBuilder SetCryptographyEndpointUris(
public OpenIddictServerBuilder SetDeviceAuthorizationEndpointUris(
[StringSyntax(StringSyntaxAttribute.Uri)] params string[] uris)
{
if (uris is null)
@ -1143,17 +1143,17 @@ public sealed class OpenIddictServerBuilder
throw new ArgumentNullException(nameof(uris));
}
return SetCryptographyEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
return SetDeviceAuthorizationEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
}
/// <summary>
/// Sets the relative or absolute URIs associated to the cryptography endpoint.
/// Sets the relative or absolute URIs associated to the device authorization endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// Note: only the first URI will be returned as part of the discovery document.
/// </summary>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/> instance.</returns>
public OpenIddictServerBuilder SetCryptographyEndpointUris(params Uri[] uris)
public OpenIddictServerBuilder SetDeviceAuthorizationEndpointUris(params Uri[] uris)
{
if (uris is null)
{
@ -1172,19 +1172,19 @@ public sealed class OpenIddictServerBuilder
return Configure(options =>
{
options.CryptographyEndpointUris.Clear();
options.CryptographyEndpointUris.AddRange(uris);
options.DeviceAuthorizationEndpointUris.Clear();
options.DeviceAuthorizationEndpointUris.AddRange(uris);
});
}
/// <summary>
/// Sets the relative or absolute URIs associated to the device endpoint.
/// Sets the relative or absolute URIs associated to the end session endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// Note: only the first URI will be returned as part of the discovery document.
/// </summary>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/> instance.</returns>
public OpenIddictServerBuilder SetDeviceEndpointUris(
public OpenIddictServerBuilder SetEndSessionEndpointUris(
[StringSyntax(StringSyntaxAttribute.Uri)] params string[] uris)
{
if (uris is null)
@ -1192,17 +1192,17 @@ public sealed class OpenIddictServerBuilder
throw new ArgumentNullException(nameof(uris));
}
return SetDeviceEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
return SetEndSessionEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
}
/// <summary>
/// Sets the relative or absolute URIs associated to the device endpoint.
/// Sets the relative or absolute URIs associated to the end session endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// Note: only the first URI will be returned as part of the discovery document.
/// </summary>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/> instance.</returns>
public OpenIddictServerBuilder SetDeviceEndpointUris(params Uri[] uris)
public OpenIddictServerBuilder SetEndSessionEndpointUris(params Uri[] uris)
{
if (uris is null)
{
@ -1221,8 +1221,8 @@ public sealed class OpenIddictServerBuilder
return Configure(options =>
{
options.DeviceEndpointUris.Clear();
options.DeviceEndpointUris.AddRange(uris);
options.EndSessionEndpointUris.Clear();
options.EndSessionEndpointUris.AddRange(uris);
});
}
@ -1276,13 +1276,13 @@ public sealed class OpenIddictServerBuilder
}
/// <summary>
/// Sets the relative or absolute URIs associated to the logout endpoint.
/// Sets the relative or absolute URIs associated to the JSON Web Key Set endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// Note: only the first URI will be returned as part of the discovery document.
/// </summary>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/> instance.</returns>
public OpenIddictServerBuilder SetLogoutEndpointUris(
public OpenIddictServerBuilder SetJsonWebKeySetEndpointUris(
[StringSyntax(StringSyntaxAttribute.Uri)] params string[] uris)
{
if (uris is null)
@ -1290,17 +1290,17 @@ public sealed class OpenIddictServerBuilder
throw new ArgumentNullException(nameof(uris));
}
return SetLogoutEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
return SetJsonWebKeySetEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
}
/// <summary>
/// Sets the relative or absolute URIs associated to the logout endpoint.
/// Sets the relative or absolute URIs associated to the JSON Web Key Set endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// Note: only the first URI will be returned as part of the discovery document.
/// </summary>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/> instance.</returns>
public OpenIddictServerBuilder SetLogoutEndpointUris(params Uri[] uris)
public OpenIddictServerBuilder SetJsonWebKeySetEndpointUris(params Uri[] uris)
{
if (uris is null)
{
@ -1319,8 +1319,8 @@ public sealed class OpenIddictServerBuilder
return Configure(options =>
{
options.LogoutEndpointUris.Clear();
options.LogoutEndpointUris.AddRange(uris);
options.JsonWebKeySetEndpointUris.Clear();
options.JsonWebKeySetEndpointUris.AddRange(uris);
});
}
@ -1429,7 +1429,7 @@ public sealed class OpenIddictServerBuilder
/// </summary>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/> instance.</returns>
public OpenIddictServerBuilder SetUserinfoEndpointUris(
public OpenIddictServerBuilder SetUserInfoEndpointUris(
[StringSyntax(StringSyntaxAttribute.Uri)] params string[] uris)
{
if (uris is null)
@ -1437,7 +1437,7 @@ public sealed class OpenIddictServerBuilder
throw new ArgumentNullException(nameof(uris));
}
return SetUserinfoEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
return SetUserInfoEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
}
/// <summary>
@ -1447,7 +1447,7 @@ public sealed class OpenIddictServerBuilder
/// </summary>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/> instance.</returns>
public OpenIddictServerBuilder SetUserinfoEndpointUris(params Uri[] uris)
public OpenIddictServerBuilder SetUserInfoEndpointUris(params Uri[] uris)
{
if (uris is null)
{
@ -1466,19 +1466,19 @@ public sealed class OpenIddictServerBuilder
return Configure(options =>
{
options.UserinfoEndpointUris.Clear();
options.UserinfoEndpointUris.AddRange(uris);
options.UserInfoEndpointUris.Clear();
options.UserInfoEndpointUris.AddRange(uris);
});
}
/// <summary>
/// Sets the relative or absolute URIs associated to the verification endpoint.
/// Sets the relative or absolute URIs associated to the end-user verification endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// Note: only the first URI will be returned by the device endpoint.
/// Note: only the first URI will be returned by the device authorization endpoint.
/// </summary>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/> instance.</returns>
public OpenIddictServerBuilder SetVerificationEndpointUris(
public OpenIddictServerBuilder SetEndUserVerificationEndpointUris(
[StringSyntax(StringSyntaxAttribute.Uri)] params string[] uris)
{
if (uris is null)
@ -1486,17 +1486,17 @@ public sealed class OpenIddictServerBuilder
throw new ArgumentNullException(nameof(uris));
}
return SetVerificationEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
return SetEndUserVerificationEndpointUris(uris.Select(uri => new Uri(uri, UriKind.RelativeOrAbsolute)).ToArray());
}
/// <summary>
/// Sets the relative or absolute URIs associated to the verification endpoint.
/// Sets the relative or absolute URIs associated to the end-user verification endpoint.
/// If an empty array is specified, the endpoint will be considered disabled.
/// Note: only the first URI will be returned by the device endpoint.
/// Note: only the first URI will be returned by the device authorization endpoint.
/// </summary>
/// <param name="uris">The URIs associated to the endpoint.</param>
/// <returns>The <see cref="OpenIddictServerBuilder"/> instance.</returns>
public OpenIddictServerBuilder SetVerificationEndpointUris(params Uri[] uris)
public OpenIddictServerBuilder SetEndUserVerificationEndpointUris(params Uri[] uris)
{
if (uris is null)
{
@ -1515,8 +1515,8 @@ public sealed class OpenIddictServerBuilder
return Configure(options =>
{
options.VerificationEndpointUris.Clear();
options.VerificationEndpointUris.AddRange(uris);
options.EndUserVerificationEndpointUris.Clear();
options.EndUserVerificationEndpointUris.AddRange(uris);
});
}

36
src/OpenIddict.Server/OpenIddictServerConfiguration.cs

@ -77,14 +77,14 @@ public sealed class OpenIddictServerConfiguration : IPostConfigureOptions<OpenId
var uris = options.AuthorizationEndpointUris.Distinct()
.Concat(options.ConfigurationEndpointUris.Distinct())
.Concat(options.CryptographyEndpointUris.Distinct())
.Concat(options.DeviceEndpointUris.Distinct())
.Concat(options.JsonWebKeySetEndpointUris.Distinct())
.Concat(options.DeviceAuthorizationEndpointUris.Distinct())
.Concat(options.IntrospectionEndpointUris.Distinct())
.Concat(options.LogoutEndpointUris.Distinct())
.Concat(options.EndSessionEndpointUris.Distinct())
.Concat(options.RevocationEndpointUris.Distinct())
.Concat(options.TokenEndpointUris.Distinct())
.Concat(options.UserinfoEndpointUris.Distinct())
.Concat(options.VerificationEndpointUris.Distinct())
.Concat(options.UserInfoEndpointUris.Distinct())
.Concat(options.EndUserVerificationEndpointUris.Distinct())
.ToList();
// Ensure endpoint URIs are unique across endpoints.
@ -101,8 +101,8 @@ public sealed class OpenIddictServerConfiguration : IPostConfigureOptions<OpenId
throw new InvalidOperationException(SR.GetResourceString(SR.ID0077));
}
// Ensure the device endpoint has been enabled when the device grant is supported.
if (options.DeviceEndpointUris.Count is 0 && options.GrantTypes.Contains(GrantTypes.DeviceCode))
// Ensure the device authorization endpoint has been enabled when the device grant is supported.
if (options.DeviceAuthorizationEndpointUris.Count is 0 && options.GrantTypes.Contains(GrantTypes.DeviceCode))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0078));
}
@ -118,14 +118,14 @@ public sealed class OpenIddictServerConfiguration : IPostConfigureOptions<OpenId
throw new InvalidOperationException(SR.GetResourceString(SR.ID0079));
}
// Ensure the verification endpoint has been enabled when the device grant is supported.
if (options.VerificationEndpointUris.Count is 0 && options.GrantTypes.Contains(GrantTypes.DeviceCode))
// Ensure the end-user verification endpoint has been enabled when the device grant is supported.
if (options.EndUserVerificationEndpointUris.Count is 0 && options.GrantTypes.Contains(GrantTypes.DeviceCode))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0080));
}
// Ensure the device grant is allowed when the device endpoint is enabled.
if (options.DeviceEndpointUris.Count > 0 && !options.GrantTypes.Contains(GrantTypes.DeviceCode))
// Ensure the device grant is allowed when the device authorization endpoint is enabled.
if (options.DeviceAuthorizationEndpointUris.Count > 0 && !options.GrantTypes.Contains(GrantTypes.DeviceCode))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0084));
}
@ -151,7 +151,7 @@ public sealed class OpenIddictServerConfiguration : IPostConfigureOptions<OpenId
}
// Ensure at least one client authentication method is enabled (unless no non-interactive endpoint was enabled).
if (options.ClientAuthenticationMethods.Count is 0 && (options.DeviceEndpointUris.Count is not 0 ||
if (options.ClientAuthenticationMethods.Count is 0 && (options.DeviceAuthorizationEndpointUris.Count is not 0 ||
options.IntrospectionEndpointUris.Count is not 0 ||
options.RevocationEndpointUris.Count is not 0 ||
options.TokenEndpointUris.Count is not 0))
@ -238,8 +238,8 @@ public sealed class OpenIddictServerConfiguration : IPostConfigureOptions<OpenId
throw new InvalidOperationException(SR.GetResourceString(SR.ID0089));
}
if (options.DeviceEndpointUris.Count is not 0 && !options.Handlers.Exists(static descriptor =>
(descriptor.ContextType == typeof(ValidateDeviceRequestContext) ||
if (options.DeviceAuthorizationEndpointUris.Count is not 0 && !options.Handlers.Exists(static descriptor =>
(descriptor.ContextType == typeof(ValidateDeviceAuthorizationRequestContext) ||
descriptor.ContextType == typeof(ProcessAuthenticationContext)) &&
descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
@ -256,8 +256,8 @@ public sealed class OpenIddictServerConfiguration : IPostConfigureOptions<OpenId
throw new InvalidOperationException(SR.GetResourceString(SR.ID0091));
}
if (options.LogoutEndpointUris.Count is not 0 && !options.Handlers.Exists(static descriptor =>
descriptor.ContextType == typeof(ValidateLogoutRequestContext) &&
if (options.EndSessionEndpointUris.Count is not 0 && !options.Handlers.Exists(static descriptor =>
descriptor.ContextType == typeof(ValidateEndSessionRequestContext) &&
descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
{
@ -282,8 +282,8 @@ public sealed class OpenIddictServerConfiguration : IPostConfigureOptions<OpenId
throw new InvalidOperationException(SR.GetResourceString(SR.ID0094));
}
if (options.VerificationEndpointUris.Count is not 0 && !options.Handlers.Exists(static descriptor =>
descriptor.ContextType == typeof(ValidateVerificationRequestContext) &&
if (options.EndUserVerificationEndpointUris.Count is not 0 && !options.Handlers.Exists(static descriptor =>
descriptor.ContextType == typeof(ValidateEndUserVerificationRequestContext) &&
descriptor.Type == OpenIddictServerHandlerType.Custom &&
descriptor.FilterTypes.All(type => !typeof(RequireDegradedModeDisabled).IsAssignableFrom(type))))
{

20
src/OpenIddict.Server/OpenIddictServerEndpointType.cs

@ -27,9 +27,9 @@ public enum OpenIddictServerEndpointType
Token = 2,
/// <summary>
/// Logout endpoint.
/// End session endpoint.
/// </summary>
Logout = 3,
EndSession = 3,
/// <summary>
/// Configuration endpoint.
@ -37,14 +37,14 @@ public enum OpenIddictServerEndpointType
Configuration = 4,
/// <summary>
/// Cryptography endpoint.
/// JSON Web Key Set endpoint.
/// </summary>
Cryptography = 5,
JsonWebKeySet = 5,
/// <summary>
/// Userinfo endpoint.
/// UserInfo endpoint.
/// </summary>
Userinfo = 6,
UserInfo = 6,
/// <summary>
/// Introspection endpoint.
@ -57,12 +57,12 @@ public enum OpenIddictServerEndpointType
Revocation = 8,
/// <summary>
/// Device endpoint.
/// Device authorization endpoint.
/// </summary>
Device = 9,
DeviceAuthorization = 9,
/// <summary>
/// Verification endpoint.
/// User verification endpoint.
/// </summary>
Verification = 10
EndUserVerification = 10
}

72
src/OpenIddict.Server/OpenIddictServerEvents.Device.cs

@ -11,15 +11,15 @@ namespace OpenIddict.Server;
public static partial class OpenIddictServerEvents
{
/// <summary>
/// Represents an event called for each request to the device endpoint to give the user code
/// a chance to manually extract the device request from the ambient HTTP context.
/// Represents an event called for each request to the device authorization endpoint to give the
/// user code a chance to manually extract the device request from the ambient HTTP context.
/// </summary>
public sealed class ExtractDeviceRequestContext : BaseValidatingContext
public sealed class ExtractDeviceAuthorizationRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="ExtractDeviceRequestContext"/> class.
/// Creates a new instance of the <see cref="ExtractDeviceAuthorizationRequestContext"/> class.
/// </summary>
public ExtractDeviceRequestContext(OpenIddictServerTransaction transaction)
public ExtractDeviceAuthorizationRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -35,15 +35,15 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called for each request to the device endpoint
/// Represents an event called for each request to the device authorization endpoint
/// to determine if the request is valid and should continue to be processed.
/// </summary>
public sealed class ValidateDeviceRequestContext : BaseValidatingClientContext
public sealed class ValidateDeviceAuthorizationRequestContext : BaseValidatingClientContext
{
/// <summary>
/// Creates a new instance of the <see cref="ValidateDeviceRequestContext"/> class.
/// Creates a new instance of the <see cref="ValidateDeviceAuthorizationRequestContext"/> class.
/// </summary>
public ValidateDeviceRequestContext(OpenIddictServerTransaction transaction)
public ValidateDeviceAuthorizationRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -59,15 +59,15 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called for each validated device request
/// Represents an event called for each validated device authorization request
/// to allow the user code to decide how the request should be handled.
/// </summary>
public sealed class HandleDeviceRequestContext : BaseValidatingTicketContext
public sealed class HandleDeviceAuthorizationRequestContext : BaseValidatingTicketContext
{
/// <summary>
/// Creates a new instance of the <see cref="HandleDeviceRequestContext"/> class.
/// Creates a new instance of the <see cref="HandleDeviceAuthorizationRequestContext"/> class.
/// </summary>
public HandleDeviceRequestContext(OpenIddictServerTransaction transaction)
public HandleDeviceAuthorizationRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -106,14 +106,14 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called before the device response is returned to the caller.
/// Represents an event called before the device authorization response is returned to the caller.
/// </summary>
public sealed class ApplyDeviceResponseContext : BaseRequestContext
public sealed class ApplyDeviceAuthorizationResponseContext : BaseRequestContext
{
/// <summary>
/// Creates a new instance of the <see cref="ApplyDeviceResponseContext"/> class.
/// Creates a new instance of the <see cref="ApplyDeviceAuthorizationResponseContext"/> class.
/// </summary>
public ApplyDeviceResponseContext(OpenIddictServerTransaction transaction)
public ApplyDeviceAuthorizationResponseContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -145,15 +145,15 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called for each request to the verification endpoint to give the user code
/// a chance to manually extract the verification request from the ambient HTTP context.
/// Represents an event called for each request to the end-user verification endpoint to give the user code
/// a chance to manually extract the end-user verification request from the ambient HTTP context.
/// </summary>
public sealed class ExtractVerificationRequestContext : BaseValidatingContext
public sealed class ExtractEndUserVerificationRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="ExtractVerificationRequestContext"/> class.
/// Creates a new instance of the <see cref="ExtractEndUserVerificationRequestContext"/> class.
/// </summary>
public ExtractVerificationRequestContext(OpenIddictServerTransaction transaction)
public ExtractEndUserVerificationRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -169,15 +169,15 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called for each request to the verification endpoint
/// Represents an event called for each request to the end-user verification endpoint
/// to determine if the request is valid and should continue to be processed.
/// </summary>
public sealed class ValidateVerificationRequestContext : BaseValidatingClientContext
public sealed class ValidateEndUserVerificationRequestContext : BaseValidatingClientContext
{
/// <summary>
/// Creates a new instance of the <see cref="ValidateVerificationRequestContext"/> class.
/// Creates a new instance of the <see cref="ValidateEndUserVerificationRequestContext"/> class.
/// </summary>
public ValidateVerificationRequestContext(OpenIddictServerTransaction transaction)
public ValidateEndUserVerificationRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -198,15 +198,15 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called for each validated verification request
/// Represents an event called for each validated end-user verification request
/// to allow the user code to decide how the request should be handled.
/// </summary>
public sealed class HandleVerificationRequestContext : BaseValidatingTicketContext
public sealed class HandleEndUserVerificationRequestContext : BaseValidatingTicketContext
{
/// <summary>
/// Creates a new instance of the <see cref="HandleVerificationRequestContext"/> class.
/// Creates a new instance of the <see cref="HandleEndUserVerificationRequestContext"/> class.
/// </summary>
public HandleVerificationRequestContext(OpenIddictServerTransaction transaction)
public HandleEndUserVerificationRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -230,8 +230,8 @@ public static partial class OpenIddictServerEvents
/// </summary>
/// <remarks>
/// Note: by default, this property is not used as empty responses are typically
/// returned for user verification requests. To return a different response, a
/// custom event handler must be registered to handle user verification responses.
/// returned for end-user verification requests. To return a different response, a
/// custom event handler must be registered to handle end-user verification responses.
/// </remarks>
public Dictionary<string, OpenIddictParameter> Parameters { get; private set; }
= new(StringComparer.Ordinal);
@ -255,14 +255,14 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called before the verification response is returned to the caller.
/// Represents an event called before the end-user verification response is returned to the caller.
/// </summary>
public sealed class ApplyVerificationResponseContext : BaseRequestContext
public sealed class ApplyEndUserVerificationResponseContext : BaseRequestContext
{
/// <summary>
/// Creates a new instance of the <see cref="ApplyVerificationResponseContext"/> class.
/// Creates a new instance of the <see cref="ApplyEndUserVerificationResponseContext"/> class.
/// </summary>
public ApplyVerificationResponseContext(OpenIddictServerTransaction transaction)
public ApplyEndUserVerificationResponseContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}

50
src/OpenIddict.Server/OpenIddictServerEvents.Discovery.cs

@ -97,14 +97,14 @@ public static partial class OpenIddictServerEvents
public Uri? AuthorizationEndpoint { get; set; }
/// <summary>
/// Gets or sets the JWKS endpoint URI.
/// Gets or sets the JSON Web Key Set endpoint URI.
/// </summary>
public Uri? CryptographyEndpoint { get; set; }
/// <summary>
/// Gets or sets the device endpoint URI.
/// Gets or sets the device authorization endpoint URI.
/// </summary>
public Uri? DeviceEndpoint { get; set; }
public Uri? DeviceAuthorizationEndpoint { get; set; }
/// <summary>
/// Gets or sets the introspection endpoint URI.
@ -112,7 +112,7 @@ public static partial class OpenIddictServerEvents
public Uri? IntrospectionEndpoint { get; set; }
/// <summary>
/// Gets or sets the logout endpoint URI.
/// Gets or sets the end session endpoint URI.
/// </summary>
public Uri? LogoutEndpoint { get; set; }
@ -129,7 +129,7 @@ public static partial class OpenIddictServerEvents
/// <summary>
/// Gets or sets the userinfo endpoint URI.
/// </summary>
public Uri? UserinfoEndpoint { get; set; }
public Uri? UserInfoEndpoint { get; set; }
/// <summary>
/// Gets the list of claims supported by the authorization server.
@ -144,9 +144,9 @@ public static partial class OpenIddictServerEvents
/// <summary>
/// Gets a list of client authentication methods supported by
/// the device endpoint provided by the authorization server.
/// the device authorization endpoint provided by the authorization server.
/// </summary>
public HashSet<string> DeviceEndpointAuthenticationMethods { get; } = new(StringComparer.Ordinal);
public HashSet<string> DeviceAuthorizationEndpointAuthenticationMethods { get; } = new(StringComparer.Ordinal);
/// <summary>
/// Gets the list of grant types
@ -243,15 +243,15 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called for each request to the cryptography endpoint to give the user code
/// a chance to manually extract the cryptography request from the ambient HTTP context.
/// Represents an event called for each request to the JSON Web Key Set endpoint to give the user code
/// a chance to manually extract the JSON Web Key Set request from the ambient HTTP context.
/// </summary>
public sealed class ExtractCryptographyRequestContext : BaseValidatingContext
public sealed class ExtractJsonWebKeySetRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="ExtractCryptographyRequestContext"/> class.
/// Creates a new instance of the <see cref="ExtractJsonWebKeySetRequestContext"/> class.
/// </summary>
public ExtractCryptographyRequestContext(OpenIddictServerTransaction transaction)
public ExtractJsonWebKeySetRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -276,15 +276,15 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called for each request to the cryptography endpoint
/// Represents an event called for each request to the JSON Web Key Set endpoint
/// to determine if the request is valid and should continue to be processed.
/// </summary>
public sealed class ValidateCryptographyRequestContext : BaseValidatingContext
public sealed class ValidateJsonWebKeySetRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="ValidateCryptographyRequestContext"/> class.
/// Creates a new instance of the <see cref="ValidateJsonWebKeySetRequestContext"/> class.
/// </summary>
public ValidateCryptographyRequestContext(OpenIddictServerTransaction transaction)
public ValidateJsonWebKeySetRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -300,15 +300,15 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called for each validated cryptography request
/// Represents an event called for each validated JSON Web Key Set request
/// to allow the user code to decide how the request should be handled.
/// </summary>
public sealed class HandleCryptographyRequestContext : BaseValidatingContext
public sealed class HandleJsonWebKeySetRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="HandleCryptographyRequestContext"/> class.
/// Creates a new instance of the <see cref="HandleJsonWebKeySetRequestContext"/> class.
/// </summary>
public HandleCryptographyRequestContext(OpenIddictServerTransaction transaction)
public HandleJsonWebKeySetRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -323,20 +323,20 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Gets the list of JSON Web Keys exposed by the JWKS endpoint.
/// Gets the list of JSON Web Keys exposed by the JSON Web Key Set endpoint.
/// </summary>
public List<JsonWebKey> Keys { get; } = [];
}
/// <summary>
/// Represents an event called before the cryptography response is returned to the caller.
/// Represents an event called before the JSON Web Key Set response is returned to the caller.
/// </summary>
public sealed class ApplyCryptographyResponseContext : BaseRequestContext
public sealed class ApplyJsonWebKeySetResponseContext : BaseRequestContext
{
/// <summary>
/// Creates a new instance of the <see cref="ApplyCryptographyResponseContext"/> class.
/// Creates a new instance of the <see cref="ApplyJsonWebKeySetResponseContext"/> class.
/// </summary>
public ApplyCryptographyResponseContext(OpenIddictServerTransaction transaction)
public ApplyJsonWebKeySetResponseContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}

34
src/OpenIddict.Server/OpenIddictServerEvents.Session.cs

@ -12,15 +12,15 @@ namespace OpenIddict.Server;
public static partial class OpenIddictServerEvents
{
/// <summary>
/// Represents an event called for each request to the logout endpoint to give the user code
/// a chance to manually extract the logout request from the ambient HTTP context.
/// Represents an event called for each request to the end session endpoint to give the user code
/// a chance to manually extract the end session request from the ambient HTTP context.
/// </summary>
public sealed class ExtractLogoutRequestContext : BaseValidatingContext
public sealed class ExtractEndSessionRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="ExtractLogoutRequestContext"/> class.
/// Creates a new instance of the <see cref="ExtractEndSessionRequestContext"/> class.
/// </summary>
public ExtractLogoutRequestContext(OpenIddictServerTransaction transaction)
public ExtractEndSessionRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -36,15 +36,15 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called for each request to the logout endpoint
/// Represents an event called for each request to the end session endpoint
/// to determine if the request is valid and should continue to be processed.
/// </summary>
public sealed class ValidateLogoutRequestContext : BaseValidatingContext
public sealed class ValidateEndSessionRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="ValidateLogoutRequestContext"/> class.
/// Creates a new instance of the <see cref="ValidateEndSessionRequestContext"/> class.
/// </summary>
public ValidateLogoutRequestContext(OpenIddictServerTransaction transaction)
public ValidateEndSessionRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
// Infer the post_logout_redirect_uri from the value specified by the client application.
=> PostLogoutRedirectUri = Request?.PostLogoutRedirectUri;
@ -99,15 +99,15 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called for each validated logout request
/// Represents an event called for each validated end session request
/// to allow the user code to decide how the request should be handled.
/// </summary>
public sealed class HandleLogoutRequestContext : BaseValidatingContext
public sealed class HandleEndSessionRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="HandleLogoutRequestContext"/> class.
/// Creates a new instance of the <see cref="HandleEndSessionRequestContext"/> class.
/// </summary>
public HandleLogoutRequestContext(OpenIddictServerTransaction transaction)
public HandleEndSessionRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -155,14 +155,14 @@ public static partial class OpenIddictServerEvents
}
/// <summary>
/// Represents an event called before the logout response is returned to the caller.
/// Represents an event called before the end session response is returned to the caller.
/// </summary>
public sealed class ApplyLogoutResponseContext : BaseRequestContext
public sealed class ApplyEndSessionResponseContext : BaseRequestContext
{
/// <summary>
/// Creates a new instance of the <see cref="ApplyLogoutResponseContext"/> class.
/// Creates a new instance of the <see cref="ApplyEndSessionResponseContext"/> class.
/// </summary>
public ApplyLogoutResponseContext(OpenIddictServerTransaction transaction)
public ApplyEndSessionResponseContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}

24
src/OpenIddict.Server/OpenIddictServerEvents.Userinfo.cs

@ -15,12 +15,12 @@ public static partial class OpenIddictServerEvents
/// Represents an event called for each request to the userinfo endpoint to give the user code
/// a chance to manually extract the userinfo request from the ambient HTTP context.
/// </summary>
public sealed class ExtractUserinfoRequestContext : BaseValidatingContext
public sealed class ExtractUserInfoRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="ExtractUserinfoRequestContext"/> class.
/// Creates a new instance of the <see cref="ExtractUserInfoRequestContext"/> class.
/// </summary>
public ExtractUserinfoRequestContext(OpenIddictServerTransaction transaction)
public ExtractUserInfoRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -39,12 +39,12 @@ public static partial class OpenIddictServerEvents
/// Represents an event called for each request to the userinfo endpoint
/// to determine if the request is valid and should continue to be processed.
/// </summary>
public sealed class ValidateUserinfoRequestContext : BaseValidatingContext
public sealed class ValidateUserInfoRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="ValidateUserinfoRequestContext"/> class.
/// Creates a new instance of the <see cref="ValidateUserInfoRequestContext"/> class.
/// </summary>
public ValidateUserinfoRequestContext(OpenIddictServerTransaction transaction)
public ValidateUserInfoRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -68,12 +68,12 @@ public static partial class OpenIddictServerEvents
/// Represents an event called for each validated userinfo request
/// to allow the user code to decide how the request should be handled.
/// </summary>
public sealed class HandleUserinfoRequestContext : BaseValidatingContext
public sealed class HandleUserInfoRequestContext : BaseValidatingContext
{
/// <summary>
/// Creates a new instance of the <see cref="HandleUserinfoRequestContext"/> class.
/// Creates a new instance of the <see cref="HandleUserInfoRequestContext"/> class.
/// </summary>
public HandleUserinfoRequestContext(OpenIddictServerTransaction transaction)
public HandleUserInfoRequestContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}
@ -194,12 +194,12 @@ public static partial class OpenIddictServerEvents
/// <summary>
/// Represents an event called before the userinfo response is returned to the caller.
/// </summary>
public sealed class ApplyUserinfoResponseContext : BaseRequestContext
public sealed class ApplyUserInfoResponseContext : BaseRequestContext
{
/// <summary>
/// Creates a new instance of the <see cref="ApplyUserinfoResponseContext"/> class.
/// Creates a new instance of the <see cref="ApplyUserInfoResponseContext"/> class.
/// </summary>
public ApplyUserinfoResponseContext(OpenIddictServerTransaction transaction)
public ApplyUserInfoResponseContext(OpenIddictServerTransaction transaction)
: base(transaction)
{
}

10
src/OpenIddict.Server/OpenIddictServerExtensions.cs

@ -52,19 +52,20 @@ public static class OpenIddictServerExtensions
builder.Services.TryAddSingleton<RequireClientIdParameter>();
builder.Services.TryAddSingleton<RequireClientSecretParameter>();
builder.Services.TryAddSingleton<RequireConfigurationRequest>();
builder.Services.TryAddSingleton<RequireCryptographyRequest>();
builder.Services.TryAddSingleton<RequireDegradedModeDisabled>();
builder.Services.TryAddSingleton<RequireDeviceAuthorizationRequest>();
builder.Services.TryAddSingleton<RequireDeviceCodeGenerated>();
builder.Services.TryAddSingleton<RequireDeviceCodeValidated>();
builder.Services.TryAddSingleton<RequireDeviceRequest>();
builder.Services.TryAddSingleton<RequireEndpointPermissionsEnabled>();
builder.Services.TryAddSingleton<RequireEndSessionRequest>();
builder.Services.TryAddSingleton<RequireEndUserVerificationRequest>();
builder.Services.TryAddSingleton<RequireGenericTokenValidated>();
builder.Services.TryAddSingleton<RequireGrantTypePermissionsEnabled>();
builder.Services.TryAddSingleton<RequireIdentityTokenGenerated>();
builder.Services.TryAddSingleton<RequireIdentityTokenValidated>();
builder.Services.TryAddSingleton<RequireIntrospectionRequest>();
builder.Services.TryAddSingleton<RequireJsonWebKeySetRequest>();
builder.Services.TryAddSingleton<RequireJsonWebTokenFormat>();
builder.Services.TryAddSingleton<RequireLogoutRequest>();
builder.Services.TryAddSingleton<RequirePostLogoutRedirectUriParameter>();
builder.Services.TryAddSingleton<RequireReferenceAccessTokensEnabled>();
builder.Services.TryAddSingleton<RequireReferenceRefreshTokensEnabled>();
@ -83,8 +84,7 @@ public static class OpenIddictServerExtensions
builder.Services.TryAddSingleton<RequireTokenStorageEnabled>();
builder.Services.TryAddSingleton<RequireUserCodeGenerated>();
builder.Services.TryAddSingleton<RequireUserCodeValidated>();
builder.Services.TryAddSingleton<RequireUserinfoRequest>();
builder.Services.TryAddSingleton<RequireVerificationRequest>();
builder.Services.TryAddSingleton<RequireUserInfoRequest>();
// Note: TryAddEnumerable() is used here to ensure the initializer is registered only once.
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<

78
src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs

@ -216,9 +216,9 @@ public static class OpenIddictServerHandlerFilters
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the request is not a cryptography request.
/// Represents a filter that excludes the associated handlers if the degraded mode was not enabled.
/// </summary>
public sealed class RequireCryptographyRequest : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireDegradedModeDisabled : IOpenIddictServerHandlerFilter<BaseContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
@ -228,14 +228,14 @@ public static class OpenIddictServerHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(context.EndpointType is OpenIddictServerEndpointType.Cryptography);
return new(!context.Options.EnableDegradedMode);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the degraded mode was not enabled.
/// Represents a filter that excludes the associated handlers if the request is not a device request.
/// </summary>
public sealed class RequireDegradedModeDisabled : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireDeviceAuthorizationRequest : IOpenIddictServerHandlerFilter<BaseContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
@ -245,7 +245,7 @@ public static class OpenIddictServerHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(!context.Options.EnableDegradedMode);
return new(context.EndpointType is OpenIddictServerEndpointType.DeviceAuthorization);
}
}
@ -284,9 +284,9 @@ public static class OpenIddictServerHandlerFilters
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the request is not a device request.
/// Represents a filter that excludes the associated handlers if endpoint permissions were disabled.
/// </summary>
public sealed class RequireDeviceRequest : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireEndpointPermissionsEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
@ -296,14 +296,14 @@ public static class OpenIddictServerHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(context.EndpointType is OpenIddictServerEndpointType.Device);
return new(!context.Options.IgnoreEndpointPermissions);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if endpoint permissions were disabled.
/// Represents a filter that excludes the associated handlers if the request is not a end session request.
/// </summary>
public sealed class RequireEndpointPermissionsEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireEndSessionRequest : IOpenIddictServerHandlerFilter<BaseContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
@ -313,7 +313,24 @@ public static class OpenIddictServerHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(!context.Options.IgnoreEndpointPermissions);
return new(context.EndpointType is OpenIddictServerEndpointType.EndSession);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the request is not a verification request.
/// </summary>
public sealed class RequireEndUserVerificationRequest : IOpenIddictServerHandlerFilter<BaseContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new(context.EndpointType is OpenIddictServerEndpointType.EndUserVerification);
}
}
@ -403,36 +420,36 @@ public static class OpenIddictServerHandlerFilters
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the selected token format is not JSON Web Token.
/// Represents a filter that excludes the associated handlers if the request is not a JSON Web Key Set request.
/// </summary>
public sealed class RequireJsonWebTokenFormat : IOpenIddictServerHandlerFilter<GenerateTokenContext>
public sealed class RequireJsonWebKeySetRequest : IOpenIddictServerHandlerFilter<BaseContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(GenerateTokenContext context)
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new(context.TokenFormat is TokenFormats.Jwt);
return new(context.EndpointType is OpenIddictServerEndpointType.JsonWebKeySet);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the request is not a logout request.
/// Represents a filter that excludes the associated handlers if the selected token format is not JSON Web Token.
/// </summary>
public sealed class RequireLogoutRequest : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireJsonWebTokenFormat : IOpenIddictServerHandlerFilter<GenerateTokenContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
public ValueTask<bool> IsActiveAsync(GenerateTokenContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new(context.EndpointType is OpenIddictServerEndpointType.Logout);
return new(context.TokenFormat is TokenFormats.Jwt);
}
}
@ -745,24 +762,7 @@ public static class OpenIddictServerHandlerFilters
/// <summary>
/// Represents a filter that excludes the associated handlers if the request is not a userinfo request.
/// </summary>
public sealed class RequireUserinfoRequest : IOpenIddictServerHandlerFilter<BaseContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new(context.EndpointType is OpenIddictServerEndpointType.Userinfo);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if the request is not a verification request.
/// </summary>
public sealed class RequireVerificationRequest : IOpenIddictServerHandlerFilter<BaseContext>
public sealed class RequireUserInfoRequest : IOpenIddictServerHandlerFilter<BaseContext>
{
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
@ -772,7 +772,7 @@ public static class OpenIddictServerHandlerFilters
throw new ArgumentNullException(nameof(context));
}
return new(context.EndpointType is OpenIddictServerEndpointType.Verification);
return new(context.EndpointType is OpenIddictServerEndpointType.UserInfo);
}
}
}

193
src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs

@ -22,13 +22,13 @@ public static partial class OpenIddictServerHandlers
/*
* Device request top-level processing:
*/
ExtractDeviceRequest.Descriptor,
ValidateDeviceRequest.Descriptor,
HandleDeviceRequest.Descriptor,
ApplyDeviceResponse<ProcessChallengeContext>.Descriptor,
ApplyDeviceResponse<ProcessErrorContext>.Descriptor,
ApplyDeviceResponse<ProcessRequestContext>.Descriptor,
ApplyDeviceResponse<ProcessSignInContext>.Descriptor,
ExtractDeviceAuthorizationRequest.Descriptor,
ValidateDeviceAuthorizationRequest.Descriptor,
HandleDeviceAuthorizationRequest.Descriptor,
ApplyDeviceAuthorizationResponse<ProcessChallengeContext>.Descriptor,
ApplyDeviceAuthorizationResponse<ProcessErrorContext>.Descriptor,
ApplyDeviceAuthorizationResponse<ProcessRequestContext>.Descriptor,
ApplyDeviceAuthorizationResponse<ProcessSignInContext>.Descriptor,
/*
* Device request validation:
@ -44,13 +44,13 @@ public static partial class OpenIddictServerHandlers
/*
* Verification request top-level processing:
*/
ExtractVerificationRequest.Descriptor,
ValidateVerificationRequest.Descriptor,
HandleVerificationRequest.Descriptor,
ApplyVerificationResponse<ProcessChallengeContext>.Descriptor,
ApplyVerificationResponse<ProcessErrorContext>.Descriptor,
ApplyVerificationResponse<ProcessRequestContext>.Descriptor,
ApplyVerificationResponse<ProcessSignInContext>.Descriptor,
ExtractEndUserVerificationRequest.Descriptor,
ValidateEndUserVerificationRequest.Descriptor,
HandleEndUserVerificationRequest.Descriptor,
ApplyEndUserVerificationResponse<ProcessChallengeContext>.Descriptor,
ApplyEndUserVerificationResponse<ProcessErrorContext>.Descriptor,
ApplyEndUserVerificationResponse<ProcessRequestContext>.Descriptor,
ApplyEndUserVerificationResponse<ProcessSignInContext>.Descriptor,
/*
* Verification request validation:
@ -66,11 +66,11 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for extracting device requests and invoking the corresponding event handlers.
/// </summary>
public sealed class ExtractDeviceRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class ExtractDeviceAuthorizationRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ExtractDeviceRequest(IOpenIddictServerDispatcher dispatcher)
public ExtractDeviceAuthorizationRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -78,8 +78,8 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireDeviceRequest>()
.UseScopedHandler<ExtractDeviceRequest>()
.AddFilter<RequireDeviceAuthorizationRequest>()
.UseScopedHandler<ExtractDeviceAuthorizationRequest>()
.SetOrder(100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -92,7 +92,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ExtractDeviceRequestContext(context.Transaction);
var notification = new ExtractDeviceAuthorizationRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -128,11 +128,11 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for validating device requests and invoking the corresponding event handlers.
/// </summary>
public sealed class ValidateDeviceRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class ValidateDeviceAuthorizationRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ValidateDeviceRequest(IOpenIddictServerDispatcher dispatcher)
public ValidateDeviceAuthorizationRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -140,9 +140,9 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireDeviceRequest>()
.UseScopedHandler<ValidateDeviceRequest>()
.SetOrder(ExtractDeviceRequest.Descriptor.Order + 1_000)
.AddFilter<RequireDeviceAuthorizationRequest>()
.UseScopedHandler<ValidateDeviceAuthorizationRequest>()
.SetOrder(ExtractDeviceAuthorizationRequest.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -154,7 +154,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ValidateDeviceRequestContext(context.Transaction);
var notification = new ValidateDeviceAuthorizationRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -185,11 +185,11 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for handling device requests and invoking the corresponding event handlers.
/// </summary>
public sealed class HandleDeviceRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class HandleDeviceAuthorizationRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public HandleDeviceRequest(IOpenIddictServerDispatcher dispatcher)
public HandleDeviceAuthorizationRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -197,9 +197,9 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireDeviceRequest>()
.UseScopedHandler<HandleDeviceRequest>()
.SetOrder(ValidateDeviceRequest.Descriptor.Order + 1_000)
.AddFilter<RequireDeviceAuthorizationRequest>()
.UseScopedHandler<HandleDeviceAuthorizationRequest>()
.SetOrder(ValidateDeviceAuthorizationRequest.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -211,7 +211,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new HandleDeviceRequestContext(context.Transaction);
var notification = new HandleDeviceAuthorizationRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -286,11 +286,11 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for processing sign-in responses and invoking the corresponding event handlers.
/// </summary>
public sealed class ApplyDeviceResponse<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseRequestContext
public sealed class ApplyDeviceAuthorizationResponse<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseRequestContext
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ApplyDeviceResponse(IOpenIddictServerDispatcher dispatcher)
public ApplyDeviceAuthorizationResponse(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -298,8 +298,8 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<TContext>()
.AddFilter<RequireDeviceRequest>()
.UseScopedHandler<ApplyDeviceResponse<TContext>>()
.AddFilter<RequireDeviceAuthorizationRequest>()
.UseScopedHandler<ApplyDeviceAuthorizationResponse<TContext>>()
.SetOrder(500_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -312,7 +312,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ApplyDeviceResponseContext(context.Transaction);
var notification = new ApplyDeviceAuthorizationResponseContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -334,20 +334,20 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for rejecting device requests that don't specify a valid scope parameter.
/// </summary>
public sealed class ValidateScopeParameter : IOpenIddictServerHandler<ValidateDeviceRequestContext>
public sealed class ValidateScopeParameter : IOpenIddictServerHandler<ValidateDeviceAuthorizationRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceAuthorizationRequestContext>()
.UseSingletonHandler<ValidateScopeParameter>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ValidateDeviceRequestContext context)
public ValueTask HandleAsync(ValidateDeviceAuthorizationRequestContext context)
{
if (context is null)
{
@ -372,20 +372,20 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for rejecting device requests that specify invalid client credentials parameters.
/// </summary>
public sealed class ValidateClientCredentialsParameters : IOpenIddictServerHandler<ValidateDeviceRequestContext>
public sealed class ValidateClientCredentialsParameters : IOpenIddictServerHandler<ValidateDeviceAuthorizationRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceAuthorizationRequestContext>()
.UseSingletonHandler<ValidateClientCredentialsParameters>()
.SetOrder(ValidateScopeParameter.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ValidateDeviceRequestContext context)
public ValueTask HandleAsync(ValidateDeviceAuthorizationRequestContext context)
{
if (context is null)
{
@ -452,7 +452,7 @@ public static partial class OpenIddictServerHandlers
/// Contains the logic responsible for rejecting authorization requests that use unregistered scopes.
/// Note: this handler partially works with the degraded mode but is not used when scope validation is disabled.
/// </summary>
public sealed class ValidateScopes : IOpenIddictServerHandler<ValidateDeviceRequestContext>
public sealed class ValidateScopes : IOpenIddictServerHandler<ValidateDeviceAuthorizationRequestContext>
{
private readonly IOpenIddictScopeManager? _scopeManager;
@ -463,7 +463,7 @@ public static partial class OpenIddictServerHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceAuthorizationRequestContext>()
.AddFilter<RequireScopeValidationEnabled>()
.UseScopedHandler<ValidateScopes>(static provider =>
{
@ -481,7 +481,7 @@ public static partial class OpenIddictServerHandlers
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateDeviceRequestContext context)
public async ValueTask HandleAsync(ValidateDeviceAuthorizationRequestContext context)
{
if (context is null)
{
@ -530,7 +530,7 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for applying the authentication logic to device requests.
/// </summary>
public sealed class ValidateDeviceAuthentication : IOpenIddictServerHandler<ValidateDeviceRequestContext>
public sealed class ValidateDeviceAuthentication : IOpenIddictServerHandler<ValidateDeviceAuthorizationRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
@ -541,14 +541,14 @@ public static partial class OpenIddictServerHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceAuthorizationRequestContext>()
.UseScopedHandler<ValidateDeviceAuthentication>()
.SetOrder(ValidateScopes.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateDeviceRequestContext context)
public async ValueTask HandleAsync(ValidateDeviceAuthorizationRequestContext context)
{
if (context is null)
{
@ -587,10 +587,10 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for rejecting device requests made by
/// applications that haven't been granted the device endpoint permission.
/// applications that haven't been granted the device authorization endpoint permission.
/// Note: this handler is not used when the degraded mode is enabled.
/// </summary>
public sealed class ValidateEndpointPermissions : IOpenIddictServerHandler<ValidateDeviceRequestContext>
public sealed class ValidateEndpointPermissions : IOpenIddictServerHandler<ValidateDeviceAuthorizationRequestContext>
{
private readonly IOpenIddictApplicationManager _applicationManager;
@ -603,7 +603,7 @@ public static partial class OpenIddictServerHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceAuthorizationRequestContext>()
.AddFilter<RequireClientIdParameter>()
.AddFilter<RequireDegradedModeDisabled>()
.AddFilter<RequireEndpointPermissionsEnabled>()
@ -613,7 +613,7 @@ public static partial class OpenIddictServerHandlers
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateDeviceRequestContext context)
public async ValueTask HandleAsync(ValidateDeviceAuthorizationRequestContext context)
{
if (context is null)
{
@ -625,8 +625,11 @@ public static partial class OpenIddictServerHandlers
var application = await _applicationManager.FindByClientIdAsync(context.ClientId) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the device endpoint.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Device))
// Reject the request if the application is not allowed to use the device authorization endpoint.
//
// Note: the legacy "ept:device" permission is still allowed for backward compatibility.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.DeviceAuthorization) &&
!await _applicationManager.HasPermissionAsync(application, "ept:device"))
{
context.Logger.LogInformation(SR.GetResourceString(SR.ID6062), context.ClientId);
@ -644,7 +647,7 @@ public static partial class OpenIddictServerHandlers
/// Contains the logic responsible for rejecting device requests made by unauthorized applications.
/// Note: this handler is not used when the degraded mode is enabled or when grant type permissions are disabled.
/// </summary>
public sealed class ValidateGrantTypePermissions : IOpenIddictServerHandler<ValidateDeviceRequestContext>
public sealed class ValidateGrantTypePermissions : IOpenIddictServerHandler<ValidateDeviceAuthorizationRequestContext>
{
private readonly IOpenIddictApplicationManager _applicationManager;
@ -657,7 +660,7 @@ public static partial class OpenIddictServerHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceAuthorizationRequestContext>()
.AddFilter<RequireGrantTypePermissionsEnabled>()
.AddFilter<RequireDegradedModeDisabled>()
.UseScopedHandler<ValidateGrantTypePermissions>()
@ -666,7 +669,7 @@ public static partial class OpenIddictServerHandlers
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateDeviceRequestContext context)
public async ValueTask HandleAsync(ValidateDeviceAuthorizationRequestContext context)
{
if (context is null)
{
@ -713,7 +716,7 @@ public static partial class OpenIddictServerHandlers
/// that haven't been granted the appropriate grant type permission.
/// Note: this handler is not used when the degraded mode is enabled.
/// </summary>
public sealed class ValidateScopePermissions : IOpenIddictServerHandler<ValidateDeviceRequestContext>
public sealed class ValidateScopePermissions : IOpenIddictServerHandler<ValidateDeviceAuthorizationRequestContext>
{
private readonly IOpenIddictApplicationManager _applicationManager;
@ -726,7 +729,7 @@ public static partial class OpenIddictServerHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateDeviceAuthorizationRequestContext>()
.AddFilter<RequireClientIdParameter>()
.AddFilter<RequireDegradedModeDisabled>()
.AddFilter<RequireScopePermissionsEnabled>()
@ -736,7 +739,7 @@ public static partial class OpenIddictServerHandlers
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateDeviceRequestContext context)
public async ValueTask HandleAsync(ValidateDeviceAuthorizationRequestContext context)
{
if (context is null)
{
@ -774,13 +777,13 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for extracting verification requests and invoking the corresponding event handlers.
/// Contains the logic responsible for extracting end-user verification requests and invoking the corresponding event handlers.
/// </summary>
public sealed class ExtractVerificationRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class ExtractEndUserVerificationRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ExtractVerificationRequest(IOpenIddictServerDispatcher dispatcher)
public ExtractEndUserVerificationRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -788,8 +791,8 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireVerificationRequest>()
.UseScopedHandler<ExtractVerificationRequest>()
.AddFilter<RequireEndUserVerificationRequest>()
.UseScopedHandler<ExtractEndUserVerificationRequest>()
.SetOrder(100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -802,7 +805,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ExtractVerificationRequestContext(context.Transaction);
var notification = new ExtractEndUserVerificationRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -836,13 +839,13 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for validating verification requests and invoking the corresponding event handlers.
/// Contains the logic responsible for validating end-user verification requests and invoking the corresponding event handlers.
/// </summary>
public sealed class ValidateVerificationRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class ValidateEndUserVerificationRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ValidateVerificationRequest(IOpenIddictServerDispatcher dispatcher)
public ValidateEndUserVerificationRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -850,9 +853,9 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireVerificationRequest>()
.UseScopedHandler<ValidateVerificationRequest>()
.SetOrder(ExtractVerificationRequest.Descriptor.Order + 1_000)
.AddFilter<RequireEndUserVerificationRequest>()
.UseScopedHandler<ValidateEndUserVerificationRequest>()
.SetOrder(ExtractEndUserVerificationRequest.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -864,12 +867,12 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ValidateVerificationRequestContext(context.Transaction);
var notification = new ValidateEndUserVerificationRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
// Store the context object in the transaction so it can be later retrieved by handlers
// that want to access the context without triggering a new validation process.
context.Transaction.SetProperty(typeof(ValidateVerificationRequestContext).FullName!, notification);
context.Transaction.SetProperty(typeof(ValidateEndUserVerificationRequestContext).FullName!, notification);
if (notification.IsRequestHandled)
{
@ -897,13 +900,13 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for handling verification requests and invoking the corresponding event handlers.
/// Contains the logic responsible for handling end-user verification requests and invoking the corresponding event handlers.
/// </summary>
public sealed class HandleVerificationRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class HandleEndUserVerificationRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public HandleVerificationRequest(IOpenIddictServerDispatcher dispatcher)
public HandleEndUserVerificationRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -911,9 +914,9 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireVerificationRequest>()
.UseScopedHandler<HandleVerificationRequest>()
.SetOrder(ValidateVerificationRequest.Descriptor.Order + 1_000)
.AddFilter<RequireEndUserVerificationRequest>()
.UseScopedHandler<HandleEndUserVerificationRequest>()
.SetOrder(ValidateEndUserVerificationRequest.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -925,7 +928,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new HandleVerificationRequestContext(context.Transaction);
var notification = new HandleEndUserVerificationRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -996,11 +999,11 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for processing sign-in responses and invoking the corresponding event handlers.
/// </summary>
public sealed class ApplyVerificationResponse<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseRequestContext
public sealed class ApplyEndUserVerificationResponse<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseRequestContext
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ApplyVerificationResponse(IOpenIddictServerDispatcher dispatcher)
public ApplyEndUserVerificationResponse(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -1008,8 +1011,8 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<TContext>()
.AddFilter<RequireVerificationRequest>()
.UseScopedHandler<ApplyVerificationResponse<TContext>>()
.AddFilter<RequireEndUserVerificationRequest>()
.UseScopedHandler<ApplyEndUserVerificationResponse<TContext>>()
.SetOrder(500_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -1022,7 +1025,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ApplyVerificationResponseContext(context.Transaction);
var notification = new ApplyEndUserVerificationResponseContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -1042,9 +1045,9 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for applying the authentication logic to verification requests.
/// Contains the logic responsible for applying the authentication logic to end-user verification requests.
/// </summary>
public sealed class ValidateVerificationAuthentication : IOpenIddictServerHandler<ValidateVerificationRequestContext>
public sealed class ValidateVerificationAuthentication : IOpenIddictServerHandler<ValidateEndUserVerificationRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
@ -1055,14 +1058,14 @@ public static partial class OpenIddictServerHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateVerificationRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateEndUserVerificationRequestContext>()
.UseScopedHandler<ValidateVerificationAuthentication>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateVerificationRequestContext context)
public async ValueTask HandleAsync(ValidateEndUserVerificationRequestContext context)
{
if (context is null)
{
@ -1105,28 +1108,28 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for attaching the principal extracted from the user code to the event context.
/// </summary>
public sealed class AttachUserCodePrincipal : IOpenIddictServerHandler<HandleVerificationRequestContext>
public sealed class AttachUserCodePrincipal : IOpenIddictServerHandler<HandleEndUserVerificationRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleVerificationRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleEndUserVerificationRequestContext>()
.UseSingletonHandler<AttachUserCodePrincipal>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleVerificationRequestContext context)
public ValueTask HandleAsync(HandleEndUserVerificationRequestContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
var notification = context.Transaction.GetProperty<ValidateVerificationRequestContext>(
typeof(ValidateVerificationRequestContext).FullName!) ??
var notification = context.Transaction.GetProperty<ValidateEndUserVerificationRequestContext>(
typeof(ValidateEndUserVerificationRequestContext).FullName!) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0007));
context.UserCodePrincipal ??= notification.Principal;

92
src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs

@ -47,11 +47,11 @@ public static partial class OpenIddictServerHandlers
/*
* Cryptography request top-level processing:
*/
ExtractCryptographyRequest.Descriptor,
ValidateCryptographyRequest.Descriptor,
HandleCryptographyRequest.Descriptor,
ApplyCryptographyResponse<ProcessErrorContext>.Descriptor,
ApplyCryptographyResponse<ProcessRequestContext>.Descriptor,
ExtractJsonWebKeySetRequest.Descriptor,
ValidateJsonWebKeySetRequest.Descriptor,
HandleJsonWebKeySetRequest.Descriptor,
ApplyJsonWebKeySetResponse<ProcessErrorContext>.Descriptor,
ApplyJsonWebKeySetResponse<ProcessRequestContext>.Descriptor,
/*
* Cryptography request handling:
@ -239,8 +239,8 @@ public static partial class OpenIddictServerHandlers
[Metadata.IntrospectionEndpoint] = notification.IntrospectionEndpoint?.AbsoluteUri,
[Metadata.EndSessionEndpoint] = notification.LogoutEndpoint?.AbsoluteUri,
[Metadata.RevocationEndpoint] = notification.RevocationEndpoint?.AbsoluteUri,
[Metadata.UserinfoEndpoint] = notification.UserinfoEndpoint?.AbsoluteUri,
[Metadata.DeviceAuthorizationEndpoint] = notification.DeviceEndpoint?.AbsoluteUri,
[Metadata.UserInfoEndpoint] = notification.UserInfoEndpoint?.AbsoluteUri,
[Metadata.DeviceAuthorizationEndpoint] = notification.DeviceAuthorizationEndpoint?.AbsoluteUri,
[Metadata.JwksUri] = notification.CryptographyEndpoint?.AbsoluteUri,
[Metadata.GrantTypesSupported] = notification.GrantTypes.ToArray(),
[Metadata.ResponseTypesSupported] = notification.ResponseTypes.ToArray(),
@ -253,7 +253,7 @@ public static partial class OpenIddictServerHandlers
[Metadata.TokenEndpointAuthMethodsSupported] = notification.TokenEndpointAuthenticationMethods.ToArray(),
[Metadata.IntrospectionEndpointAuthMethodsSupported] = notification.IntrospectionEndpointAuthenticationMethods.ToArray(),
[Metadata.RevocationEndpointAuthMethodsSupported] = notification.RevocationEndpointAuthenticationMethods.ToArray(),
[Metadata.DeviceAuthorizationEndpointAuthMethodsSupported] = notification.DeviceEndpointAuthenticationMethods.ToArray()
[Metadata.DeviceAuthorizationEndpointAuthMethodsSupported] = notification.DeviceAuthorizationEndpointAuthenticationMethods.ToArray()
};
foreach (var metadata in notification.Metadata)
@ -372,16 +372,16 @@ public static partial class OpenIddictServerHandlers
context.BaseUri, context.Options.AuthorizationEndpointUris.FirstOrDefault());
context.CryptographyEndpoint ??= OpenIddictHelpers.CreateAbsoluteUri(
context.BaseUri, context.Options.CryptographyEndpointUris.FirstOrDefault());
context.BaseUri, context.Options.JsonWebKeySetEndpointUris.FirstOrDefault());
context.DeviceEndpoint ??= OpenIddictHelpers.CreateAbsoluteUri(
context.BaseUri, context.Options.DeviceEndpointUris.FirstOrDefault());
context.DeviceAuthorizationEndpoint ??= OpenIddictHelpers.CreateAbsoluteUri(
context.BaseUri, context.Options.DeviceAuthorizationEndpointUris.FirstOrDefault());
context.IntrospectionEndpoint ??= OpenIddictHelpers.CreateAbsoluteUri(
context.BaseUri, context.Options.IntrospectionEndpointUris.FirstOrDefault());
context.LogoutEndpoint ??= OpenIddictHelpers.CreateAbsoluteUri(
context.BaseUri, context.Options.LogoutEndpointUris.FirstOrDefault());
context.BaseUri, context.Options.EndSessionEndpointUris.FirstOrDefault());
context.RevocationEndpoint ??= OpenIddictHelpers.CreateAbsoluteUri(
context.BaseUri, context.Options.RevocationEndpointUris.FirstOrDefault());
@ -389,8 +389,8 @@ public static partial class OpenIddictServerHandlers
context.TokenEndpoint ??= OpenIddictHelpers.CreateAbsoluteUri(
context.BaseUri, context.Options.TokenEndpointUris.FirstOrDefault());
context.UserinfoEndpoint ??= OpenIddictHelpers.CreateAbsoluteUri(
context.BaseUri, context.Options.UserinfoEndpointUris.FirstOrDefault());
context.UserInfoEndpoint ??= OpenIddictHelpers.CreateAbsoluteUri(
context.BaseUri, context.Options.UserInfoEndpointUris.FirstOrDefault());
return default;
}
@ -509,9 +509,9 @@ public static partial class OpenIddictServerHandlers
// Note: "device_authorization_endpoint_auth_methods_supported" is not a standard parameter
// but is supported by OpenIddict 4.3.0 and higher for consistency with the other endpoints.
if (context.DeviceEndpoint is not null)
if (context.DeviceAuthorizationEndpoint is not null)
{
context.DeviceEndpointAuthenticationMethods.UnionWith(context.Options.ClientAuthenticationMethods);
context.DeviceAuthorizationEndpointAuthenticationMethods.UnionWith(context.Options.ClientAuthenticationMethods);
}
if (context.IntrospectionEndpoint is not null)
@ -755,13 +755,13 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for extracting cryptography requests and invoking the corresponding event handlers.
/// Contains the logic responsible for extracting JSON Web Key Set requests and invoking the corresponding event handlers.
/// </summary>
public sealed class ExtractCryptographyRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class ExtractJsonWebKeySetRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ExtractCryptographyRequest(IOpenIddictServerDispatcher dispatcher)
public ExtractJsonWebKeySetRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -769,8 +769,8 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireCryptographyRequest>()
.UseScopedHandler<ExtractCryptographyRequest>()
.AddFilter<RequireJsonWebKeySetRequest>()
.UseScopedHandler<ExtractJsonWebKeySetRequest>()
.SetOrder(100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -783,7 +783,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ExtractCryptographyRequestContext(context.Transaction);
var notification = new ExtractJsonWebKeySetRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -817,13 +817,13 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for validating cryptography requests and invoking the corresponding event handlers.
/// Contains the logic responsible for validating JSON Web Key Set requests and invoking the corresponding event handlers.
/// </summary>
public sealed class ValidateCryptographyRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class ValidateJsonWebKeySetRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ValidateCryptographyRequest(IOpenIddictServerDispatcher dispatcher)
public ValidateJsonWebKeySetRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -831,9 +831,9 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireCryptographyRequest>()
.UseScopedHandler<ValidateCryptographyRequest>()
.SetOrder(ExtractCryptographyRequest.Descriptor.Order + 1_000)
.AddFilter<RequireJsonWebKeySetRequest>()
.UseScopedHandler<ValidateJsonWebKeySetRequest>()
.SetOrder(ExtractJsonWebKeySetRequest.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -845,7 +845,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ValidateCryptographyRequestContext(context.Transaction);
var notification = new ValidateJsonWebKeySetRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -874,13 +874,13 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for handling cryptography requests and invoking the corresponding event handlers.
/// Contains the logic responsible for handling JSON Web Key Set requests and invoking the corresponding event handlers.
/// </summary>
public sealed class HandleCryptographyRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class HandleJsonWebKeySetRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public HandleCryptographyRequest(IOpenIddictServerDispatcher dispatcher)
public HandleJsonWebKeySetRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -888,9 +888,9 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireCryptographyRequest>()
.UseScopedHandler<HandleCryptographyRequest>()
.SetOrder(ValidateCryptographyRequest.Descriptor.Order + 1_000)
.AddFilter<RequireJsonWebKeySetRequest>()
.UseScopedHandler<HandleJsonWebKeySetRequest>()
.SetOrder(ValidateJsonWebKeySetRequest.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -902,7 +902,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new HandleCryptographyRequestContext(context.Transaction);
var notification = new HandleJsonWebKeySetRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -1002,13 +1002,13 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for processing cryptography responses and invoking the corresponding event handlers.
/// Contains the logic responsible for processing JSON Web Key Set responses and invoking the corresponding event handlers.
/// </summary>
public sealed class ApplyCryptographyResponse<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseRequestContext
public sealed class ApplyJsonWebKeySetResponse<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseRequestContext
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ApplyCryptographyResponse(IOpenIddictServerDispatcher dispatcher)
public ApplyJsonWebKeySetResponse(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -1016,8 +1016,8 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<TContext>()
.AddFilter<RequireCryptographyRequest>()
.UseScopedHandler<ApplyCryptographyResponse<TContext>>()
.AddFilter<RequireJsonWebKeySetRequest>()
.UseScopedHandler<ApplyJsonWebKeySetResponse<TContext>>()
.SetOrder(500_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -1030,7 +1030,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ApplyCryptographyResponseContext(context.Transaction);
var notification = new ApplyJsonWebKeySetResponseContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -1050,22 +1050,22 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for attaching the signing keys to the JWKS document.
/// Contains the logic responsible for attaching the signing keys to the JSON Web Key Set document.
/// </summary>
public sealed class AttachSigningKeys : IOpenIddictServerHandler<HandleCryptographyRequestContext>
public sealed class AttachSigningKeys : IOpenIddictServerHandler<HandleJsonWebKeySetRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleCryptographyRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleJsonWebKeySetRequestContext>()
.UseSingletonHandler<AttachSigningKeys>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleCryptographyRequestContext context)
public ValueTask HandleAsync(HandleJsonWebKeySetRequestContext context)
{
if (context is null)
{

153
src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs

@ -23,12 +23,12 @@ public static partial class OpenIddictServerHandlers
/*
* Logout request top-level processing:
*/
ExtractLogoutRequest.Descriptor,
ValidateLogoutRequest.Descriptor,
HandleLogoutRequest.Descriptor,
ApplyLogoutResponse<ProcessErrorContext>.Descriptor,
ApplyLogoutResponse<ProcessRequestContext>.Descriptor,
ApplyLogoutResponse<ProcessSignOutContext>.Descriptor,
ExtractEndSessionRequest.Descriptor,
ValidateEndSessionRequest.Descriptor,
HandleEndSessionRequest.Descriptor,
ApplyEndSessionResponse<ProcessErrorContext>.Descriptor,
ApplyEndSessionResponse<ProcessRequestContext>.Descriptor,
ApplyEndSessionResponse<ProcessSignOutContext>.Descriptor,
/*
* Logout request validation:
@ -52,13 +52,13 @@ public static partial class OpenIddictServerHandlers
]);
/// <summary>
/// Contains the logic responsible for extracting logout requests and invoking the corresponding event handlers.
/// Contains the logic responsible for extracting end session requests and invoking the corresponding event handlers.
/// </summary>
public sealed class ExtractLogoutRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class ExtractEndSessionRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ExtractLogoutRequest(IOpenIddictServerDispatcher dispatcher)
public ExtractEndSessionRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -66,8 +66,8 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireLogoutRequest>()
.UseScopedHandler<ExtractLogoutRequest>()
.AddFilter<RequireEndSessionRequest>()
.UseScopedHandler<ExtractEndSessionRequest>()
.SetOrder(100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -80,7 +80,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ExtractLogoutRequestContext(context.Transaction);
var notification = new ExtractEndSessionRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -114,13 +114,13 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for validating logout requests and invoking the corresponding event handlers.
/// Contains the logic responsible for validating end session requests and invoking the corresponding event handlers.
/// </summary>
public sealed class ValidateLogoutRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class ValidateEndSessionRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ValidateLogoutRequest(IOpenIddictServerDispatcher dispatcher)
public ValidateEndSessionRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -128,9 +128,9 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireLogoutRequest>()
.UseScopedHandler<ValidateLogoutRequest>()
.SetOrder(ExtractLogoutRequest.Descriptor.Order + 1_000)
.AddFilter<RequireEndSessionRequest>()
.UseScopedHandler<ValidateEndSessionRequest>()
.SetOrder(ExtractEndSessionRequest.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -142,12 +142,12 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ValidateLogoutRequestContext(context.Transaction);
var notification = new ValidateEndSessionRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
// Store the context object in the transaction so it can be later retrieved by handlers
// that want to access the redirect_uri without triggering a new validation process.
context.Transaction.SetProperty(typeof(ValidateLogoutRequestContext).FullName!, notification);
context.Transaction.SetProperty(typeof(ValidateEndSessionRequestContext).FullName!, notification);
if (notification.IsRequestHandled)
{
@ -175,13 +175,13 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for handling logout requests and invoking the corresponding event handlers.
/// Contains the logic responsible for handling end session requests and invoking the corresponding event handlers.
/// </summary>
public sealed class HandleLogoutRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class HandleEndSessionRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public HandleLogoutRequest(IOpenIddictServerDispatcher dispatcher)
public HandleEndSessionRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -189,9 +189,9 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireLogoutRequest>()
.UseScopedHandler<HandleLogoutRequest>()
.SetOrder(ValidateLogoutRequest.Descriptor.Order + 1_000)
.AddFilter<RequireEndSessionRequest>()
.UseScopedHandler<HandleEndSessionRequest>()
.SetOrder(ValidateEndSessionRequest.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -203,7 +203,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new HandleLogoutRequestContext(context.Transaction);
var notification = new HandleEndSessionRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -273,11 +273,11 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for processing sign-in responses and invoking the corresponding event handlers.
/// </summary>
public sealed class ApplyLogoutResponse<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseRequestContext
public sealed class ApplyEndSessionResponse<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseRequestContext
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ApplyLogoutResponse(IOpenIddictServerDispatcher dispatcher)
public ApplyEndSessionResponse(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -285,8 +285,8 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<TContext>()
.AddFilter<RequireLogoutRequest>()
.UseScopedHandler<ApplyLogoutResponse<TContext>>()
.AddFilter<RequireEndSessionRequest>()
.UseScopedHandler<ApplyEndSessionResponse<TContext>>()
.SetOrder(500_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -299,7 +299,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ApplyLogoutResponseContext(context.Transaction);
var notification = new ApplyEndSessionResponseContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -319,22 +319,22 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for rejecting logout requests that specify an invalid post_logout_redirect_uri parameter.
/// Contains the logic responsible for rejecting end session requests that specify an invalid post_logout_redirect_uri parameter.
/// </summary>
public sealed class ValidatePostLogoutRedirectUriParameter : IOpenIddictServerHandler<ValidateLogoutRequestContext>
public sealed class ValidatePostLogoutRedirectUriParameter : IOpenIddictServerHandler<ValidateEndSessionRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateLogoutRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateEndSessionRequestContext>()
.UseSingletonHandler<ValidatePostLogoutRedirectUriParameter>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ValidateLogoutRequestContext context)
public ValueTask HandleAsync(ValidateEndSessionRequestContext context)
{
if (context is null)
{
@ -376,9 +376,9 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for applying the authentication logic to logout requests.
/// Contains the logic responsible for applying the authentication logic to end session requests.
/// </summary>
public sealed class ValidateAuthentication : IOpenIddictServerHandler<ValidateLogoutRequestContext>
public sealed class ValidateAuthentication : IOpenIddictServerHandler<ValidateEndSessionRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
@ -389,14 +389,14 @@ public static partial class OpenIddictServerHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateLogoutRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateEndSessionRequestContext>()
.UseScopedHandler<ValidateAuthentication>()
.SetOrder(ValidatePostLogoutRedirectUriParameter.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateLogoutRequestContext context)
public async ValueTask HandleAsync(ValidateEndSessionRequestContext context)
{
if (context is null)
{
@ -441,7 +441,7 @@ public static partial class OpenIddictServerHandlers
/// requests that use an invalid post_logout_redirect_uri.
/// Note: this handler is not used when the degraded mode is enabled.
/// </summary>
public sealed class ValidateClientPostLogoutRedirectUri : IOpenIddictServerHandler<ValidateLogoutRequestContext>
public sealed class ValidateClientPostLogoutRedirectUri : IOpenIddictServerHandler<ValidateEndSessionRequestContext>
{
private readonly IOpenIddictApplicationManager _applicationManager;
@ -454,7 +454,7 @@ public static partial class OpenIddictServerHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateLogoutRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateEndSessionRequestContext>()
.AddFilter<RequireDegradedModeDisabled>()
.AddFilter<RequirePostLogoutRedirectUriParameter>()
.UseScopedHandler<ValidateClientPostLogoutRedirectUri>()
@ -463,7 +463,7 @@ public static partial class OpenIddictServerHandlers
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateLogoutRequestContext context)
public async ValueTask HandleAsync(ValidateEndSessionRequestContext context)
{
if (context is null)
{
@ -527,8 +527,10 @@ public static partial class OpenIddictServerHandlers
await foreach (var application in _applicationManager.FindByPostLogoutRedirectUriAsync(uri))
{
// Note: the legacy "ept:logout" permission is still allowed for backward compatibility.
if (!context.Options.IgnoreEndpointPermissions &&
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Logout))
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout"))
{
continue;
}
@ -558,8 +560,10 @@ public static partial class OpenIddictServerHandlers
await foreach (var application in _applicationManager.FindByPostLogoutRedirectUriAsync(
uri: new UriBuilder(value) { Port = -1 }.Uri.AbsoluteUri))
{
// Note: the legacy "ept:logout" permission is still allowed for backward compatibility.
if (!context.Options.IgnoreEndpointPermissions &&
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Logout))
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout"))
{
continue;
}
@ -578,10 +582,10 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for rejecting logout requests made by unauthorized applications.
/// Contains the logic responsible for rejecting end session requests made by unauthorized applications.
/// Note: this handler is not used when the degraded mode is enabled or when endpoint permissions are disabled.
/// </summary>
public sealed class ValidateEndpointPermissions : IOpenIddictServerHandler<ValidateLogoutRequestContext>
public sealed class ValidateEndpointPermissions : IOpenIddictServerHandler<ValidateEndSessionRequestContext>
{
private readonly IOpenIddictApplicationManager _applicationManager;
@ -594,7 +598,7 @@ public static partial class OpenIddictServerHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateLogoutRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateEndSessionRequestContext>()
.AddFilter<RequireEndpointPermissionsEnabled>()
.AddFilter<RequireDegradedModeDisabled>()
// Note: support for the client_id parameter was only added in the second draft of the
@ -610,7 +614,7 @@ public static partial class OpenIddictServerHandlers
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateLogoutRequestContext context)
public async ValueTask HandleAsync(ValidateEndSessionRequestContext context)
{
if (context is null)
{
@ -622,8 +626,11 @@ public static partial class OpenIddictServerHandlers
var application = await _applicationManager.FindByClientIdAsync(context.ClientId) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the logout endpoint.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Logout))
// Reject the request if the application is not allowed to use the end session endpoint.
//
// Note: the legacy "ept:logout" permission is still allowed for backward compatibility.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout"))
{
context.Logger.LogInformation(SR.GetResourceString(SR.ID6048), context.ClientId);
@ -638,10 +645,10 @@ public static partial class OpenIddictServerHandlers
}
/// <summary>
/// Contains the logic responsible for rejecting logout requests that specify an identity
/// token hint that cannot be used by the client application sending the logout request.
/// Contains the logic responsible for rejecting end session requests that specify an identity
/// token hint that cannot be used by the client application sending the end session request.
/// </summary>
public sealed class ValidateAuthorizedParty : IOpenIddictServerHandler<ValidateLogoutRequestContext>
public sealed class ValidateAuthorizedParty : IOpenIddictServerHandler<ValidateEndSessionRequestContext>
{
private readonly IOpenIddictApplicationManager? _applicationManager;
@ -652,7 +659,7 @@ public static partial class OpenIddictServerHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateLogoutRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateEndSessionRequestContext>()
.UseScopedHandler<ValidateAuthorizedParty>(static provider =>
{
// Note: the application manager is only resolved if the degraded mode was not enabled to ensure
@ -669,7 +676,7 @@ public static partial class OpenIddictServerHandlers
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateLogoutRequestContext context)
public async ValueTask HandleAsync(ValidateEndSessionRequestContext context)
{
if (context is null)
{
@ -754,8 +761,10 @@ public static partial class OpenIddictServerHandlers
continue;
}
// Note: the legacy "ept:logout" permission is still allowed for backward compatibility.
if (!context.Options.IgnoreEndpointPermissions &&
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Logout))
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout"))
{
continue;
}
@ -775,28 +784,28 @@ public static partial class OpenIddictServerHandlers
/// Contains the logic responsible for attaching the principal
/// extracted from the identity token hint to the event context.
/// </summary>
public sealed class AttachPrincipal : IOpenIddictServerHandler<HandleLogoutRequestContext>
public sealed class AttachPrincipal : IOpenIddictServerHandler<HandleEndSessionRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleLogoutRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleEndSessionRequestContext>()
.UseSingletonHandler<AttachPrincipal>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleLogoutRequestContext context)
public ValueTask HandleAsync(HandleEndSessionRequestContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
var notification = context.Transaction.GetProperty<ValidateLogoutRequestContext>(
typeof(ValidateLogoutRequestContext).FullName!) ??
var notification = context.Transaction.GetProperty<ValidateEndSessionRequestContext>(
typeof(ValidateEndSessionRequestContext).FullName!) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0007));
context.IdentityTokenHintPrincipal ??= notification.IdentityTokenHintPrincipal;
@ -809,20 +818,20 @@ public static partial class OpenIddictServerHandlers
/// Contains the logic responsible for inferring the redirect URI
/// used to send the response back to the client application.
/// </summary>
public sealed class AttachPostLogoutRedirectUri : IOpenIddictServerHandler<ApplyLogoutResponseContext>
public sealed class AttachPostLogoutRedirectUri : IOpenIddictServerHandler<ApplyEndSessionResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyLogoutResponseContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyEndSessionResponseContext>()
.UseSingletonHandler<AttachPostLogoutRedirectUri>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyLogoutResponseContext context)
public ValueTask HandleAsync(ApplyEndSessionResponseContext context)
{
if (context is null)
{
@ -834,11 +843,11 @@ public static partial class OpenIddictServerHandlers
return default;
}
var notification = context.Transaction.GetProperty<ValidateLogoutRequestContext>(
typeof(ValidateLogoutRequestContext).FullName!);
var notification = context.Transaction.GetProperty<ValidateEndSessionRequestContext>(
typeof(ValidateEndSessionRequestContext).FullName!);
// Note: at this stage, the validated redirect URI property may be null (e.g if
// an error is returned from the ExtractLogoutRequest/ValidateLogoutRequest events).
// an error is returned from the ExtractEndSessionRequest/ValidateEndSessionRequest events).
if (notification is { IsRejected: false })
{
context.PostLogoutRedirectUri = notification.PostLogoutRedirectUri;
@ -851,27 +860,27 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for attaching the state to the response.
/// </summary>
public sealed class AttachResponseState : IOpenIddictServerHandler<ApplyLogoutResponseContext>
public sealed class AttachResponseState : IOpenIddictServerHandler<ApplyEndSessionResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyLogoutResponseContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ApplyEndSessionResponseContext>()
.UseSingletonHandler<AttachResponseState>()
.SetOrder(AttachPostLogoutRedirectUri.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ApplyLogoutResponseContext context)
public ValueTask HandleAsync(ApplyEndSessionResponseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
// Attach the request state to the logout response.
// Attach the request state to the end session response.
if (string.IsNullOrEmpty(context.Response.State))
{
context.Response.State = context.Request?.State;

100
src/OpenIddict.Server/OpenIddictServerHandlers.Userinfo.cs

@ -13,27 +13,27 @@ namespace OpenIddict.Server;
public static partial class OpenIddictServerHandlers
{
public static class Userinfo
public static class UserInfo
{
public static ImmutableArray<OpenIddictServerHandlerDescriptor> DefaultHandlers { get; } = ImmutableArray.Create([
/*
* Userinfo request top-level processing:
* UserInfo request top-level processing:
*/
ExtractUserinfoRequest.Descriptor,
ValidateUserinfoRequest.Descriptor,
HandleUserinfoRequest.Descriptor,
ApplyUserinfoResponse<ProcessChallengeContext>.Descriptor,
ApplyUserinfoResponse<ProcessErrorContext>.Descriptor,
ApplyUserinfoResponse<ProcessRequestContext>.Descriptor,
ExtractUserInfoRequest.Descriptor,
ValidateUserInfoRequest.Descriptor,
HandleUserInfoRequest.Descriptor,
ApplyUserInfoResponse<ProcessChallengeContext>.Descriptor,
ApplyUserInfoResponse<ProcessErrorContext>.Descriptor,
ApplyUserInfoResponse<ProcessRequestContext>.Descriptor,
/*
* Userinfo request validation:
* UserInfo request validation:
*/
ValidateAccessTokenParameter.Descriptor,
ValidateAuthentication.Descriptor,
/*
* Userinfo request handling:
* UserInfo request handling:
*/
AttachPrincipal.Descriptor,
AttachAudiences.Descriptor,
@ -43,11 +43,11 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for extracting userinfo requests and invoking the corresponding event handlers.
/// </summary>
public sealed class ExtractUserinfoRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class ExtractUserInfoRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ExtractUserinfoRequest(IOpenIddictServerDispatcher dispatcher)
public ExtractUserInfoRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -55,8 +55,8 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireUserinfoRequest>()
.UseScopedHandler<ExtractUserinfoRequest>()
.AddFilter<RequireUserInfoRequest>()
.UseScopedHandler<ExtractUserInfoRequest>()
.SetOrder(100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -69,7 +69,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ExtractUserinfoRequestContext(context.Transaction);
var notification = new ExtractUserInfoRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -105,11 +105,11 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for validating userinfo requests and invoking the corresponding event handlers.
/// </summary>
public sealed class ValidateUserinfoRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class ValidateUserInfoRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ValidateUserinfoRequest(IOpenIddictServerDispatcher dispatcher)
public ValidateUserInfoRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -117,9 +117,9 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireUserinfoRequest>()
.UseScopedHandler<ValidateUserinfoRequest>()
.SetOrder(ExtractUserinfoRequest.Descriptor.Order + 1_000)
.AddFilter<RequireUserInfoRequest>()
.UseScopedHandler<ValidateUserInfoRequest>()
.SetOrder(ExtractUserInfoRequest.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -131,12 +131,12 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ValidateUserinfoRequestContext(context.Transaction);
var notification = new ValidateUserInfoRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
// Store the context object in the transaction so it can be later retrieved by handlers
// that want to access the principal without triggering a new validation process.
context.Transaction.SetProperty(typeof(ValidateUserinfoRequestContext).FullName!, notification);
context.Transaction.SetProperty(typeof(ValidateUserInfoRequestContext).FullName!, notification);
if (notification.IsRequestHandled)
{
@ -166,11 +166,11 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for handling userinfo requests and invoking the corresponding event handlers.
/// </summary>
public sealed class HandleUserinfoRequest : IOpenIddictServerHandler<ProcessRequestContext>
public sealed class HandleUserInfoRequest : IOpenIddictServerHandler<ProcessRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public HandleUserinfoRequest(IOpenIddictServerDispatcher dispatcher)
public HandleUserInfoRequest(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -178,9 +178,9 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
.AddFilter<RequireUserinfoRequest>()
.UseScopedHandler<HandleUserinfoRequest>()
.SetOrder(ValidateUserinfoRequest.Descriptor.Order + 1_000)
.AddFilter<RequireUserInfoRequest>()
.UseScopedHandler<HandleUserInfoRequest>()
.SetOrder(ValidateUserInfoRequest.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -192,7 +192,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new HandleUserinfoRequestContext(context.Transaction);
var notification = new HandleUserInfoRequestContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -258,11 +258,11 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for processing userinfo responses and invoking the corresponding event handlers.
/// </summary>
public sealed class ApplyUserinfoResponse<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseRequestContext
public sealed class ApplyUserInfoResponse<TContext> : IOpenIddictServerHandler<TContext> where TContext : BaseRequestContext
{
private readonly IOpenIddictServerDispatcher _dispatcher;
public ApplyUserinfoResponse(IOpenIddictServerDispatcher dispatcher)
public ApplyUserInfoResponse(IOpenIddictServerDispatcher dispatcher)
=> _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
/// <summary>
@ -270,8 +270,8 @@ public static partial class OpenIddictServerHandlers
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<TContext>()
.AddFilter<RequireUserinfoRequest>()
.UseScopedHandler<ApplyUserinfoResponse<TContext>>()
.AddFilter<RequireUserInfoRequest>()
.UseScopedHandler<ApplyUserInfoResponse<TContext>>()
.SetOrder(500_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
@ -284,7 +284,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
var notification = new ApplyUserinfoResponseContext(context.Transaction);
var notification = new ApplyUserInfoResponseContext(context.Transaction);
await _dispatcher.DispatchAsync(notification);
if (notification.IsRequestHandled)
@ -306,20 +306,20 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for rejecting userinfo requests that don't specify an access token.
/// </summary>
public sealed class ValidateAccessTokenParameter : IOpenIddictServerHandler<ValidateUserinfoRequestContext>
public sealed class ValidateAccessTokenParameter : IOpenIddictServerHandler<ValidateUserInfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateUserinfoRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateUserInfoRequestContext>()
.UseSingletonHandler<ValidateAccessTokenParameter>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ValidateUserinfoRequestContext context)
public ValueTask HandleAsync(ValidateUserInfoRequestContext context)
{
if (context is null)
{
@ -345,7 +345,7 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for applying the authentication logic to userinfo requests.
/// </summary>
public sealed class ValidateAuthentication : IOpenIddictServerHandler<ValidateUserinfoRequestContext>
public sealed class ValidateAuthentication : IOpenIddictServerHandler<ValidateUserInfoRequestContext>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
@ -356,14 +356,14 @@ public static partial class OpenIddictServerHandlers
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateUserinfoRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<ValidateUserInfoRequestContext>()
.UseScopedHandler<ValidateAuthentication>()
.SetOrder(ValidateAccessTokenParameter.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public async ValueTask HandleAsync(ValidateUserinfoRequestContext context)
public async ValueTask HandleAsync(ValidateUserInfoRequestContext context)
{
if (context is null)
{
@ -407,28 +407,28 @@ public static partial class OpenIddictServerHandlers
/// Contains the logic responsible for attaching the principal
/// extracted from the access token to the event context.
/// </summary>
public sealed class AttachPrincipal : IOpenIddictServerHandler<HandleUserinfoRequestContext>
public sealed class AttachPrincipal : IOpenIddictServerHandler<HandleUserInfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleUserinfoRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleUserInfoRequestContext>()
.UseSingletonHandler<AttachPrincipal>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleUserinfoRequestContext context)
public ValueTask HandleAsync(HandleUserInfoRequestContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
var notification = context.Transaction.GetProperty<ValidateUserinfoRequestContext>(
typeof(ValidateUserinfoRequestContext).FullName!) ??
var notification = context.Transaction.GetProperty<ValidateUserInfoRequestContext>(
typeof(ValidateUserInfoRequestContext).FullName!) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0007));
Debug.Assert(notification.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
@ -442,20 +442,20 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for attaching the audiences to the userinfo response.
/// </summary>
public sealed class AttachAudiences : IOpenIddictServerHandler<HandleUserinfoRequestContext>
public sealed class AttachAudiences : IOpenIddictServerHandler<HandleUserInfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleUserinfoRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleUserInfoRequestContext>()
.UseSingletonHandler<AttachAudiences>()
.SetOrder(AttachPrincipal.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleUserinfoRequestContext context)
public ValueTask HandleAsync(HandleUserInfoRequestContext context)
{
if (context is null)
{
@ -476,20 +476,20 @@ public static partial class OpenIddictServerHandlers
/// <summary>
/// Contains the logic responsible for attaching well known claims to the userinfo response.
/// </summary>
public sealed class AttachClaims : IOpenIddictServerHandler<HandleUserinfoRequestContext>
public sealed class AttachClaims : IOpenIddictServerHandler<HandleUserInfoRequestContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleUserinfoRequestContext>()
= OpenIddictServerHandlerDescriptor.CreateBuilder<HandleUserInfoRequestContext>()
.UseSingletonHandler<AttachClaims>()
.SetOrder(AttachAudiences.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleUserinfoRequestContext context)
public ValueTask HandleAsync(HandleUserInfoRequestContext context)
{
if (context is null)
{

168
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -119,7 +119,7 @@ public static partial class OpenIddictServerHandlers
.. Protection.DefaultHandlers,
.. Revocation.DefaultHandlers,
.. Session.DefaultHandlers,
.. Userinfo.DefaultHandlers
.. UserInfo.DefaultHandlers
]);
/// <summary>
@ -151,17 +151,17 @@ public static partial class OpenIddictServerHandlers
}
context.EndpointType =
Matches(context.Options.AuthorizationEndpointUris) ? OpenIddictServerEndpointType.Authorization :
Matches(context.Options.ConfigurationEndpointUris) ? OpenIddictServerEndpointType.Configuration :
Matches(context.Options.CryptographyEndpointUris) ? OpenIddictServerEndpointType.Cryptography :
Matches(context.Options.DeviceEndpointUris) ? OpenIddictServerEndpointType.Device :
Matches(context.Options.IntrospectionEndpointUris) ? OpenIddictServerEndpointType.Introspection :
Matches(context.Options.LogoutEndpointUris) ? OpenIddictServerEndpointType.Logout :
Matches(context.Options.RevocationEndpointUris) ? OpenIddictServerEndpointType.Revocation :
Matches(context.Options.TokenEndpointUris) ? OpenIddictServerEndpointType.Token :
Matches(context.Options.UserinfoEndpointUris) ? OpenIddictServerEndpointType.Userinfo :
Matches(context.Options.VerificationEndpointUris) ? OpenIddictServerEndpointType.Verification :
OpenIddictServerEndpointType.Unknown;
Matches(context.Options.AuthorizationEndpointUris) ? OpenIddictServerEndpointType.Authorization :
Matches(context.Options.ConfigurationEndpointUris) ? OpenIddictServerEndpointType.Configuration :
Matches(context.Options.DeviceAuthorizationEndpointUris) ? OpenIddictServerEndpointType.DeviceAuthorization :
Matches(context.Options.EndSessionEndpointUris) ? OpenIddictServerEndpointType.EndSession :
Matches(context.Options.EndUserVerificationEndpointUris) ? OpenIddictServerEndpointType.EndUserVerification :
Matches(context.Options.IntrospectionEndpointUris) ? OpenIddictServerEndpointType.Introspection :
Matches(context.Options.JsonWebKeySetEndpointUris) ? OpenIddictServerEndpointType.JsonWebKeySet :
Matches(context.Options.RevocationEndpointUris) ? OpenIddictServerEndpointType.Revocation :
Matches(context.Options.TokenEndpointUris) ? OpenIddictServerEndpointType.Token :
Matches(context.Options.UserInfoEndpointUris) ? OpenIddictServerEndpointType.UserInfo :
OpenIddictServerEndpointType.Unknown;
if (context.EndpointType is not OpenIddictServerEndpointType.Unknown)
{
@ -240,10 +240,10 @@ public static partial class OpenIddictServerHandlers
return context.EndpointType switch
{
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Device or
OpenIddictServerEndpointType.Introspection or OpenIddictServerEndpointType.Logout or
OpenIddictServerEndpointType.Revocation or OpenIddictServerEndpointType.Token or
OpenIddictServerEndpointType.Userinfo or OpenIddictServerEndpointType.Verification
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.DeviceAuthorization or
OpenIddictServerEndpointType.EndSession or OpenIddictServerEndpointType.EndUserVerification or
OpenIddictServerEndpointType.Introspection or OpenIddictServerEndpointType.Revocation or
OpenIddictServerEndpointType.Token or OpenIddictServerEndpointType.UserInfo
=> default,
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0002)),
@ -280,7 +280,7 @@ public static partial class OpenIddictServerHandlers
context.RejectAccessToken) = context.EndpointType switch
{
// The userinfo endpoint requires sending a valid access token.
OpenIddictServerEndpointType.Userinfo => (true, true, true, true),
OpenIddictServerEndpointType.UserInfo => (true, true, true, true),
_ => (false, false, false, false)
};
@ -305,7 +305,7 @@ public static partial class OpenIddictServerHandlers
// Client assertions can be used with all the endpoints that support client authentication.
// By default, client assertions are not required, but they are extracted and validated if
// present and invalid client assertions are always automatically rejected by OpenIddict.
OpenIddictServerEndpointType.Device or OpenIddictServerEndpointType.Introspection or
OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or
OpenIddictServerEndpointType.Revocation or OpenIddictServerEndpointType.Token
=> (true, false, true, true),
@ -347,7 +347,7 @@ public static partial class OpenIddictServerHandlers
//
// As such, identity token hints are extracted and validated, but
// the authentication demand is not rejected if they are not valid.
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Logout
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.EndSession
=> (true, false, true, false),
_ => (false, false, false, false)
@ -370,9 +370,9 @@ public static partial class OpenIddictServerHandlers
context.ValidateUserCode,
context.RejectUserCode) = context.EndpointType switch
{
// Note: the verification endpoint can be accessed without specifying a
// Note: the end-user verification endpoint can be accessed without specifying a
// user code (that can be later set by the user using a form, for instance).
OpenIddictServerEndpointType.Verification => (true, false, true, false),
OpenIddictServerEndpointType.EndUserVerification => (true, false, true, false),
_ => (false, false, false, false)
};
@ -406,7 +406,7 @@ public static partial class OpenIddictServerHandlers
context.AccessToken = context.EndpointType switch
{
OpenIddictServerEndpointType.Userinfo when context.ExtractAccessToken
OpenIddictServerEndpointType.UserInfo when context.ExtractAccessToken
=> context.Request.AccessToken,
_ => null
@ -422,8 +422,8 @@ public static partial class OpenIddictServerHandlers
(context.ClientAssertion, context.ClientAssertionType) = context.EndpointType switch
{
OpenIddictServerEndpointType.Device or OpenIddictServerEndpointType.Introspection or
OpenIddictServerEndpointType.Revocation or OpenIddictServerEndpointType.Token
OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or
OpenIddictServerEndpointType.Revocation or OpenIddictServerEndpointType.Token
when context.ExtractClientAssertion
=> (context.Request.ClientAssertion, context.Request.ClientAssertionType),
@ -450,7 +450,7 @@ public static partial class OpenIddictServerHandlers
context.IdentityToken = context.EndpointType switch
{
OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.Logout when context.ExtractIdentityToken
OpenIddictServerEndpointType.EndSession when context.ExtractIdentityToken
=> context.Request.IdTokenHint,
_ => null
@ -466,7 +466,7 @@ public static partial class OpenIddictServerHandlers
context.UserCode = context.EndpointType switch
{
OpenIddictServerEndpointType.Verification when context.ExtractUserCode
OpenIddictServerEndpointType.EndUserVerification when context.ExtractUserCode
=> context.Request.UserCode,
_ => null
@ -885,9 +885,9 @@ public static partial class OpenIddictServerHandlers
}
// If the current request is a device request, consider the audience valid
// if the address matches one of the URIs assigned to the device endpoint.
if (context.EndpointType is OpenIddictServerEndpointType.Device &&
MatchesAnyUri(uri, context.Options.DeviceEndpointUris))
// if the address matches one of the URIs assigned to the device authorization endpoint.
if (context.EndpointType is OpenIddictServerEndpointType.DeviceAuthorization &&
MatchesAnyUri(uri, context.Options.DeviceAuthorizationEndpointUris))
{
return true;
}
@ -987,7 +987,8 @@ public static partial class OpenIddictServerHandlers
}
// Don't validate the client identifier on endpoints that don't support client identification.
if (context.EndpointType is OpenIddictServerEndpointType.Userinfo or OpenIddictServerEndpointType.Verification)
if (context.EndpointType is OpenIddictServerEndpointType.EndUserVerification or
OpenIddictServerEndpointType.UserInfo)
{
return;
}
@ -999,7 +1000,7 @@ public static partial class OpenIddictServerHandlers
// Note: support for the client_id parameter was only added in the second draft of the
// https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout specification
// and is optional. As such, the client identifier is only validated if it was specified.
case OpenIddictServerEndpointType.Logout:
case OpenIddictServerEndpointType.EndSession:
return;
case OpenIddictServerEndpointType.Introspection when context.Options.AcceptAnonymousClients:
@ -1036,7 +1037,7 @@ public static partial class OpenIddictServerHandlers
error: context.EndpointType switch
{
// For non-interactive endpoints, return "invalid_client" instead of "invalid_request".
OpenIddictServerEndpointType.Device or OpenIddictServerEndpointType.Introspection or
OpenIddictServerEndpointType.DeviceAuthorization or OpenIddictServerEndpointType.Introspection or
OpenIddictServerEndpointType.Revocation or OpenIddictServerEndpointType.Token
=> Errors.InvalidClient,
@ -1088,10 +1089,10 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
// Don't validate the client type on endpoints that don't support client authentication.
if (context.EndpointType is OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.Logout or
OpenIddictServerEndpointType.Userinfo or
OpenIddictServerEndpointType.Verification)
if (context.EndpointType is OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.EndSession or
OpenIddictServerEndpointType.EndUserVerification or
OpenIddictServerEndpointType.UserInfo)
{
return;
}
@ -1197,10 +1198,10 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientSecret), SR.FormatID4000(Parameters.ClientSecret));
// Don't validate the client secret on endpoints that don't support client authentication.
if (context.EndpointType is OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.Logout or
OpenIddictServerEndpointType.Userinfo or
OpenIddictServerEndpointType.Verification)
if (context.EndpointType is OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.EndSession or
OpenIddictServerEndpointType.EndUserVerification or
OpenIddictServerEndpointType.UserInfo)
{
return;
}
@ -1572,7 +1573,7 @@ public static partial class OpenIddictServerHandlers
{
// Don't validate the lifetime of id_tokens used as id_token_hints.
DisableLifetimeValidation = context.EndpointType is OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.Logout,
OpenIddictServerEndpointType.EndSession,
Token = context.IdentityToken,
ValidTokenTypes = { TokenTypeHints.IdToken }
};
@ -1789,7 +1790,7 @@ public static partial class OpenIddictServerHandlers
OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType()
=> context.RefreshTokenPrincipal,
OpenIddictServerEndpointType.Verification => context.UserCodePrincipal,
OpenIddictServerEndpointType.EndUserVerification => context.UserCodePrincipal,
_ => null
};
@ -1903,10 +1904,10 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
if (context.EndpointType is not (OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.Token or
OpenIddictServerEndpointType.Userinfo or
OpenIddictServerEndpointType.Verification))
if (context.EndpointType is not (OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.EndUserVerification or
OpenIddictServerEndpointType.Token or
OpenIddictServerEndpointType.UserInfo))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0006));
}
@ -1940,33 +1941,33 @@ public static partial class OpenIddictServerHandlers
context.Response.Error ??= context.EndpointType switch
{
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.EndUserVerification
=> Errors.AccessDenied,
OpenIddictServerEndpointType.Token => Errors.InvalidGrant,
OpenIddictServerEndpointType.Userinfo => Errors.InsufficientAccess,
OpenIddictServerEndpointType.UserInfo => Errors.InsufficientAccess,
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006))
};
context.Response.ErrorDescription ??= context.EndpointType switch
{
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.EndUserVerification
=> SR.GetResourceString(SR.ID2015),
OpenIddictServerEndpointType.Token => SR.GetResourceString(SR.ID2024),
OpenIddictServerEndpointType.Userinfo => SR.GetResourceString(SR.ID2025),
OpenIddictServerEndpointType.UserInfo => SR.GetResourceString(SR.ID2025),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006))
};
context.Response.ErrorUri ??= context.EndpointType switch
{
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.EndUserVerification
=> SR.FormatID8000(SR.ID2015),
OpenIddictServerEndpointType.Token => SR.FormatID8000(SR.ID2024),
OpenIddictServerEndpointType.Userinfo => SR.FormatID8000(SR.ID2025),
OpenIddictServerEndpointType.UserInfo => SR.FormatID8000(SR.ID2025),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006))
};
@ -2008,7 +2009,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
if (context.EndpointType is not OpenIddictServerEndpointType.Verification)
if (context.EndpointType is not OpenIddictServerEndpointType.EndUserVerification)
{
return;
}
@ -2067,7 +2068,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
if (context.EndpointType is not OpenIddictServerEndpointType.Verification)
if (context.EndpointType is not OpenIddictServerEndpointType.EndUserVerification)
{
return;
}
@ -2153,10 +2154,10 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
if (context.EndpointType is not (OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.Device or
OpenIddictServerEndpointType.Token or
OpenIddictServerEndpointType.Verification))
if (context.EndpointType is not (OpenIddictServerEndpointType.Authorization or
OpenIddictServerEndpointType.DeviceAuthorization or
OpenIddictServerEndpointType.EndUserVerification or
OpenIddictServerEndpointType.Token))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0010));
}
@ -2166,10 +2167,10 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0011));
}
// Note: sign-in operations triggered from the device endpoint can't be associated to specific users
// as users' identity is not known until they reach the verification endpoint and validate the user code.
// Note: sign-in operations triggered from the device authorization endpoint can't be associated to specific users
// as users' identity is not known until they reach the end-user verification endpoint and validate the user code.
// As such, the principal used in this case cannot contain an authenticated identity or a subject claim.
if (context.EndpointType is OpenIddictServerEndpointType.Device)
if (context.EndpointType is OpenIddictServerEndpointType.DeviceAuthorization)
{
if (context.Principal.Identity.IsAuthenticated)
{
@ -2283,11 +2284,11 @@ public static partial class OpenIddictServerHandlers
switch (context.EndpointType)
{
case OpenIddictServerEndpointType.EndUserVerification:
case OpenIddictServerEndpointType.Token when context.Request.IsAuthorizationCodeGrantType():
case OpenIddictServerEndpointType.Token when context.Request.IsDeviceCodeGrantType():
case OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType() &&
!context.Options.DisableRollingRefreshTokens:
case OpenIddictServerEndpointType.Verification:
break;
default: return;
@ -2308,7 +2309,7 @@ public static partial class OpenIddictServerHandlers
OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType()
=> notification.RefreshTokenPrincipal,
OpenIddictServerEndpointType.Verification => notification.UserCodePrincipal,
OpenIddictServerEndpointType.EndUserVerification => notification.UserCodePrincipal,
_ => null
};
@ -2389,10 +2390,10 @@ public static partial class OpenIddictServerHandlers
switch (context.EndpointType)
{
case OpenIddictServerEndpointType.EndUserVerification:
case OpenIddictServerEndpointType.Token when context.Request.IsAuthorizationCodeGrantType():
case OpenIddictServerEndpointType.Token when context.Request.IsDeviceCodeGrantType():
case OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType():
case OpenIddictServerEndpointType.Verification:
break;
default: return default;
@ -2406,6 +2407,8 @@ public static partial class OpenIddictServerHandlers
var principal = context.EndpointType switch
{
OpenIddictServerEndpointType.EndUserVerification => notification.UserCodePrincipal,
OpenIddictServerEndpointType.Token when context.Request.IsAuthorizationCodeGrantType()
=> notification.AuthorizationCodePrincipal,
@ -2415,8 +2418,6 @@ public static partial class OpenIddictServerHandlers
OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType()
=> notification.RefreshTokenPrincipal,
OpenIddictServerEndpointType.Verification => notification.UserCodePrincipal,
_ => null
};
@ -2436,8 +2437,8 @@ public static partial class OpenIddictServerHandlers
continue;
}
// When the request is a verification request, don't flow the scopes from the user code.
if (context.EndpointType is OpenIddictServerEndpointType.Verification &&
// When the request is a end-user verification request, don't flow the scopes from the user code.
if (context.EndpointType is OpenIddictServerEndpointType.EndUserVerification &&
string.Equals(claims.Key, Claims.Private.Scope, StringComparison.OrdinalIgnoreCase))
{
continue;
@ -2645,13 +2646,13 @@ public static partial class OpenIddictServerHandlers
(context.GenerateDeviceCode, context.IncludeDeviceCode) = context.EndpointType switch
{
// For device requests, always generate and return a device code.
OpenIddictServerEndpointType.Device => (true, true),
OpenIddictServerEndpointType.DeviceAuthorization => (true, true),
// Note: a device code is not directly returned by the verification endpoint (that generally
// Note: a device code is not directly returned by the end-user verification endpoint (that generally
// returns an empty response or redirects the user agent to another page), but a device code
// must be generated to replace the payload of the device code initially returned to the client.
// In this case, the device code is not returned as part of the response but persisted in the DB.
OpenIddictServerEndpointType.Verification => (true, false),
OpenIddictServerEndpointType.EndUserVerification => (true, false),
_ => (false, false)
};
@ -2683,7 +2684,7 @@ public static partial class OpenIddictServerHandlers
(context.GenerateUserCode, context.IncludeUserCode) = context.EndpointType switch
{
// Only generate and return a user code if the request is a device authorization request.
OpenIddictServerEndpointType.Device => (true, true),
OpenIddictServerEndpointType.DeviceAuthorization => (true, true),
_ => (false, false)
};
@ -3189,8 +3190,8 @@ public static partial class OpenIddictServerHandlers
principal.SetClaim(Claims.Private.Issuer, (context.Options.Issuer ?? context.BaseUri)?.AbsoluteUri);
// Restore the device code internal token identifier from the principal
// resolved from the user code used in the user code verification request.
if (context.EndpointType is OpenIddictServerEndpointType.Verification)
// resolved from the user code used in the end-user verification request.
if (context.EndpointType is OpenIddictServerEndpointType.EndUserVerification)
{
principal.SetClaim(Claims.Private.TokenId, context.Principal.GetClaim(Claims.Private.DeviceCodeId));
}
@ -3765,19 +3766,19 @@ public static partial class OpenIddictServerHandlers
{
ClientId = context.ClientId,
// Don't create a new entry if the device code is generated as part
// of a device code swap made by the user code verification endpoint.
// of a device code swap made by the end-user verification endpoint.
CreateTokenEntry = context.EndpointType switch
{
OpenIddictServerEndpointType.Verification => false,
OpenIddictServerEndpointType.EndUserVerification => false,
_ => !context.Options.DisableTokenStorage
},
IsReferenceToken = !context.Options.DisableTokenStorage,
// Device codes are not persisted using the generic logic if they are generated
// as part of a device code swap made by the user code verification endpoint.
// as part of a device code swap made by the end-user verification endpoint.
PersistTokenPayload = context.EndpointType switch
{
OpenIddictServerEndpointType.Verification => false,
OpenIddictServerEndpointType.EndUserVerification => false,
_ => !context.Options.DisableTokenStorage
},
@ -3956,7 +3957,8 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
if (context.EndpointType is not OpenIddictServerEndpointType.Verification || string.IsNullOrEmpty(context.DeviceCode))
if (context.EndpointType is not OpenIddictServerEndpointType.EndUserVerification ||
string.IsNullOrEmpty(context.DeviceCode))
{
return;
}
@ -4366,17 +4368,17 @@ public static partial class OpenIddictServerHandlers
context.Response.UserCode = context.UserCode;
}
if (context.EndpointType is OpenIddictServerEndpointType.Device)
if (context.EndpointType is OpenIddictServerEndpointType.DeviceAuthorization)
{
var uri = OpenIddictHelpers.CreateAbsoluteUri(
left : context.BaseUri ?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0127)),
right: context.Options.VerificationEndpointUris.First());
right: context.Options.EndUserVerificationEndpointUris.First());
context.Response.VerificationUri = uri.AbsoluteUri;
if (!string.IsNullOrEmpty(context.UserCode))
{
// Build the "verification_uri_complete" parameter using the verification endpoint URI
// Build the "verification_uri_complete" parameter using the end-user verification endpoint URI
// with the generated user code appended to the query string as a unique parameter.
context.Response.VerificationUriComplete = OpenIddictHelpers.AddQueryStringParameter(
uri, Parameters.UserCode, context.UserCode).AbsoluteUri;
@ -4469,7 +4471,7 @@ public static partial class OpenIddictServerHandlers
throw new ArgumentNullException(nameof(context));
}
if (context.EndpointType is not OpenIddictServerEndpointType.Logout)
if (context.EndpointType is not OpenIddictServerEndpointType.EndSession)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0024));
}

24
src/OpenIddict.Server/OpenIddictServerOptions.cs

@ -72,17 +72,14 @@ public sealed class OpenIddictServerOptions
];
/// <summary>
/// Gets the absolute and relative URIs associated to the cryptography endpoint.
/// Gets the absolute and relative URIs associated to the device authorization endpoint.
/// </summary>
public List<Uri> CryptographyEndpointUris { get; } =
[
new Uri(".well-known/jwks", UriKind.Relative)
];
public List<Uri> DeviceAuthorizationEndpointUris { get; } = [];
/// <summary>
/// Gets the absolute and relative URIs associated to the device endpoint.
/// Gets the absolute and relative URIs associated to the end session endpoint.
/// </summary>
public List<Uri> DeviceEndpointUris { get; } = [];
public List<Uri> EndSessionEndpointUris { get; } = [];
/// <summary>
/// Gets the absolute and relative URIs associated to the introspection endpoint.
@ -90,9 +87,12 @@ public sealed class OpenIddictServerOptions
public List<Uri> IntrospectionEndpointUris { get; } = [];
/// <summary>
/// Gets the absolute and relative URIs associated to the logout endpoint.
/// Gets the absolute and relative URIs associated to the JSON Web Key Set endpoint.
/// </summary>
public List<Uri> LogoutEndpointUris { get; } = [];
public List<Uri> JsonWebKeySetEndpointUris { get; } =
[
new Uri(".well-known/jwks", UriKind.Relative)
];
/// <summary>
/// Gets the absolute and relative URIs associated to the revocation endpoint.
@ -107,12 +107,12 @@ public sealed class OpenIddictServerOptions
/// <summary>
/// Gets the absolute and relative URIs associated to the userinfo endpoint.
/// </summary>
public List<Uri> UserinfoEndpointUris { get; } = [];
public List<Uri> UserInfoEndpointUris { get; } = [];
/// <summary>
/// Gets the absolute and relative URIs associated to the verification endpoint.
/// Gets the absolute and relative URIs associated to the end-user verification endpoint.
/// </summary>
public List<Uri> VerificationEndpointUris { get; } = [];
public List<Uri> EndUserVerificationEndpointUris { get; } = [];
/// <summary>
/// Gets or sets the JWT handler used to protect and unprotect tokens.

2
src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreConstants.cs

@ -14,7 +14,7 @@ public static class OpenIddictValidationAspNetCoreConstants
public static class Cache
{
public const string AuthorizationRequest = "openiddict-authorization-request:";
public const string LogoutRequest = "openiddict-logout-request:";
public const string EndSessionRequest = "openiddict-logout-request:";
}
public static class Properties

2
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinConstants.cs

@ -14,7 +14,7 @@ public static class OpenIddictValidationOwinConstants
public static class Cache
{
public const string AuthorizationRequest = "openiddict-authorization-request:";
public const string LogoutRequest = "openiddict-logout-request:";
public const string EndSessionRequest = "openiddict-logout-request:";
}
public static class Headers

28
src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.Discovery.cs

@ -38,24 +38,24 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
/*
* Cryptography request processing:
*/
CreateHttpClient<PrepareCryptographyRequestContext>.Descriptor,
PrepareGetHttpRequest<PrepareCryptographyRequestContext>.Descriptor,
AttachHttpVersion<PrepareCryptographyRequestContext>.Descriptor,
AttachJsonAcceptHeaders<PrepareCryptographyRequestContext>.Descriptor,
AttachUserAgentHeader<PrepareCryptographyRequestContext>.Descriptor,
AttachFromHeader<PrepareCryptographyRequestContext>.Descriptor,
AttachHttpParameters<PrepareCryptographyRequestContext>.Descriptor,
SendHttpRequest<ApplyCryptographyRequestContext>.Descriptor,
DisposeHttpRequest<ApplyCryptographyRequestContext>.Descriptor,
CreateHttpClient<PrepareJsonWebKeySetRequestContext>.Descriptor,
PrepareGetHttpRequest<PrepareJsonWebKeySetRequestContext>.Descriptor,
AttachHttpVersion<PrepareJsonWebKeySetRequestContext>.Descriptor,
AttachJsonAcceptHeaders<PrepareJsonWebKeySetRequestContext>.Descriptor,
AttachUserAgentHeader<PrepareJsonWebKeySetRequestContext>.Descriptor,
AttachFromHeader<PrepareJsonWebKeySetRequestContext>.Descriptor,
AttachHttpParameters<PrepareJsonWebKeySetRequestContext>.Descriptor,
SendHttpRequest<ApplyJsonWebKeySetRequestContext>.Descriptor,
DisposeHttpRequest<ApplyJsonWebKeySetRequestContext>.Descriptor,
/*
* Configuration response processing:
*/
DecompressResponseContent<ExtractCryptographyResponseContext>.Descriptor,
ExtractJsonHttpResponse<ExtractCryptographyResponseContext>.Descriptor,
ExtractWwwAuthenticateHeader<ExtractCryptographyResponseContext>.Descriptor,
ValidateHttpResponse<ExtractCryptographyResponseContext>.Descriptor,
DisposeHttpResponse<ExtractCryptographyResponseContext>.Descriptor
DecompressResponseContent<ExtractJsonWebKeySetResponseContext>.Descriptor,
ExtractJsonHttpResponse<ExtractJsonWebKeySetResponseContext>.Descriptor,
ExtractWwwAuthenticateHeader<ExtractJsonWebKeySetResponseContext>.Descriptor,
ValidateHttpResponse<ExtractJsonWebKeySetResponseContext>.Descriptor,
DisposeHttpResponse<ExtractJsonWebKeySetResponseContext>.Descriptor
]);
}
}

2
src/OpenIddict.Validation/OpenIddictValidationConfiguration.cs

@ -143,7 +143,7 @@ public sealed class OpenIddictValidationConfiguration : IPostConfigureOptions<Op
else
{
if (!options.Handlers.Exists(static descriptor => descriptor.ContextType == typeof(ApplyConfigurationRequestContext)) ||
!options.Handlers.Exists(static descriptor => descriptor.ContextType == typeof(ApplyCryptographyRequestContext)))
!options.Handlers.Exists(static descriptor => descriptor.ContextType == typeof(ApplyJsonWebKeySetRequestContext)))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0135));
}

36
src/OpenIddict.Validation/OpenIddictValidationEvents.Discovery.cs

@ -123,15 +123,15 @@ public static partial class OpenIddictValidationEvents
}
/// <summary>
/// Represents an event called for each request to the cryptography endpoint
/// to give the user code a chance to add parameters to the cryptography request.
/// Represents an event called for each request to the JSON Web Key Set endpoint
/// to give the user code a chance to add parameters to the JSON Web Key Set request.
/// </summary>
public sealed class PrepareCryptographyRequestContext : BaseExternalContext
public sealed class PrepareJsonWebKeySetRequestContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="PrepareCryptographyRequestContext"/> class.
/// Creates a new instance of the <see cref="PrepareJsonWebKeySetRequestContext"/> class.
/// </summary>
public PrepareCryptographyRequestContext(OpenIddictValidationTransaction transaction)
public PrepareJsonWebKeySetRequestContext(OpenIddictValidationTransaction transaction)
: base(transaction)
{
}
@ -147,15 +147,15 @@ public static partial class OpenIddictValidationEvents
}
/// <summary>
/// Represents an event called for each request to the cryptography endpoint
/// to send the cryptography request to the remote authorization server.
/// Represents an event called for each request to the JSON Web Key Set endpoint
/// to send the JSON Web Key Set request to the remote authorization server.
/// </summary>
public sealed class ApplyCryptographyRequestContext : BaseExternalContext
public sealed class ApplyJsonWebKeySetRequestContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="ApplyCryptographyRequestContext"/> class.
/// Creates a new instance of the <see cref="ApplyJsonWebKeySetRequestContext"/> class.
/// </summary>
public ApplyCryptographyRequestContext(OpenIddictValidationTransaction transaction)
public ApplyJsonWebKeySetRequestContext(OpenIddictValidationTransaction transaction)
: base(transaction)
{
}
@ -171,15 +171,15 @@ public static partial class OpenIddictValidationEvents
}
/// <summary>
/// Represents an event called for each cryptography response
/// Represents an event called for each JSON Web Key Set response
/// to extract the response parameters from the server response.
/// </summary>
public sealed class ExtractCryptographyResponseContext : BaseExternalContext
public sealed class ExtractJsonWebKeySetResponseContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="ExtractCryptographyResponseContext"/> class.
/// Creates a new instance of the <see cref="ExtractJsonWebKeySetResponseContext"/> class.
/// </summary>
public ExtractCryptographyResponseContext(OpenIddictValidationTransaction transaction)
public ExtractJsonWebKeySetResponseContext(OpenIddictValidationTransaction transaction)
: base(transaction)
{
}
@ -204,14 +204,14 @@ public static partial class OpenIddictValidationEvents
}
/// <summary>
/// Represents an event called for each cryptography response.
/// Represents an event called for each JSON Web Key Set response.
/// </summary>
public sealed class HandleCryptographyResponseContext : BaseExternalContext
public sealed class HandleJsonWebKeySetResponseContext : BaseExternalContext
{
/// <summary>
/// Creates a new instance of the <see cref="HandleCryptographyResponseContext"/> class.
/// Creates a new instance of the <see cref="HandleJsonWebKeySetResponseContext"/> class.
/// </summary>
public HandleCryptographyResponseContext(OpenIddictValidationTransaction transaction)
public HandleJsonWebKeySetResponseContext(OpenIddictValidationTransaction transaction)
: base(transaction)
{
}

28
src/OpenIddict.Validation/OpenIddictValidationHandlers.Discovery.cs

@ -211,7 +211,7 @@ public static partial class OpenIddictValidationHandlers
}
/// <summary>
/// Contains the logic responsible for extracting the JWKS endpoint URI from the discovery document.
/// Contains the logic responsible for extracting the JSON Web Key Set endpoint URI from the discovery document.
/// </summary>
public sealed class ExtractCryptographyEndpoint : IOpenIddictValidationHandler<HandleConfigurationResponseContext>
{
@ -349,22 +349,22 @@ public static partial class OpenIddictValidationHandlers
}
/// <summary>
/// Contains the logic responsible for validating the well-known parameters contained in the JWKS response.
/// Contains the logic responsible for validating the well-known parameters contained in the JSON Web Key Set response.
/// </summary>
public sealed class ValidateWellKnownCryptographyParameters : IOpenIddictValidationHandler<HandleCryptographyResponseContext>
public sealed class ValidateWellKnownCryptographyParameters : IOpenIddictValidationHandler<HandleJsonWebKeySetResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleCryptographyResponseContext>()
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleJsonWebKeySetResponseContext>()
.UseSingletonHandler<ValidateWellKnownCryptographyParameters>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleCryptographyResponseContext context)
public ValueTask HandleAsync(HandleJsonWebKeySetResponseContext context)
{
if (context is null)
{
@ -423,22 +423,22 @@ public static partial class OpenIddictValidationHandlers
}
/// <summary>
/// Contains the logic responsible for surfacing potential errors from the cryptography response.
/// Contains the logic responsible for surfacing potential errors from the JSON Web Key Set response.
/// </summary>
public sealed class HandleCryptographyErrorResponse : IOpenIddictValidationHandler<HandleCryptographyResponseContext>
public sealed class HandleCryptographyErrorResponse : IOpenIddictValidationHandler<HandleJsonWebKeySetResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleCryptographyResponseContext>()
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleJsonWebKeySetResponseContext>()
.UseSingletonHandler<HandleCryptographyErrorResponse>()
.SetOrder(ValidateWellKnownCryptographyParameters.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleCryptographyResponseContext context)
public ValueTask HandleAsync(HandleJsonWebKeySetResponseContext context)
{
if (context is null)
{
@ -466,22 +466,22 @@ public static partial class OpenIddictValidationHandlers
}
/// <summary>
/// Contains the logic responsible for extracting the signing keys from the JWKS document.
/// Contains the logic responsible for extracting the signing keys from the JSON Web Key Set document.
/// </summary>
public sealed class ExtractSigningKeys : IOpenIddictValidationHandler<HandleCryptographyResponseContext>
public sealed class ExtractSigningKeys : IOpenIddictValidationHandler<HandleJsonWebKeySetResponseContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleCryptographyResponseContext>()
= OpenIddictValidationHandlerDescriptor.CreateBuilder<HandleJsonWebKeySetResponseContext>()
.UseSingletonHandler<ExtractSigningKeys>()
.SetOrder(HandleCryptographyErrorResponse.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(HandleCryptographyResponseContext context)
public ValueTask HandleAsync(HandleJsonWebKeySetResponseContext context)
{
if (context is null)
{
@ -501,7 +501,7 @@ public static partial class OpenIddictValidationHandlers
for (var index = 0; index < keys.Count; index++)
{
// Note: the "use" parameter is defined as optional by the JWKS specification
// Note: the "use" parameter is defined as optional by the JSON Web Key Set specification
// but is required by the OpenID Connect discovery specification if both signing
// and encryption keys are present in the returned list. If the "use" parameter
// is not explicitly specified or has an empty value, assume it is a signing key.

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save