diff --git a/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx b/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx index f22b2404..24a39582 100644 --- a/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx +++ b/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx @@ -1776,10 +1776,6 @@ To register the OpenIddict core services, reference the 'OpenIddict.Core' packag The token shouldn't be null or empty at this point. {Locked} - - The OpenIddict Core services should be registered. - {Locked} - An error occurred while validating the token '{Token}'. {Locked} diff --git a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs index 98d78bfd..e9e03cdb 100644 --- a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs +++ b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.Session.cs @@ -244,13 +244,13 @@ namespace OpenIddict.Server.AspNetCore encryptingCredentials: context.Options.EncryptionCredentials.First(), additionalHeaderClaims: new Dictionary { - [JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.Private.AuthorizationRequest + [JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.Private.LogoutRequest }); // 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.AuthorizationEndpointCachingPolicy); + token, _options.CurrentValue.LogoutEndpointCachingPolicy); // Create a new GET logout request containing only the request_id parameter. var address = QueryHelpers.AddQueryString( diff --git a/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs b/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs index 1e057f49..79fca055 100644 --- a/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs +++ b/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs @@ -177,7 +177,7 @@ namespace OpenIddict.Server.DataProtection /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .AddFilter() .UseSingletonHandler() .SetOrder(GenerateIdentityModelAccessToken.Descriptor.Order - 500) @@ -240,7 +240,7 @@ namespace OpenIddict.Server.DataProtection /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .AddFilter() .UseSingletonHandler() .SetOrder(GenerateIdentityModelAuthorizationCode.Descriptor.Order - 500) @@ -303,7 +303,7 @@ namespace OpenIddict.Server.DataProtection /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .AddFilter() .UseSingletonHandler() .SetOrder(GenerateIdentityModelDeviceCode.Descriptor.Order - 500) @@ -366,7 +366,7 @@ namespace OpenIddict.Server.DataProtection /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .AddFilter() .UseSingletonHandler() .SetOrder(GenerateIdentityModelRefreshToken.Descriptor.Order - 500) @@ -429,7 +429,7 @@ namespace OpenIddict.Server.DataProtection /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .AddFilter() .UseSingletonHandler() .SetOrder(GenerateIdentityModelUserCode.Descriptor.Order - 500) diff --git a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs index ce199ebe..c60f799e 100644 --- a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs +++ b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.Session.cs @@ -244,7 +244,7 @@ namespace OpenIddict.Server.Owin // 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.AuthorizationEndpointCachingPolicy); + token, _options.CurrentValue.LogoutEndpointCachingPolicy); // Create a new GET logout request containing only the request_id parameter. var address = WebUtilities.AddQueryString( diff --git a/src/OpenIddict.Server/OpenIddictServerEvents.cs b/src/OpenIddict.Server/OpenIddictServerEvents.cs index fad33170..64f7d4f7 100644 --- a/src/OpenIddict.Server/OpenIddictServerEvents.cs +++ b/src/OpenIddict.Server/OpenIddictServerEvents.cs @@ -387,82 +387,172 @@ namespace OpenIddict.Server /// /// Gets or sets a boolean indicating whether an access token - /// should be returned to the client application. + /// should be generated (and optionally returned to the client). /// Note: overriding the value of this property is generally not /// recommended, except when dealing with non-standard clients. /// - public bool IncludeAccessToken { get; set; } + public bool GenerateAccessToken { get; set; } /// /// Gets or sets a boolean indicating whether an authorization code - /// should be returned to the client application. + /// should be generated (and optionally returned to the client). /// Note: overriding the value of this property is generally not /// recommended, except when dealing with non-standard clients. /// - public bool IncludeAuthorizationCode { get; set; } + public bool GenerateAuthorizationCode { get; set; } /// /// Gets or sets a boolean indicating whether a device code - /// should be returned to the client application. + /// should be generated (and optionally returned to the client). /// Note: overriding the value of this property is generally not /// recommended, except when dealing with non-standard clients. /// - public bool IncludeDeviceCode { get; set; } + public bool GenerateDeviceCode { get; set; } /// /// Gets or sets a boolean indicating whether an identity token - /// should be returned to the client application. + /// should be generated (and optionally returned to the client). /// Note: overriding the value of this property is generally not /// recommended, except when dealing with non-standard clients. /// - public bool IncludeIdentityToken { get; set; } + public bool GenerateIdentityToken { get; set; } /// /// Gets or sets a boolean indicating whether a refresh token - /// should be returned to the client application. + /// should be generated (and optionally returned to the client). /// Note: overriding the value of this property is generally not /// recommended, except when dealing with non-standard clients. /// - public bool IncludeRefreshToken { get; set; } + public bool GenerateRefreshToken { get; set; } /// /// Gets or sets a boolean indicating whether a user code - /// should be returned to the client application. + /// should be generated (and optionally returned to the client). + /// Note: overriding the value of this property is generally not + /// recommended, except when dealing with non-standard clients. + /// + public bool GenerateUserCode { get; set; } + + /// + /// Gets or sets a boolean indicating whether the generated access token + /// should be returned to the client application as part of the response. + /// Note: overriding the value of this property is generally not + /// recommended, except when dealing with non-standard clients. + /// + public bool IncludeAccessToken { get; set; } + + /// + /// Gets or sets a boolean indicating whether the generated authorization code + /// should be returned to the client application as part of the response. + /// Note: overriding the value of this property is generally not + /// recommended, except when dealing with non-standard clients. + /// + public bool IncludeAuthorizationCode { get; set; } + + /// + /// Gets or sets a boolean indicating whether the generated device code + /// should be returned to the client application as part of the response. + /// Note: overriding the value of this property is generally not + /// recommended, except when dealing with non-standard clients. + /// + public bool IncludeDeviceCode { get; set; } + + /// + /// Gets or sets a boolean indicating whether the generated identity token + /// should be returned to the client application as part of the response. + /// Note: overriding the value of this property is generally not + /// recommended, except when dealing with non-standard clients. + /// + public bool IncludeIdentityToken { get; set; } + + /// + /// Gets or sets a boolean indicating whether the generated refresh token + /// should be returned to the client application as part of the response. + /// Note: overriding the value of this property is generally not + /// recommended, except when dealing with non-standard clients. + /// + public bool IncludeRefreshToken { get; set; } + + /// + /// Gets or sets a boolean indicating whether the generated user code + /// should be returned to the client application as part of the response. /// Note: overriding the value of this property is generally not /// recommended, except when dealing with non-standard clients. /// public bool IncludeUserCode { get; set; } + /// + /// Gets or sets the generated access token, if applicable. + /// The access token will only be returned if + /// is set to true. + /// + public string? AccessToken { get; set; } + /// /// Gets or sets the principal containing the claims that /// will be used to create the access token, if applicable. /// public ClaimsPrincipal? AccessTokenPrincipal { get; set; } + /// + /// Gets or sets the generated authorization code, if applicable. + /// The authorization code will only be returned if + /// is set to true. + /// + public string? AuthorizationCode { get; set; } + /// /// Gets or sets the principal containing the claims that /// will be used to create the authorization code, if applicable. /// public ClaimsPrincipal? AuthorizationCodePrincipal { get; set; } + /// + /// Gets or sets the generated device code, if applicable. + /// The device code will only be returned if + /// is set to true. + /// + public string? DeviceCode { get; set; } + /// /// Gets or sets the principal containing the claims that /// will be used to create the device code, if applicable. /// public ClaimsPrincipal? DeviceCodePrincipal { get; set; } + /// + /// Gets or sets the generated identity token, if applicable. + /// The identity token will only be returned if + /// is set to true. + /// + public string? IdentityToken { get; set; } + /// /// Gets or sets the principal containing the claims that /// will be used to create the identity token, if applicable. /// public ClaimsPrincipal? IdentityTokenPrincipal { get; set; } + /// + /// Gets or sets the generated refresh token, if applicable. + /// The refresh token will only be returned if + /// is set to true. + /// + public string? RefreshToken { get; set; } + /// /// Gets or sets the principal containing the claims that /// will be used to create the refresh token, if applicable. /// public ClaimsPrincipal? RefreshTokenPrincipal { get; set; } + /// + /// Gets or sets the generated user code, if applicable. + /// The user code will only be returned if + /// is set to true. + /// + public string? UserCode { get; set; } + /// /// Gets or sets the principal containing the claims that /// will be used to create the user code, if applicable. diff --git a/src/OpenIddict.Server/OpenIddictServerExtensions.cs b/src/OpenIddict.Server/OpenIddictServerExtensions.cs index 6ae522c6..2c40955b 100644 --- a/src/OpenIddict.Server/OpenIddictServerExtensions.cs +++ b/src/OpenIddict.Server/OpenIddictServerExtensions.cs @@ -48,25 +48,25 @@ namespace Microsoft.Extensions.DependencyInjection builder.Services.TryAdd(DefaultHandlers.Select(descriptor => descriptor.ServiceDescriptor)); // Register the built-in filters used by the default OpenIddict server event handlers. - builder.Services.TryAddSingleton(); - builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); - builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); - builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); - builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); @@ -75,7 +75,7 @@ namespace Microsoft.Extensions.DependencyInjection builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); - builder.Services.TryAddSingleton(); + builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); builder.Services.TryAddSingleton(); diff --git a/src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs b/src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs index caffae2a..0600c68a 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs @@ -15,9 +15,9 @@ namespace OpenIddict.Server public static class OpenIddictServerHandlerFilters { /// - /// Represents a filter that excludes the associated handlers if no access token is returned. + /// Represents a filter that excludes the associated handlers if no access token is generated. /// - public class RequireAccessTokenIncluded : IOpenIddictServerHandlerFilter + public class RequireAccessTokenGenerated : IOpenIddictServerHandlerFilter { public ValueTask IsActiveAsync(ProcessSignInContext context) { @@ -26,14 +26,14 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - return new ValueTask(context.IncludeAccessToken); + return new ValueTask(context.GenerateAccessToken); } } /// - /// Represents a filter that excludes the associated handlers if no authorization code is returned. + /// Represents a filter that excludes the associated handlers if no authorization code is generated. /// - public class RequireAuthorizationCodeIncluded : IOpenIddictServerHandlerFilter + public class RequireAuthorizationCodeGenerated : IOpenIddictServerHandlerFilter { public ValueTask IsActiveAsync(ProcessSignInContext context) { @@ -42,7 +42,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - return new ValueTask(context.IncludeAuthorizationCode); + return new ValueTask(context.GenerateAuthorizationCode); } } @@ -143,9 +143,9 @@ namespace OpenIddict.Server } /// - /// Represents a filter that excludes the associated handlers if no device code is returned. + /// Represents a filter that excludes the associated handlers if no device code is generated. /// - public class RequireDeviceCodeIncluded : IOpenIddictServerHandlerFilter + public class RequireDeviceCodeGenerated : IOpenIddictServerHandlerFilter { public ValueTask IsActiveAsync(ProcessSignInContext context) { @@ -154,7 +154,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - return new ValueTask(context.IncludeDeviceCode); + return new ValueTask(context.GenerateDeviceCode); } } @@ -207,9 +207,9 @@ namespace OpenIddict.Server } /// - /// Represents a filter that excludes the associated handlers if no identity token is returned. + /// Represents a filter that excludes the associated handlers if no identity token is generated. /// - public class RequireIdentityTokenIncluded : IOpenIddictServerHandlerFilter + public class RequireIdentityTokenGenerated : IOpenIddictServerHandlerFilter { public ValueTask IsActiveAsync(ProcessSignInContext context) { @@ -218,7 +218,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - return new ValueTask(context.IncludeIdentityToken); + return new ValueTask(context.GenerateIdentityToken); } } @@ -303,9 +303,9 @@ namespace OpenIddict.Server } /// - /// Represents a filter that excludes the associated handlers if no refresh token is returned. + /// Represents a filter that excludes the associated handlers if no refresh token is generated. /// - public class RequireRefreshTokenIncluded : IOpenIddictServerHandlerFilter + public class RequireRefreshTokenGenerated : IOpenIddictServerHandlerFilter { public ValueTask IsActiveAsync(ProcessSignInContext context) { @@ -314,7 +314,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - return new ValueTask(context.IncludeRefreshToken); + return new ValueTask(context.GenerateRefreshToken); } } @@ -447,9 +447,9 @@ namespace OpenIddict.Server } /// - /// Represents a filter that excludes the associated handlers if no user code is returned. + /// Represents a filter that excludes the associated handlers if no user code is generated. /// - public class RequireUserCodeIncluded : IOpenIddictServerHandlerFilter + public class RequireUserCodeGenerated : IOpenIddictServerHandlerFilter { public ValueTask IsActiveAsync(ProcessSignInContext context) { @@ -458,7 +458,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - return new ValueTask(context.IncludeUserCode); + return new ValueTask(context.GenerateUserCode); } } diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs index 6b22bbc0..e0607006 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs @@ -1121,7 +1121,10 @@ namespace OpenIddict.Server // even if the service was registered and resolved from the dependency injection container. if (scopes.Count != 0 && !context.Options.EnableDegradedMode) { - Debug.Assert(_scopeManager is not null, SR.GetResourceString(SR.ID4011)); + if (_scopeManager is null) + { + throw new InvalidOperationException(SR.GetResourceString(SR.ID0016)); + } await foreach (var scope in _scopeManager.FindByNamesAsync(scopes.ToImmutableArray())) { diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs index a3cbb1da..3bd8e9c2 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs @@ -405,7 +405,10 @@ namespace OpenIddict.Server // even if the service was registered and resolved from the dependency injection container. if (scopes.Count != 0 && !context.Options.EnableDegradedMode) { - Debug.Assert(_scopeManager is not null, SR.GetResourceString(SR.ID4011)); + if (_scopeManager is null) + { + throw new InvalidOperationException(SR.GetResourceString(SR.ID0016)); + } await foreach (var scope in _scopeManager.FindByNamesAsync(scopes.ToImmutableArray())) { diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs index ee2a8160..757722f0 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs @@ -686,7 +686,10 @@ namespace OpenIddict.Server // even if the service was registered and resolved from the dependency injection container. if (scopes.Count != 0 && !context.Options.EnableDegradedMode) { - Debug.Assert(_scopeManager is not null, SR.GetResourceString(SR.ID4011)); + if (_scopeManager is null) + { + throw new InvalidOperationException(SR.GetResourceString(SR.ID0016)); + } await foreach (var scope in _scopeManager.FindByNamesAsync(scopes.ToImmutableArray())) { diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.cs index 253d384c..27efd548 100644 --- a/src/OpenIddict.Server/OpenIddictServerHandlers.cs +++ b/src/OpenIddict.Server/OpenIddictServerHandlers.cs @@ -63,7 +63,7 @@ namespace OpenIddict.Server AttachDefaultScopes.Descriptor, AttachDefaultPresenters.Descriptor, InferResources.Descriptor, - EvaluateReturnedTokens.Descriptor, + EvaluateTokenTypes.Descriptor, AttachAuthorization.Descriptor, PrepareAccessTokenPrincipal.Descriptor, @@ -104,8 +104,7 @@ namespace OpenIddict.Server GenerateIdentityModelIdentityToken.Descriptor, BeautifyUserCode.Descriptor, - AttachAccessTokenProperties.Descriptor, - AttachDeviceCodeProperties.Descriptor, + AttachTokenParameters.Descriptor, /* * Sign-out processing: @@ -1575,16 +1574,17 @@ namespace OpenIddict.Server } /// - /// Contains the logic responsible of selecting the token types returned to the client application. + /// Contains the logic responsible of selecting the token types that + /// should be generated and optionally returned in the response. /// - public class EvaluateReturnedTokens : IOpenIddictServerHandler + public class EvaluateTokenTypes : IOpenIddictServerHandler { /// /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .UseSingletonHandler() + .UseSingletonHandler() .SetOrder(InferResources.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) .Build(); @@ -1599,73 +1599,80 @@ namespace OpenIddict.Server Debug.Assert(context.Principal is not null, SR.GetResourceString(SR.ID4006)); - context.IncludeAccessToken = context.EndpointType switch + (context.GenerateAccessToken, context.IncludeAccessToken) = context.EndpointType switch { - // For authorization requests, return an access token if a response type containing token was specified. - OpenIddictServerEndpointType.Authorization => context.Request.HasResponseType(ResponseTypes.Token), + // For authorization requests, generate and return an access token + // if a response type containing the "token" value was specified. + OpenIddictServerEndpointType.Authorization when context.Request.HasResponseType(ResponseTypes.Token) + => (true, true), - // For token requests, always return an access token. - OpenIddictServerEndpointType.Token => true, + // For token requests, always generate and return an access token. + OpenIddictServerEndpointType.Token => (true, true), - _ => false + _ => (false, false) }; - context.IncludeAuthorizationCode = context.EndpointType switch + (context.GenerateAuthorizationCode, context.IncludeAuthorizationCode) = context.EndpointType switch { - // For authorization requests, return an authorization code if a response type containing code was specified. - OpenIddictServerEndpointType.Authorization => context.Request.HasResponseType(ResponseTypes.Code), + // For authorization requests, generate and return an authorization code + // if a response type containing the "code" value was specified. + OpenIddictServerEndpointType.Authorization when context.Request.HasResponseType(ResponseTypes.Code) + => (true, true), - _ => false + _ => (false, false) }; - context.IncludeDeviceCode = context.EndpointType switch + (context.GenerateDeviceCode, context.IncludeDeviceCode) = context.EndpointType switch { - // For device requests, always return a device code. - OpenIddictServerEndpointType.Device => true, + // For device requests, always generate and return a device code. + OpenIddictServerEndpointType.Device => (true, true), // Note: a device code is not directly returned by the 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 new device code is not returned as part of the response but persisted in the DB. - OpenIddictServerEndpointType.Verification => true, + // In this case, the device code is not returned as part of the response but persisted in the DB. + OpenIddictServerEndpointType.Verification => (true, false), - _ => false + _ => (false, false) }; - context.IncludeRefreshToken = context.EndpointType switch + (context.GenerateIdentityToken, context.IncludeIdentityToken) = context.EndpointType switch { - // For token requests, never return a refresh token if the offline_access scope was not granted. - OpenIddictServerEndpointType.Token when !context.Principal.HasScope(Scopes.OfflineAccess) => false, + // For authorization requests, generate and return an identity token if a response type + // containing code was specified and if the openid scope was explicitly or implicitly granted. + OpenIddictServerEndpointType.Authorization when + context.Principal.HasScope(Scopes.OpenId) && + context.Request.HasResponseType(ResponseTypes.IdToken) => (true, true), - // For grant_type=refresh_token token requests, only return a refresh token if rolling tokens are enabled. - OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType() - => context.Options.UseRollingRefreshTokens, - - // For token requests that don't meet the previous criteria, allow a refresh token to be returned. - OpenIddictServerEndpointType.Token => true, + // For token requests, only generate and return an identity token if the openid scope was granted. + OpenIddictServerEndpointType.Token when context.Principal.HasScope(Scopes.OpenId) => (true, true), - _ => false + _ => (false, false) }; - context.IncludeIdentityToken = context.EndpointType switch + (context.GenerateRefreshToken, context.IncludeRefreshToken) = context.EndpointType switch { - // For authorization requests, return an identity token if a response type containing code - // was specified and if the openid scope was explicitly or implicitly granted. - OpenIddictServerEndpointType.Authorization => context.Principal.HasScope(Scopes.OpenId) && - context.Request.HasResponseType(ResponseTypes.IdToken), + // For token requests, never generate a refresh token if the offline_access scope was not granted. + OpenIddictServerEndpointType.Token when !context.Principal.HasScope(Scopes.OfflineAccess) + => (false, false), - // For token requests, only return an identity token if the openid scope was granted. - OpenIddictServerEndpointType.Token => context.Principal.HasScope(Scopes.OpenId), + // For grant_type=refresh_token token requests, only generate + // and return a refresh token if rolling tokens are enabled. + OpenIddictServerEndpointType.Token when context.Request.IsRefreshTokenGrantType() && + context.Options.UseRollingRefreshTokens => (true, true), - _ => false + // For token requests that don't meet the previous criteria, allow a refresh token to be returned. + OpenIddictServerEndpointType.Token when !context.Request.IsRefreshTokenGrantType() => (true, true), + + _ => (false, false) }; - context.IncludeUserCode = context.EndpointType switch + (context.GenerateUserCode, context.IncludeUserCode) = context.EndpointType switch { - // Only return a user code if the request is a device authorization request. - OpenIddictServerEndpointType.Device => true, + // Only generate and return a user code if the request is a device authorization request. + OpenIddictServerEndpointType.Device => (true, true), - _ => false + _ => (false, false) }; return default; @@ -1699,7 +1706,7 @@ namespace OpenIddict.Server .AddFilter() .AddFilter() .UseScopedHandler() - .SetOrder(EvaluateReturnedTokens.Descriptor.Order + 1_000) + .SetOrder(EvaluateTokenTypes.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) .Build(); @@ -1714,7 +1721,7 @@ namespace OpenIddict.Server Debug.Assert(context.Principal is not null, SR.GetResourceString(SR.ID4006)); // If no authorization code, device code or refresh token is returned, don't create an authorization. - if (!context.IncludeAuthorizationCode && !context.IncludeDeviceCode && !context.IncludeRefreshToken) + if (!context.GenerateAuthorizationCode && !context.GenerateDeviceCode && !context.GenerateRefreshToken) { return; } @@ -1783,7 +1790,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(AttachAuthorization.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -1902,7 +1909,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(PrepareAccessTokenPrincipal.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -2006,7 +2013,7 @@ namespace OpenIddict.Server // Note: a device code principal is produced when a device code is included in the response or when a // device code entry is replaced when processing a sign-in response sent to the verification endpoint. - if (context.EndpointType != OpenIddictServerEndpointType.Verification && !context.IncludeDeviceCode) + if (context.EndpointType != OpenIddictServerEndpointType.Verification && !context.GenerateDeviceCode) { return default; } @@ -2069,7 +2076,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(PrepareDeviceCodePrincipal.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -2153,7 +2160,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(PrepareRefreshTokenPrincipal.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -2267,7 +2274,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(PrepareIdentityTokenPrincipal.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -2582,7 +2589,7 @@ namespace OpenIddict.Server = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .AddFilter() - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(ExtendRefreshTokenEntry.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -2650,7 +2657,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(CreateAccessTokenEntry.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -2665,7 +2672,7 @@ namespace OpenIddict.Server } // If an access token was already attached by another handler, don't overwrite it. - if (!string.IsNullOrEmpty(context.Response.AccessToken)) + if (!string.IsNullOrEmpty(context.AccessToken)) { return default; } @@ -2739,9 +2746,10 @@ namespace OpenIddict.Server additionalHeaderClaims: descriptor.AdditionalHeaderClaims); } - context.Response.AccessToken = token; + context.AccessToken = token; - context.Logger.LogTrace(SR.GetResourceString(SR.ID6013), principal.GetClaim(Claims.JwtId), token, principal.Claims); + context.Logger.LogTrace(SR.GetResourceString(SR.ID6013), principal.GetClaim(Claims.JwtId), + context.AccessToken, principal.Claims); return default; } @@ -2768,7 +2776,7 @@ namespace OpenIddict.Server .AddFilter() .AddFilter() .AddFilter() - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(GenerateIdentityModelAccessToken.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -2782,7 +2790,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - if (string.IsNullOrEmpty(context.Response.AccessToken)) + if (string.IsNullOrEmpty(context.AccessToken)) { return; } @@ -2818,13 +2826,13 @@ namespace OpenIddict.Server // Attach the generated token to the token entry, persist the change // and replace the returned token by the reference identifier. - descriptor.Payload = context.Response.AccessToken; + descriptor.Payload = context.AccessToken; descriptor.Principal = principal; descriptor.ReferenceId = Base64UrlEncoder.Encode(data); await _tokenManager.UpdateAsync(token, descriptor); - context.Response.AccessToken = descriptor.ReferenceId; + context.AccessToken = descriptor.ReferenceId; context.Logger.LogTrace(SR.GetResourceString(SR.ID6014), identifier, descriptor.ReferenceId); } @@ -2856,7 +2864,7 @@ namespace OpenIddict.Server = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .AddFilter() - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(ConvertReferenceAccessToken.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -2924,7 +2932,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(CreateAuthorizationCodeEntry.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -2939,7 +2947,7 @@ namespace OpenIddict.Server } // If an authorization code was already attached by another handler, don't overwrite it. - if (!string.IsNullOrEmpty(context.Response.Code)) + if (!string.IsNullOrEmpty(context.AuthorizationCode)) { return default; } @@ -2994,9 +3002,10 @@ namespace OpenIddict.Server encryptingCredentials: context.Options.EncryptionCredentials.First(), additionalHeaderClaims: descriptor.AdditionalHeaderClaims); - context.Response.Code = token; + context.AuthorizationCode = token; - context.Logger.LogTrace(SR.GetResourceString(SR.ID6016), principal.GetClaim(Claims.JwtId), token, principal.Claims); + context.Logger.LogTrace(SR.GetResourceString(SR.ID6016), principal.GetClaim(Claims.JwtId), + context.AuthorizationCode, principal.Claims); return default; } @@ -3022,7 +3031,7 @@ namespace OpenIddict.Server = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .AddFilter() - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(GenerateIdentityModelAuthorizationCode.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3036,7 +3045,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - if (string.IsNullOrEmpty(context.Response.Code)) + if (string.IsNullOrEmpty(context.AuthorizationCode)) { return; } @@ -3072,13 +3081,13 @@ namespace OpenIddict.Server // Attach the generated token to the token entry, persist the change // and replace the returned token by the reference identifier. - descriptor.Payload = context.Response.Code; + descriptor.Payload = context.AuthorizationCode; descriptor.Principal = principal; descriptor.ReferenceId = Base64UrlEncoder.Encode(data); await _tokenManager.UpdateAsync(token, descriptor); - context.Response.Code = descriptor.ReferenceId; + context.AuthorizationCode = descriptor.ReferenceId; context.Logger.LogTrace(SR.GetResourceString(SR.ID6017), identifier, descriptor.ReferenceId); } @@ -3110,7 +3119,7 @@ namespace OpenIddict.Server = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .AddFilter() - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(ConvertReferenceAuthorizationCode.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3183,7 +3192,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(CreateDeviceCodeEntry.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3198,7 +3207,7 @@ namespace OpenIddict.Server } // If a device code was already attached by another handler, don't overwrite it. - if (!string.IsNullOrEmpty(context.Response.DeviceCode)) + if (!string.IsNullOrEmpty(context.DeviceCode)) { return default; } @@ -3253,9 +3262,10 @@ namespace OpenIddict.Server encryptingCredentials: context.Options.EncryptionCredentials.First(), additionalHeaderClaims: descriptor.AdditionalHeaderClaims); - context.Response.DeviceCode = token; + context.DeviceCode = token; - context.Logger.LogTrace(SR.GetResourceString(SR.ID6019), principal.GetClaim(Claims.JwtId), token, principal.Claims); + context.Logger.LogTrace(SR.GetResourceString(SR.ID6019), principal.GetClaim(Claims.JwtId), + context.DeviceCode, principal.Claims); return default; } @@ -3282,7 +3292,7 @@ namespace OpenIddict.Server .AddFilter() .AddFilter() // Note: device codes are always reference tokens. - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(GenerateIdentityModelDeviceCode.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3296,7 +3306,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - if (string.IsNullOrEmpty(context.Response.DeviceCode)) + if (string.IsNullOrEmpty(context.DeviceCode)) { return; } @@ -3337,13 +3347,13 @@ namespace OpenIddict.Server // Attach the generated token to the token entry, persist the change // and replace the returned token by the reference identifier. - descriptor.Payload = context.Response.DeviceCode; + descriptor.Payload = context.DeviceCode; descriptor.Principal = principal; descriptor.ReferenceId = Base64UrlEncoder.Encode(data); await _tokenManager.UpdateAsync(token, descriptor); - context.Response.DeviceCode = descriptor.ReferenceId; + context.DeviceCode = descriptor.ReferenceId; context.Logger.LogTrace(SR.GetResourceString(SR.ID6020), identifier, descriptor.ReferenceId); } @@ -3369,7 +3379,7 @@ namespace OpenIddict.Server = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .AddFilter() - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(ConvertReferenceDeviceCode.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3383,7 +3393,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - if (string.IsNullOrEmpty(context.Response.DeviceCode)) + if (string.IsNullOrEmpty(context.DeviceCode)) { return; } @@ -3421,16 +3431,13 @@ namespace OpenIddict.Server // Note: the lifetime is deliberately extended to give more time to the client to redeem the code. descriptor.ExpirationDate = principal.GetExpirationDate(); - descriptor.Payload = context.Response.DeviceCode; + descriptor.Payload = context.DeviceCode; descriptor.Principal = principal; descriptor.Status = Statuses.Valid; descriptor.Subject = principal.GetClaim(Claims.Subject); await _tokenManager.UpdateAsync(token, descriptor); - // Don't return the prepared device code directly from the verification endpoint. - context.Response.DeviceCode = null; - context.Logger.LogTrace(SR.GetResourceString(SR.ID6021), await _tokenManager.GetIdAsync(token)); } } @@ -3461,7 +3468,7 @@ namespace OpenIddict.Server = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .AddFilter() - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(UpdateReferenceDeviceCodeEntry.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3529,7 +3536,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(CreateRefreshTokenEntry.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3544,7 +3551,7 @@ namespace OpenIddict.Server } // If a refresh token was already attached by another handler, don't overwrite it. - if (!string.IsNullOrEmpty(context.Response.RefreshToken)) + if (!string.IsNullOrEmpty(context.RefreshToken)) { return default; } @@ -3594,14 +3601,14 @@ namespace OpenIddict.Server // Sign and encrypt the refresh token. var token = context.Options.JsonWebTokenHandler.CreateToken(descriptor); - token = context.Options.JsonWebTokenHandler.EncryptToken(token, encryptingCredentials: context.Options.EncryptionCredentials.First(), additionalHeaderClaims: descriptor.AdditionalHeaderClaims); - context.Response.RefreshToken = token; + context.RefreshToken = token; - context.Logger.LogTrace(SR.GetResourceString(SR.ID6023), principal.GetClaim(Claims.JwtId), token, principal.Claims); + context.Logger.LogTrace(SR.GetResourceString(SR.ID6023), principal.GetClaim(Claims.JwtId), + context.RefreshToken, principal.Claims); return default; } @@ -3628,7 +3635,7 @@ namespace OpenIddict.Server .AddFilter() .AddFilter() .AddFilter() - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(GenerateIdentityModelRefreshToken.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3642,7 +3649,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - if (string.IsNullOrEmpty(context.Response.RefreshToken)) + if (string.IsNullOrEmpty(context.RefreshToken)) { return; } @@ -3678,13 +3685,13 @@ namespace OpenIddict.Server // Attach the generated token to the token entry, persist the change // and replace the returned token by the reference identifier. - descriptor.Payload = context.Response.RefreshToken; + descriptor.Payload = context.RefreshToken; descriptor.Principal = principal; descriptor.ReferenceId = Base64UrlEncoder.Encode(data); await _tokenManager.UpdateAsync(token, descriptor); - context.Response.RefreshToken = descriptor.ReferenceId; + context.RefreshToken = descriptor.ReferenceId; context.Logger.LogTrace(SR.GetResourceString(SR.ID6024), identifier, descriptor.ReferenceId); } @@ -3700,8 +3707,8 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() - .AddFilter() + .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(ConvertReferenceRefreshToken.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3757,7 +3764,7 @@ namespace OpenIddict.Server = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .AddFilter() - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(AttachDeviceCodeIdentifier.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3825,7 +3832,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(CreateUserCodeEntry.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3840,7 +3847,7 @@ namespace OpenIddict.Server } // If a user code was already attached by another handler, don't overwrite it. - if (!string.IsNullOrEmpty(context.Response.UserCode)) + if (!string.IsNullOrEmpty(context.UserCode)) { return default; } @@ -3885,9 +3892,10 @@ namespace OpenIddict.Server encryptingCredentials: context.Options.EncryptionCredentials.First(), additionalHeaderClaims: descriptor.AdditionalHeaderClaims); - context.Response.UserCode = token; + context.UserCode = token; - context.Logger.LogTrace(SR.GetResourceString(SR.ID6026), principal.GetClaim(Claims.JwtId), token, principal.Claims); + context.Logger.LogTrace(SR.GetResourceString(SR.ID6026), principal.GetClaim(Claims.JwtId), + context.UserCode, principal.Claims); return default; } @@ -3914,7 +3922,7 @@ namespace OpenIddict.Server .AddFilter() .AddFilter() // Note: user codes are always reference tokens. - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(GenerateIdentityModelUserCode.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -3928,7 +3936,7 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - if (string.IsNullOrEmpty(context.Response.UserCode)) + if (string.IsNullOrEmpty(context.UserCode)) { return; } @@ -3962,13 +3970,13 @@ namespace OpenIddict.Server // Attach the generated token to the token entry, persist the change // and replace the returned token by the reference identifier. - descriptor.Payload = context.Response.UserCode; + descriptor.Payload = context.UserCode; descriptor.Principal = principal; descriptor.ReferenceId = await GenerateReferenceIdentifierAsync(_tokenManager); await _tokenManager.UpdateAsync(token, descriptor); - context.Response.UserCode = descriptor.ReferenceId; + context.UserCode = descriptor.ReferenceId; context.Logger.LogTrace(SR.GetResourceString(SR.ID6027), identifier, descriptor.ReferenceId); @@ -4015,7 +4023,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(ConvertReferenceUserCode.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -4035,8 +4043,7 @@ namespace OpenIddict.Server throw new InvalidOperationException(SR.GetResourceString(SR.ID0022)); } - if (string.IsNullOrEmpty(context.Response.AccessToken) && - string.IsNullOrEmpty(context.Response.Code)) + if (string.IsNullOrEmpty(context.AccessToken) && string.IsNullOrEmpty(context.AuthorizationCode)) { return default; } @@ -4054,18 +4061,18 @@ namespace OpenIddict.Server throw new InvalidOperationException(SR.GetResourceString(SR.ID0267)); } - if (!string.IsNullOrEmpty(context.Response.AccessToken)) + if (!string.IsNullOrEmpty(context.AccessToken)) { - var digest = hash.ComputeHash(Encoding.ASCII.GetBytes(context.Response.AccessToken)); + var digest = hash.ComputeHash(Encoding.ASCII.GetBytes(context.AccessToken)); // Note: only the left-most half of the hash is used. // See http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken principal.SetClaim(Claims.AccessTokenHash, Base64UrlEncoder.Encode(digest, 0, digest.Length / 2)); } - if (!string.IsNullOrEmpty(context.Response.Code)) + if (!string.IsNullOrEmpty(context.AuthorizationCode)) { - var digest = hash.ComputeHash(Encoding.ASCII.GetBytes(context.Response.Code)); + var digest = hash.ComputeHash(Encoding.ASCII.GetBytes(context.AuthorizationCode)); // Note: only the left-most half of the hash is used. // See http://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken @@ -4163,7 +4170,7 @@ namespace OpenIddict.Server = OpenIddictServerHandlerDescriptor.CreateBuilder() .AddFilter() .AddFilter() - .AddFilter() + .AddFilter() .UseScopedHandler() .SetOrder(AttachTokenDigests.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -4231,7 +4238,7 @@ namespace OpenIddict.Server /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(CreateIdentityTokenEntry.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -4246,7 +4253,7 @@ namespace OpenIddict.Server } // If an identity token was already attached by another handler, don't overwrite it. - if (!string.IsNullOrEmpty(context.Response.IdToken)) + if (!string.IsNullOrEmpty(context.IdentityToken)) { return default; } @@ -4306,9 +4313,10 @@ namespace OpenIddict.Server // Sign and attach the identity token. var token = context.Options.JsonWebTokenHandler.CreateToken(descriptor); - context.Response.IdToken = token; + context.IdentityToken = token; - context.Logger.LogTrace(SR.GetResourceString(SR.ID6029), principal.GetClaim(Claims.JwtId), token, principal.Claims); + context.Logger.LogTrace(SR.GetResourceString(SR.ID6029), principal.GetClaim(Claims.JwtId), + context.IdentityToken, principal.Claims); return default; } @@ -4329,7 +4337,7 @@ namespace OpenIddict.Server // but the default CreateReferenceUserCodeEntry that creates the user code // reference identifiers only works when the degraded mode is disabled. .AddFilter() - .AddFilter() + .AddFilter() .UseSingletonHandler() .SetOrder(GenerateIdentityModelIdentityToken.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) @@ -4347,7 +4355,7 @@ namespace OpenIddict.Server // appended before each new block of 4 integers. These dashes are expected to be // stripped from the user codes when receiving them at the verification endpoint. - var builder = new StringBuilder(context.Response.UserCode); + var builder = new StringBuilder(context.UserCode); if (builder.Length % 4 != 0) { return default; @@ -4361,24 +4369,23 @@ namespace OpenIddict.Server } } - context.Response.UserCode = builder.ToString(); + context.UserCode = builder.ToString(); return default; } } /// - /// Contains the logic responsible of attaching additional access token properties to the sign-in response. + /// Contains the logic responsible of attaching the tokens and their metadata to the sign-in response. /// - public class AttachAccessTokenProperties : IOpenIddictServerHandler + public class AttachTokenParameters : IOpenIddictServerHandler { /// /// Gets the default descriptor definition assigned to this handler. /// public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() - .UseSingletonHandler() + .UseSingletonHandler() .SetOrder(BeautifyUserCode.Descriptor.Order + 1_000) .SetType(OpenIddictServerHandlerType.BuiltIn) .Build(); @@ -4391,73 +4398,78 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(context)); } - Debug.Assert(context.AccessTokenPrincipal is not null, SR.GetResourceString(SR.ID4006)); + if (context.IncludeAccessToken) + { + context.Response.AccessToken = context.AccessToken; + context.Response.TokenType = TokenTypes.Bearer; - context.Response.TokenType = TokenTypes.Bearer; + // If the principal is available, attach additional metadata. + if (context.AccessTokenPrincipal is not null) + { + // If an expiration date was set on the access token principal, return it to the client application. + var date = context.AccessTokenPrincipal.GetExpirationDate(); + if (date.HasValue && date.Value > DateTimeOffset.UtcNow) + { + context.Response.ExpiresIn = (long) ((date.Value - DateTimeOffset.UtcNow).TotalSeconds + .5); + } - // If an expiration date was set on the access token principal, return it to the client application. - var date = context.AccessTokenPrincipal.GetExpirationDate(); - if (date.HasValue && date.Value > DateTimeOffset.UtcNow) - { - context.Response.ExpiresIn = (long) ((date.Value - DateTimeOffset.UtcNow).TotalSeconds + .5); + // If the granted access token scopes differ from the requested scopes, return the granted scopes + // list as a parameter to inform the client application of the fact the scopes set will be reduced. + var scopes = new HashSet(context.AccessTokenPrincipal.GetScopes(), StringComparer.Ordinal); + if ((context.EndpointType == OpenIddictServerEndpointType.Token && context.Request.IsAuthorizationCodeGrantType()) || + !scopes.SetEquals(context.Request.GetScopes())) + { + context.Response.Scope = string.Join(" ", scopes); + } + } } - // If the granted access token scopes differ from the requested scopes, return the granted scopes - // list as a parameter to inform the client application of the fact the scopes set will be reduced. - var scopes = new HashSet(context.AccessTokenPrincipal.GetScopes(), StringComparer.Ordinal); - if ((context.EndpointType == OpenIddictServerEndpointType.Token && context.Request.IsAuthorizationCodeGrantType()) || - !scopes.SetEquals(context.Request.GetScopes())) + if (context.IncludeAuthorizationCode) { - context.Response.Scope = string.Join(" ", scopes); + context.Response.Code = context.AuthorizationCode; } - return default; - } - } + if (context.IncludeDeviceCode) + { + context.Response.DeviceCode = context.DeviceCode; - /// - /// Contains the logic responsible of attaching additional device code properties to the sign-in response. - /// - public class AttachDeviceCodeProperties : IOpenIddictServerHandler - { - /// - /// Gets the default descriptor definition assigned to this handler. - /// - public static OpenIddictServerHandlerDescriptor Descriptor { get; } - = OpenIddictServerHandlerDescriptor.CreateBuilder() - .AddFilter() - .UseSingletonHandler() - .SetOrder(AttachAccessTokenProperties.Descriptor.Order + 1_000) - .SetType(OpenIddictServerHandlerType.BuiltIn) - .Build(); + // If the principal is available, attach additional metadata. + if (context.DeviceCodePrincipal is not null) + { + // If an expiration date was set on the device code principal, return it to the client application. + var date = context.DeviceCodePrincipal.GetExpirationDate(); + if (date.HasValue && date.Value > DateTimeOffset.UtcNow) + { + context.Response.ExpiresIn = (long) ((date.Value - DateTimeOffset.UtcNow).TotalSeconds + .5); + } + } + } - /// - public ValueTask HandleAsync(ProcessSignInContext context) - { - if (context is null) + if (context.IncludeIdentityToken) { - throw new ArgumentNullException(nameof(context)); + context.Response.IdToken = context.IdentityToken; } - Debug.Assert(context.DeviceCodePrincipal is not null, SR.GetResourceString(SR.ID4006)); - - var address = GetEndpointAbsoluteUri(context.Issuer, context.Options.VerificationEndpointUris.FirstOrDefault()); - if (address is not null) + if (context.IncludeRefreshToken) { - var builder = new UriBuilder(address) - { - Query = string.Concat(Parameters.UserCode, "=", context.Response.UserCode) - }; - - context.Response[Parameters.VerificationUri] = address.AbsoluteUri; - context.Response[Parameters.VerificationUriComplete] = builder.Uri.AbsoluteUri; + context.Response.RefreshToken = context.RefreshToken; } - // If an expiration date was set on the device code principal, return it to the client application. - var date = context.DeviceCodePrincipal.GetExpirationDate(); - if (date.HasValue && date.Value > DateTimeOffset.UtcNow) + if (context.IncludeUserCode) { - context.Response.ExpiresIn = (long) ((date.Value - DateTimeOffset.UtcNow).TotalSeconds + .5); + context.Response.UserCode = context.UserCode; + + var address = GetEndpointAbsoluteUri(context.Issuer, context.Options.VerificationEndpointUris.FirstOrDefault()); + if (address is not null) + { + var builder = new UriBuilder(address) + { + Query = string.Concat(Parameters.UserCode, "=", context.UserCode) + }; + + context.Response[Parameters.VerificationUri] = address.AbsoluteUri; + context.Response[Parameters.VerificationUriComplete] = builder.Uri.AbsoluteUri; + } } return default; diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs index e029ce66..57d6f38c 100644 --- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs +++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs @@ -1608,15 +1608,15 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { - context.IncludeAccessToken = false; - context.IncludeAuthorizationCode = true; - context.IncludeIdentityToken = true; - context.IncludeRefreshToken = true; + context.GenerateAccessToken = context.IncludeAccessToken = false; + context.GenerateAuthorizationCode = context.IncludeAuthorizationCode = true; + context.GenerateIdentityToken = context.IncludeIdentityToken = true; + context.GenerateRefreshToken = context.IncludeRefreshToken = true; return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -1662,12 +1662,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateAuthorizationCode); Assert.True(context.IncludeAuthorizationCode); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -1801,12 +1802,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateAccessToken); Assert.True(context.IncludeAccessToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -1856,12 +1858,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateAccessToken); Assert.True(context.IncludeAccessToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -1908,12 +1911,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateAccessToken); Assert.True(context.IncludeAccessToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -1951,12 +1955,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateAccessToken); Assert.True(context.IncludeAccessToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -1995,12 +2000,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateAccessToken); Assert.True(context.IncludeAccessToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -2040,12 +2046,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateAccessToken); Assert.True(context.IncludeAccessToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -2114,12 +2121,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.False(context.GenerateRefreshToken); Assert.False(context.IncludeRefreshToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -2168,12 +2176,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateRefreshToken); Assert.True(context.IncludeRefreshToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -2221,12 +2230,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateRefreshToken); Assert.True(context.IncludeRefreshToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -2255,12 +2265,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateRefreshToken); Assert.True(context.IncludeRefreshToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); options.AddEventHandler(builder => @@ -2300,12 +2311,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateRefreshToken); Assert.True(context.IncludeRefreshToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); options.AddEventHandler(builder => @@ -2346,12 +2358,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateRefreshToken); Assert.True(context.IncludeRefreshToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); options.AddEventHandler(builder => @@ -2398,12 +2411,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.False(context.GenerateIdentityToken); Assert.False(context.IncludeIdentityToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -2446,12 +2460,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateIdentityToken); Assert.True(context.IncludeIdentityToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -2502,12 +2517,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateIdentityToken); Assert.True(context.IncludeIdentityToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -2555,12 +2571,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateIdentityToken); Assert.True(context.IncludeIdentityToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -2589,12 +2606,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateIdentityToken); Assert.True(context.IncludeIdentityToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); options.AddEventHandler(builder => @@ -2643,12 +2661,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateIdentityToken); Assert.True(context.IncludeIdentityToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); }); @@ -2689,12 +2708,13 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { + Assert.True(context.GenerateIdentityToken); Assert.True(context.IncludeIdentityToken); return default; }); - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); + builder.SetOrder(EvaluateTokenTypes.Descriptor.Order + 500); }); });