diff --git a/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx b/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx index 00b89ba1..f53a180c 100644 --- a/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx +++ b/src/OpenIddict.Abstractions/Resources/OpenIddictResources.resx @@ -396,12 +396,6 @@ Consider using 'options.AddSigningCredentials(SigningCredentials)' instead. The verification endpoint must be enabled to use the device flow. - - The device and verification endpoints cannot be enabled when token storage is disabled. - - - The revocation endpoint cannot be enabled when token storage is disabled. - Reference tokens cannot be used when disabling token storage. diff --git a/src/OpenIddict.Server/OpenIddictServerConfiguration.cs b/src/OpenIddict.Server/OpenIddictServerConfiguration.cs index d4085eb3..3425a983 100644 --- a/src/OpenIddict.Server/OpenIddictServerConfiguration.cs +++ b/src/OpenIddict.Server/OpenIddictServerConfiguration.cs @@ -34,6 +34,20 @@ namespace OpenIddict.Server throw new ArgumentNullException(nameof(options)); } + if (options.EnableDegradedMode) + { + // Explicitly disable all the features that are implicitly excluded when the degraded mode is active. + options.DisableAuthorizationStorage = options.DisableTokenStorage = true; + options.IgnoreEndpointPermissions = options.IgnoreGrantTypePermissions = options.IgnoreScopePermissions = true; + options.UseReferenceAccessTokens = options.UseReferenceRefreshTokens = false; + + // When the degraded mode is enabled (and the token storage disabled), OpenIddict is not able to dynamically + // update the expiration date of a token. As such, either rolling tokens MUST be enabled or sliding token + // expiration MUST be disabled to always issue new refresh tokens with the same fixed expiration date. + // By default, OpenIddict will automatically force the rolling tokens option when using the degraded mode. + options.UseRollingRefreshTokens |= !options.UseRollingRefreshTokens && !options.DisableSlidingRefreshTokenExpiration; + } + if (options.JsonWebTokenHandler == null) { throw new InvalidOperationException(SR.GetResourceString(SR.ID1074)); @@ -78,16 +92,6 @@ namespace OpenIddict.Server if (options.DisableTokenStorage) { - if (options.DeviceEndpointUris.Count != 0 || options.VerificationEndpointUris.Count != 0) - { - throw new InvalidOperationException(SR.GetResourceString(SR.ID1080)); - } - - if (options.RevocationEndpointUris.Count != 0) - { - throw new InvalidOperationException(SR.GetResourceString(SR.ID1081)); - } - if (options.UseReferenceAccessTokens || options.UseReferenceRefreshTokens) { throw new InvalidOperationException(SR.GetResourceString(SR.ID1082)); diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs index 54d00fe9..a5365970 100644 --- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs +++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs @@ -2192,7 +2192,7 @@ namespace OpenIddict.Server.IntegrationTests } [Fact] - public async Task ProcessSignIn_NoRefreshTokenIsReturnedForRefreshTokenGrantRequests() + public async Task ProcessSignIn_ARefreshTokenIsReturnedForRefreshTokenGrantRequests() { // Arrange await using var server = await CreateServerAsync(options => @@ -2221,60 +2221,7 @@ namespace OpenIddict.Server.IntegrationTests { builder.UseInlineHandler(context => { - Assert.False(context.IncludeRefreshToken); - - return default; - }); - - builder.SetOrder(EvaluateReturnedTokens.Descriptor.Order + 500); - }); - }); - - await using var client = await server.CreateClientAsync(); - - // Act - var response = await client.PostAsync("/connect/token", new OpenIddictRequest - { - GrantType = GrantTypes.RefreshToken, - RefreshToken = "8xLOxBtZp8" - }); - - // Assert - Assert.Null(response.RefreshToken); - } - - [Fact] - public async Task ProcessSignIn_NoRefreshTokenIsReturnedWhenSlidingExpirationIsDisabled() - { - // Arrange - await using var server = await CreateServerAsync(options => - { - options.EnableDegradedMode(); - options.DisableSlidingRefreshTokenExpiration(); - - options.AddEventHandler(builder => - { - builder.UseInlineHandler(context => - { - Assert.Equal("8xLOxBtZp8", context.Token); - Assert.Equal(TokenTypeHints.RefreshToken, context.TokenType); - - context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer")) - .SetTokenType(TokenTypeHints.RefreshToken) - .SetScopes(Scopes.OfflineAccess) - .SetClaim(Claims.Subject, "Bob le Bricoleur"); - - return default; - }); - - builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500); - }); - - options.AddEventHandler(builder => - { - builder.UseInlineHandler(context => - { - Assert.False(context.IncludeRefreshToken); + Assert.True(context.IncludeRefreshToken); return default; }); @@ -2293,7 +2240,7 @@ namespace OpenIddict.Server.IntegrationTests }); // Assert - Assert.Null(response.RefreshToken); + Assert.NotNull(response.RefreshToken); } [Fact] @@ -3003,6 +2950,7 @@ namespace OpenIddict.Server.IntegrationTests await using var server = await CreateServerAsync(options => { options.EnableDegradedMode(); + options.DisableSlidingRefreshTokenExpiration(); options.AddEventHandler(builder => {