Browse Source

Make authorization codes reference tokens by default, split UseReferenceTokens into two settings and allow the Data Protection to fall back to JWT for specific token types

pull/996/head
Kévin Chalet 6 years ago
committed by GitHub
parent
commit
beb6b3e92b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 34
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionBuilder.cs
  2. 6
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionExtensions.cs
  3. 97
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlerFilters.cs
  4. 16
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs
  5. 30
      src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionOptions.cs
  6. 21
      src/OpenIddict.Server/OpenIddictServerBuilder.cs
  7. 4
      src/OpenIddict.Server/OpenIddictServerConfiguration.cs
  8. 5
      src/OpenIddict.Server/OpenIddictServerExtensions.cs
  9. 30
      src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs
  10. 12
      src/OpenIddict.Server/OpenIddictServerHandlers.cs
  11. 21
      src/OpenIddict.Server/OpenIddictServerOptions.cs
  12. 4
      src/OpenIddict.Validation.ServerIntegration/OpenIddictValidationServerIntegrationConfiguration.cs
  13. 9
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Introspection.cs
  14. 18
      test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs
  15. 124
      test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs

34
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionBuilder.cs

@ -81,11 +81,39 @@ namespace Microsoft.Extensions.DependencyInjection
}
/// <summary>
/// Configures OpenIddict to use the default token format (JWT) when issuing new tokens.
/// Configures OpenIddict to use the default token format (JWT) when issuing new access tokens.
/// </summary>
/// <returns>The <see cref="OpenIddictServerDataProtectionBuilder"/>.</returns>
public OpenIddictServerDataProtectionBuilder PreferDefaultTokenFormat()
=> Configure(options => options.PreferDefaultTokenFormat = true);
public OpenIddictServerDataProtectionBuilder PreferDefaultAccessTokenFormat()
=> Configure(options => options.PreferDefaultAccessTokenFormat = true);
/// <summary>
/// Configures OpenIddict to use the default token format (JWT) when issuing new authorization codes.
/// </summary>
/// <returns>The <see cref="OpenIddictServerDataProtectionBuilder"/>.</returns>
public OpenIddictServerDataProtectionBuilder PreferDefaultAuthorizationCodeFormat()
=> Configure(options => options.PreferDefaultAuthorizationCodeFormat = true);
/// <summary>
/// Configures OpenIddict to use the default token format (JWT) when issuing new device codes.
/// </summary>
/// <returns>The <see cref="OpenIddictServerDataProtectionBuilder"/>.</returns>
public OpenIddictServerDataProtectionBuilder PreferDefaultDeviceCodeFormat()
=> Configure(options => options.PreferDefaultDeviceCodeFormat = true);
/// <summary>
/// Configures OpenIddict to use the default token format (JWT) when issuing new refresh tokens.
/// </summary>
/// <returns>The <see cref="OpenIddictServerDataProtectionBuilder"/>.</returns>
public OpenIddictServerDataProtectionBuilder PreferDefaultRefreshTokenFormat()
=> Configure(options => options.PreferDefaultRefreshTokenFormat = true);
/// <summary>
/// Configures OpenIddict to use the default token format (JWT) when issuing new user codes.
/// </summary>
/// <returns>The <see cref="OpenIddictServerDataProtectionBuilder"/>.</returns>
public OpenIddictServerDataProtectionBuilder PreferDefaultUserCodeFormat()
=> Configure(options => options.PreferDefaultUserCodeFormat = true);
/// <summary>
/// Determines whether the specified object is equal to the current object.

6
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionExtensions.cs

@ -42,7 +42,11 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Services.TryAdd(DefaultHandlers.Select(descriptor => descriptor.ServiceDescriptor));
// Register the built-in filter used by the default OpenIddict Data Protection event handlers.
builder.Services.TryAddSingleton<RequireDataProtectionFormatEnabled>();
builder.Services.TryAddSingleton<RequireDataProtectionAccessTokenFormatEnabled>();
builder.Services.TryAddSingleton<RequireDataProtectionAuthorizationCodeFormatEnabled>();
builder.Services.TryAddSingleton<RequireDataProtectionDeviceCodeFormatEnabled>();
builder.Services.TryAddSingleton<RequireDataProtectionRefreshTokenFormatEnabled>();
builder.Services.TryAddSingleton<RequireDataProtectionUserCodeFormatEnabled>();
// Note: TryAddEnumerable() is used here to ensure the initializers are registered only once.
builder.Services.TryAddEnumerable(new[]

97
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlerFilters.cs

@ -20,13 +20,14 @@ namespace OpenIddict.Server.DataProtection
public static class OpenIddictServerDataProtectionHandlerFilters
{
/// <summary>
/// Represents a filter that excludes the associated handlers if OpenIddict was not configured to issue Data Protection tokens.
/// Represents a filter that excludes the associated handlers if OpenIddict
/// was not configured to issue ASP.NET Core Data Protection access tokens.
/// </summary>
public class RequireDataProtectionFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public class RequireDataProtectionAccessTokenFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerDataProtectionOptions> _options;
public RequireDataProtectionFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options)
public RequireDataProtectionAccessTokenFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options)
=> _options = options;
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
@ -36,7 +37,95 @@ namespace OpenIddict.Server.DataProtection
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultTokenFormat);
return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultAccessTokenFormat);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if OpenIddict
/// was not configured to issue ASP.NET Core Data Protection authorization codes.
/// </summary>
public class RequireDataProtectionAuthorizationCodeFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerDataProtectionOptions> _options;
public RequireDataProtectionAuthorizationCodeFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options)
=> _options = options;
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultAuthorizationCodeFormat);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if OpenIddict
/// was not configured to issue ASP.NET Core Data Protection device codes.
/// </summary>
public class RequireDataProtectionDeviceCodeFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerDataProtectionOptions> _options;
public RequireDataProtectionDeviceCodeFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options)
=> _options = options;
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultDeviceCodeFormat);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if OpenIddict
/// was not configured to issue ASP.NET Core Data Protection refresh tokens.
/// </summary>
public class RequireDataProtectionRefreshTokenFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerDataProtectionOptions> _options;
public RequireDataProtectionRefreshTokenFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options)
=> _options = options;
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultRefreshTokenFormat);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if OpenIddict
/// was not configured to issue ASP.NET Core Data Protection user codes.
/// </summary>
public class RequireDataProtectionUserCodeFormatEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictServerDataProtectionOptions> _options;
public RequireDataProtectionUserCodeFormatEnabled([NotNull] IOptionsMonitor<OpenIddictServerDataProtectionOptions> options)
=> _options = options;
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(!_options.CurrentValue.PreferDefaultUserCodeFormat);
}
}
}

16
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionHandlers.cs

@ -178,7 +178,7 @@ namespace OpenIddict.Server.DataProtection
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireAccessTokenIncluded>()
.AddFilter<RequireDataProtectionFormatEnabled>()
.AddFilter<RequireDataProtectionAccessTokenFormatEnabled>()
.UseSingletonHandler<GenerateDataProtectionAccessToken>()
.SetOrder(GenerateIdentityModelAccessToken.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
@ -205,7 +205,7 @@ namespace OpenIddict.Server.DataProtection
}
// Create a Data Protection protector using the provider registered in the options.
var protector = context.Options.UseReferenceTokens ?
var protector = context.Options.UseReferenceAccessTokens ?
_options.CurrentValue.DataProtectionProvider.CreateProtector(
Handlers.Server, Formats.AccessToken, Features.ReferenceTokens, Schemes.Server) :
_options.CurrentValue.DataProtectionProvider.CreateProtector(
@ -243,7 +243,7 @@ namespace OpenIddict.Server.DataProtection
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireAuthorizationCodeIncluded>()
.AddFilter<RequireDataProtectionFormatEnabled>()
.AddFilter<RequireDataProtectionAuthorizationCodeFormatEnabled>()
.UseSingletonHandler<GenerateDataProtectionAuthorizationCode>()
.SetOrder(GenerateIdentityModelAuthorizationCode.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
@ -270,7 +270,7 @@ namespace OpenIddict.Server.DataProtection
}
// Create a Data Protection protector using the provider registered in the options.
var protector = context.Options.UseReferenceTokens ?
var protector = !context.Options.DisableTokenStorage ?
_options.CurrentValue.DataProtectionProvider.CreateProtector(
Handlers.Server, Formats.AuthorizationCode, Features.ReferenceTokens, Schemes.Server) :
_options.CurrentValue.DataProtectionProvider.CreateProtector(
@ -308,7 +308,7 @@ namespace OpenIddict.Server.DataProtection
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireDeviceCodeIncluded>()
.AddFilter<RequireDataProtectionFormatEnabled>()
.AddFilter<RequireDataProtectionDeviceCodeFormatEnabled>()
.UseSingletonHandler<GenerateDataProtectionDeviceCode>()
.SetOrder(GenerateIdentityModelDeviceCode.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
@ -373,7 +373,7 @@ namespace OpenIddict.Server.DataProtection
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireRefreshTokenIncluded>()
.AddFilter<RequireDataProtectionFormatEnabled>()
.AddFilter<RequireDataProtectionRefreshTokenFormatEnabled>()
.UseSingletonHandler<GenerateDataProtectionRefreshToken>()
.SetOrder(GenerateIdentityModelRefreshToken.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)
@ -400,7 +400,7 @@ namespace OpenIddict.Server.DataProtection
}
// Create a Data Protection protector using the provider registered in the options.
var protector = context.Options.UseReferenceTokens ?
var protector = context.Options.UseReferenceRefreshTokens ?
_options.CurrentValue.DataProtectionProvider.CreateProtector(
Handlers.Server, Formats.RefreshToken, Features.ReferenceTokens, Schemes.Server) :
_options.CurrentValue.DataProtectionProvider.CreateProtector(
@ -438,7 +438,7 @@ namespace OpenIddict.Server.DataProtection
public static OpenIddictServerHandlerDescriptor Descriptor { get; }
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireUserCodeIncluded>()
.AddFilter<RequireDataProtectionFormatEnabled>()
.AddFilter<RequireDataProtectionUserCodeFormatEnabled>()
.UseSingletonHandler<GenerateDataProtectionUserCode>()
.SetOrder(GenerateIdentityModelUserCode.Descriptor.Order - 500)
.SetType(OpenIddictServerHandlerType.BuiltIn)

30
src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionOptions.cs

@ -29,9 +29,33 @@ namespace OpenIddict.Server.DataProtection
= new OpenIddictServerDataProtectionFormatter();
/// <summary>
/// Gets or sets a boolean indicating whether the default token format should be
/// used when issuing new tokens. This property is set to <c>false</c> by default.
/// Gets or sets a boolean indicating whether the default access token format should be
/// used when issuing new access tokens. This property is set to <c>false</c> by default.
/// </summary>
public bool PreferDefaultTokenFormat { get; set; }
public bool PreferDefaultAccessTokenFormat { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the default authorization code format should be
/// used when issuing new authorization codes. This property is set to <c>false</c> by default.
/// </summary>
public bool PreferDefaultAuthorizationCodeFormat { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the default device code format should be
/// used when issuing new device codes. This property is set to <c>false</c> by default.
/// </summary>
public bool PreferDefaultDeviceCodeFormat { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the default refresh token format should be
/// used when issuing new refresh tokens. This property is set to <c>false</c> by default.
/// </summary>
public bool PreferDefaultRefreshTokenFormat { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the default user code format should be
/// used when issuing new user codes. This property is set to <c>false</c> by default.
/// </summary>
public bool PreferDefaultUserCodeFormat { get; set; }
}
}

21
src/OpenIddict.Server/OpenIddictServerBuilder.cs

@ -1782,15 +1782,26 @@ namespace Microsoft.Extensions.DependencyInjection
}
/// <summary>
/// Configures OpenIddict to use reference tokens, so that the token and code payloads
/// Configures OpenIddict to use reference tokens, so that the access token payloads
/// are stored in the database (only an identifier is returned to the client application).
/// Enabling this option is useful when storing a very large number of claims in the tokens,
/// but it is RECOMMENDED to enable column encryption in the database or use the ASP.NET Core
/// Data Protection integration, that provides additional protection against token leakage.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder UseReferenceTokens()
=> Configure(options => options.UseReferenceTokens = true);
public OpenIddictServerBuilder UseReferenceAccessTokens()
=> Configure(options => options.UseReferenceAccessTokens = true);
/// <summary>
/// Configures OpenIddict to use reference tokens, so that the refresh token payloads
/// are stored in the database (only an identifier is returned to the client application).
/// Enabling this option is useful when storing a very large number of claims in the tokens,
/// but it is RECOMMENDED to enable column encryption in the database or use the ASP.NET Core
/// Data Protection integration, that provides additional protection against token leakage.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder UseReferenceRefreshTokens()
=> Configure(options => options.UseReferenceRefreshTokens = true);
/// <summary>
/// Configures OpenIddict to use rolling refresh tokens. When this option is enabled,
@ -1798,8 +1809,8 @@ namespace Microsoft.Extensions.DependencyInjection
/// one is automatically revoked unless token storage was explicitly disabled).
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder UseRollingTokens()
=> Configure(options => options.UseRollingTokens = true);
public OpenIddictServerBuilder UseRollingRefreshTokens()
=> Configure(options => options.UseRollingRefreshTokens = true);
/// <summary>
/// Determines whether the specified object is equal to the current object.

4
src/OpenIddict.Server/OpenIddictServerConfiguration.cs

@ -96,12 +96,12 @@ namespace OpenIddict.Server
throw new InvalidOperationException("The revocation endpoint cannot be enabled when token storage is disabled.");
}
if (options.UseReferenceTokens)
if (options.UseReferenceAccessTokens || options.UseReferenceRefreshTokens)
{
throw new InvalidOperationException("Reference tokens cannot be used when disabling token storage.");
}
if (options.UseSlidingExpiration && !options.UseRollingTokens)
if (options.UseSlidingExpiration && !options.UseRollingRefreshTokens)
{
throw new InvalidOperationException(new StringBuilder()
.Append("Sliding expiration must be disabled when turning off token storage if rolling tokens are not used.")

5
src/OpenIddict.Server/OpenIddictServerExtensions.cs

@ -54,10 +54,11 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Services.TryAddSingleton<RequireGrantTypePermissionsEnabled>();
builder.Services.TryAddSingleton<RequireIdentityTokenIncluded>();
builder.Services.TryAddSingleton<RequirePostLogoutRedirectUriParameter>();
builder.Services.TryAddSingleton<RequireReferenceTokensEnabled>();
builder.Services.TryAddSingleton<RequireReferenceAccessTokensEnabled>();
builder.Services.TryAddSingleton<RequireReferenceRefreshTokensEnabled>();
builder.Services.TryAddSingleton<RequireRefreshTokenIncluded>();
builder.Services.TryAddSingleton<RequireRollingTokensDisabled>();
builder.Services.TryAddSingleton<RequireRollingTokensEnabled>();
builder.Services.TryAddSingleton<RequireRollingRefreshTokensEnabled>();
builder.Services.TryAddSingleton<RequireSlidingExpirationEnabled>();
builder.Services.TryAddSingleton<RequireScopePermissionsEnabled>();
builder.Services.TryAddSingleton<RequireScopeValidationEnabled>();

30
src/OpenIddict.Server/OpenIddictServerHandlerFilters.cs

@ -176,9 +176,9 @@ namespace OpenIddict.Server
}
/// <summary>
/// Represents a filter that excludes the associated handlers if reference tokens are disabled.
/// Represents a filter that excludes the associated handlers if reference access tokens are disabled.
/// </summary>
public class RequireReferenceTokensEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public class RequireReferenceAccessTokensEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
@ -187,7 +187,23 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(context.Options.UseReferenceTokens);
return new ValueTask<bool>(context.Options.UseReferenceAccessTokens);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if reference refresh tokens are disabled.
/// </summary>
public class RequireReferenceRefreshTokensEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(context.Options.UseReferenceRefreshTokens);
}
}
@ -219,14 +235,14 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(!context.Options.UseRollingTokens);
return new ValueTask<bool>(!context.Options.UseRollingRefreshTokens);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if rolling tokens were not enabled.
/// Represents a filter that excludes the associated handlers if rolling refresh tokens were not enabled.
/// </summary>
public class RequireRollingTokensEnabled : IOpenIddictServerHandlerFilter<BaseContext>
public class RequireRollingRefreshTokensEnabled : IOpenIddictServerHandlerFilter<BaseContext>
{
public ValueTask<bool> IsActiveAsync([NotNull] BaseContext context)
{
@ -235,7 +251,7 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context));
}
return new ValueTask<bool>(context.Options.UseRollingTokens);
return new ValueTask<bool>(context.Options.UseRollingRefreshTokens);
}
}

12
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -1764,7 +1764,8 @@ namespace OpenIddict.Server
OpenIddictServerEndpointType.Token when !context.Principal.HasScope(Scopes.OfflineAccess) => false,
// 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.UseRollingTokens,
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,
@ -2547,7 +2548,7 @@ namespace OpenIddict.Server
return;
}
if (context.Request.IsRefreshTokenGrantType() && !context.Options.UseRollingTokens)
if (context.Request.IsRefreshTokenGrantType() && !context.Options.UseRollingRefreshTokens)
{
return;
}
@ -2615,7 +2616,7 @@ namespace OpenIddict.Server
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireDegradedModeDisabled>()
.AddFilter<RequireTokenStorageEnabled>()
.AddFilter<RequireRollingTokensEnabled>()
.AddFilter<RequireRollingRefreshTokensEnabled>()
.UseScopedHandler<RevokeExistingTokenEntries>()
.SetOrder(RedeemTokenEntry.Descriptor.Order + 1_000)
.SetType(OpenIddictServerHandlerType.BuiltIn)
@ -2980,7 +2981,7 @@ namespace OpenIddict.Server
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireDegradedModeDisabled>()
.AddFilter<RequireTokenStorageEnabled>()
.AddFilter<RequireReferenceTokensEnabled>()
.AddFilter<RequireReferenceAccessTokensEnabled>()
.AddFilter<RequireAccessTokenIncluded>()
.UseScopedHandler<ConvertReferenceAccessToken>()
.SetOrder(GenerateIdentityModelAccessToken.Descriptor.Order + 1_000)
@ -3266,7 +3267,6 @@ namespace OpenIddict.Server
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireDegradedModeDisabled>()
.AddFilter<RequireTokenStorageEnabled>()
.AddFilter<RequireReferenceTokensEnabled>()
.AddFilter<RequireAuthorizationCodeIncluded>()
.UseScopedHandler<ConvertReferenceAuthorizationCode>()
.SetOrder(GenerateIdentityModelAuthorizationCode.Descriptor.Order + 1_000)
@ -3945,7 +3945,7 @@ namespace OpenIddict.Server
= OpenIddictServerHandlerDescriptor.CreateBuilder<ProcessSignInContext>()
.AddFilter<RequireDegradedModeDisabled>()
.AddFilter<RequireTokenStorageEnabled>()
.AddFilter<RequireReferenceTokensEnabled>()
.AddFilter<RequireReferenceRefreshTokensEnabled>()
.AddFilter<RequireRefreshTokenIncluded>()
.UseScopedHandler<ConvertReferenceRefreshToken>()
.SetOrder(GenerateIdentityModelRefreshToken.Descriptor.Order + 1_000)

21
src/OpenIddict.Server/OpenIddictServerOptions.cs

@ -334,15 +334,26 @@ namespace OpenIddict.Server
};
/// <summary>
/// Gets or sets a boolean indicating whether reference tokens should be used.
/// When set to <c>true</c>, token and code payloads are stored in the database
/// and a crypto-secure random identifier is returned to the client application.
/// Gets or sets a boolean indicating whether reference access tokens should be used.
/// When set to <c>true</c>, the token payload is stored in the database and a
/// crypto-secure random identifier is returned to the client application.
/// Enabling this option is useful when storing a very large number of claims
/// in the tokens, but it is RECOMMENDED to enable column encryption
/// in the database or use the ASP.NET Core Data Protection integration,
/// that provides additional protection against token leakage.
/// </summary>
public bool UseReferenceTokens { get; set; }
public bool UseReferenceAccessTokens { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether reference refresh tokens should be used.
/// When set to <c>true</c>, the token payload is stored in the database and a
/// crypto-secure random identifier is returned to the client application.
/// Enabling this option is useful when storing a very large number of claims
/// in the tokens, but it is RECOMMENDED to enable column encryption
/// in the database or use the ASP.NET Core Data Protection integration,
/// that provides additional protection against token leakage.
/// </summary>
public bool UseReferenceRefreshTokens { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether rolling tokens should be used.
@ -352,6 +363,6 @@ namespace OpenIddict.Server
/// refresh token request (and the previous one is automatically revoked
/// unless token storage was explicitly disabled in the options).
/// </summary>
public bool UseRollingTokens { get; set; }
public bool UseRollingRefreshTokens { get; set; }
}
}

4
src/OpenIddict.Validation.ServerIntegration/OpenIddictValidationServerIntegrationConfiguration.cs

@ -59,8 +59,8 @@ namespace OpenIddict.Validation.ServerIntegration
options.EncryptionCredentials.Add(credentials);
}
// Note: token entry validation must be enabled to be able to validate reference tokens.
options.EnableTokenEntryValidation = _options.CurrentValue.UseReferenceTokens;
// Note: token entry validation must be enabled to be able to validate reference access tokens.
options.EnableTokenEntryValidation = _options.CurrentValue.UseReferenceAccessTokens;
}
/// <summary>

9
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Introspection.cs

@ -1217,8 +1217,6 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options =>
{
options.UseReferenceTokens();
options.Services.AddSingleton(CreateApplicationManager(mock =>
{
var application = new OpenIddictApplication();
@ -1329,7 +1327,6 @@ namespace OpenIddict.Server.FunctionalTests
options.Services.AddSingleton(manager);
options.DisableAuthorizationStorage();
options.UseReferenceTokens();
});
await using var client = await server.CreateClientAsync();
@ -1421,8 +1418,6 @@ namespace OpenIddict.Server.FunctionalTests
options.Services.AddSingleton(manager);
options.UseReferenceTokens();
options.RemoveEventHandler(NormalizeErrorResponse.Descriptor);
});
@ -1521,8 +1516,6 @@ namespace OpenIddict.Server.FunctionalTests
options.Services.AddSingleton(manager);
options.UseReferenceTokens();
options.RemoveEventHandler(NormalizeErrorResponse.Descriptor);
});
@ -1608,8 +1601,6 @@ namespace OpenIddict.Server.FunctionalTests
options.Services.AddSingleton(manager);
options.UseReferenceTokens();
options.RemoveEventHandler(NormalizeErrorResponse.Descriptor);
});

18
test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs

@ -2888,7 +2888,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options =>
{
options.EnableDegradedMode();
options.UseRollingTokens();
options.UseRollingRefreshTokens();
options.AddEventHandler<ProcessAuthenticationContext>(builder =>
{
@ -2940,7 +2940,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options =>
{
options.EnableDegradedMode();
options.UseRollingTokens();
options.UseRollingRefreshTokens();
options.AddEventHandler<ProcessAuthenticationContext>(builder =>
{
@ -2984,7 +2984,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options =>
{
options.EnableDegradedMode();
options.UseRollingTokens();
options.UseRollingRefreshTokens();
options.AddEventHandler<ProcessAuthenticationContext>(builder =>
{
@ -3240,7 +3240,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options =>
{
options.UseRollingTokens();
options.UseRollingRefreshTokens();
options.DisableAuthorizationStorage();
options.AddEventHandler<ProcessAuthenticationContext>(builder =>
@ -3307,7 +3307,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options =>
{
options.UseRollingTokens();
options.UseRollingRefreshTokens();
options.DisableAuthorizationStorage();
options.AddEventHandler<ProcessAuthenticationContext>(builder =>
@ -3456,7 +3456,7 @@ namespace OpenIddict.Server.FunctionalTests
await using var server = await CreateServerAsync(options =>
{
options.UseRollingTokens();
options.UseRollingRefreshTokens();
options.AddEventHandler<ProcessAuthenticationContext>(builder =>
{
@ -3969,6 +3969,9 @@ namespace OpenIddict.Server.FunctionalTests
mock.Setup(manager => manager.GetIdAsync(token, It.IsAny<CancellationToken>()))
.ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56");
mock.Setup(manager => manager.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
}));
options.Services.AddSingleton(manager);
@ -4042,6 +4045,9 @@ namespace OpenIddict.Server.FunctionalTests
mock.Setup(manager => manager.GetIdAsync(token, It.IsAny<CancellationToken>()))
.ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56");
mock.Setup(manager => manager.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny<CancellationToken>()))
.ReturnsAsync(token);
}));
options.Services.AddSingleton(manager);

124
test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs

@ -35,7 +35,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Action<OpenIddictServerHandlerDescriptor.Builder<CustomContext>> configuration = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEventHandler(configuration));
Assert.Equal(nameof(configuration), exception.ParamName);
}
@ -48,7 +48,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
OpenIddictServerHandlerDescriptor descriptor = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEventHandler(descriptor));
Assert.Equal(nameof(descriptor), exception.ParamName);
}
@ -136,7 +136,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
EncryptingCredentials credentials = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEncryptionCredentials(credentials));
Assert.Equal(nameof(credentials), exception.ParamName);
}
@ -149,7 +149,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
SecurityKey key = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.AddEncryptionKey(key));
Assert.Equal(nameof(key), exception.ParamName);
}
@ -163,7 +163,7 @@ namespace OpenIddict.Server.Tests
var key = new Mock<AsymmetricSecurityKey>();
key.SetupGet(x => x.PrivateKeyStatus).Returns(PrivateKeyStatus.DoesNotExist);
// Act & Assert
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => builder.AddEncryptionKey(key.Object));
Assert.Equal("The asymmetric encryption key doesn't contain the required private key.", exception.Message);
}
@ -194,7 +194,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
OpenIddictServerHandlerDescriptor descriptor = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.RemoveEventHandler(descriptor));
Assert.Equal(nameof(descriptor), exception.ParamName);
}
@ -242,7 +242,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Action<OpenIddictServerOptions> configuration = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.Configure(configuration));
Assert.Equal(nameof(configuration), exception.ParamName);
}
@ -271,7 +271,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
X500DistinguishedName subject = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.AddDevelopmentEncryptionCertificate(subject));
Assert.Equal(nameof(subject), exception.ParamName);
}
@ -455,7 +455,7 @@ namespace OpenIddict.Server.Tests
var services = CreateServices();
var builder = CreateBuilder(services);
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.AllowCustomFlow(type));
Assert.Equal(nameof(type), exception.ParamName);
Assert.Contains("The grant type cannot be null or empty.", exception.Message);
@ -533,7 +533,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetConfigurationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -546,7 +546,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetConfigurationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -562,7 +562,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), };
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetConfigurationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -608,7 +608,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetDeviceEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -621,7 +621,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetDeviceEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -635,7 +635,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), };
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetDeviceEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -697,7 +697,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetCryptographyEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -710,7 +710,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetCryptographyEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -724,7 +724,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), };
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetCryptographyEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -818,7 +818,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetAuthorizationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -831,7 +831,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetAuthorizationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -845,7 +845,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), };
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetAuthorizationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -891,7 +891,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetIntrospectionEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -904,7 +904,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetIntrospectionEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -918,7 +918,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), };
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetIntrospectionEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -964,7 +964,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetLogoutEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -977,7 +977,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetLogoutEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -991,7 +991,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), };
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetLogoutEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -1037,7 +1037,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetRevocationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -1050,7 +1050,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetRevocationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -1064,7 +1064,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), };
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetRevocationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -1126,7 +1126,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetTokenEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -1139,7 +1139,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetTokenEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -1153,7 +1153,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri), };
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetTokenEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -1199,7 +1199,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetUserinfoEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -1212,7 +1212,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetUserinfoEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -1226,7 +1226,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = {new Uri(uri), };
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetUserinfoEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message);
@ -1526,7 +1526,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] claims = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.RegisterClaims(claims));
Assert.Equal(nameof(claims), exception.ParamName);
}
@ -1541,7 +1541,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] claims = { claim };
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.RegisterClaims(claims));
Assert.Equal(nameof(claims), exception.ParamName);
Assert.Contains("Claims cannot be null or empty.", exception.Message);
@ -1572,7 +1572,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] scopes = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.RegisterScopes(scopes));
Assert.Equal(nameof(scopes), exception.ParamName);
}
@ -1587,26 +1587,58 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] scopes = { scope };
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.RegisterScopes(scopes));
Assert.Equal(nameof(scopes), exception.ParamName);
Assert.Contains("Scopes cannot be null or empty.", exception.Message);
}
[Fact]
public void UseReferenceTokens_ReferenceTokensAreEnabled()
public void UseReferenceAccessTokens_ReferenceAccessTokensAreEnabled()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.UseReferenceAccessTokens();
var options = GetOptions(services);
// Assert
Assert.True(options.UseReferenceAccessTokens);
}
[Fact]
public void UseReferenceRefreshTokens_ReferenceRefreshTokensAreEnabled()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.UseReferenceTokens();
builder.UseReferenceRefreshTokens();
var options = GetOptions(services);
// Assert
Assert.True(options.UseReferenceTokens);
Assert.True(options.UseReferenceRefreshTokens);
}
[Fact]
public void UseRollingRefreshTokens_RollingRefreshTokensAreEnabled()
{
// Arrange
var services = CreateServices();
var builder = CreateBuilder(services);
// Act
builder.UseRollingRefreshTokens();
var options = GetOptions(services);
// Assert
Assert.True(options.UseRollingRefreshTokens);
}
[Fact]
@ -1617,7 +1649,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetVerificationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -1630,7 +1662,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
string[] addresses = null;
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => builder.SetVerificationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
}
@ -1661,7 +1693,7 @@ namespace OpenIddict.Server.Tests
var builder = CreateBuilder(services);
Uri[] addresses = { new Uri(uri)};
// Act & Assert
// Act and assert
var exception = Assert.Throws<ArgumentException>(() => builder.SetVerificationEndpointUris(addresses));
Assert.Equal(nameof(addresses), exception.ParamName);
Assert.Contains("One of the specified addresses is not valid.", exception.Message);

Loading…
Cancel
Save