diff --git a/src/OpenIddict.Abstractions/OpenIddictResources.resx b/src/OpenIddict.Abstractions/OpenIddictResources.resx index 8ff98b2c..bf0fb02e 100644 --- a/src/OpenIddict.Abstractions/OpenIddictResources.resx +++ b/src/OpenIddict.Abstractions/OpenIddictResources.resx @@ -1866,6 +1866,9 @@ To use a custom policy relying on the system store, set 'OpenIddictServerOptions The '{0}' attached to the execution context could not be resolved. + + The '{0}' grant type is already assigned to a standard grant type and cannot be used for custom flows. + The security token is missing. diff --git a/src/OpenIddict.Server/OpenIddictServerBuilder.cs b/src/OpenIddict.Server/OpenIddictServerBuilder.cs index bca5f7a7..c91efbbf 100644 --- a/src/OpenIddict.Server/OpenIddictServerBuilder.cs +++ b/src/OpenIddict.Server/OpenIddictServerBuilder.cs @@ -924,7 +924,16 @@ public sealed class OpenIddictServerBuilder { ArgumentException.ThrowIfNullOrEmpty(type); - return Configure(options => options.GrantTypes.Add(type)); + return type switch + { + GrantTypes.AuthorizationCode or GrantTypes.ClientCredentials or + GrantTypes.DeviceCode or GrantTypes.Implicit or + GrantTypes.Password or GrantTypes.RefreshToken or + GrantTypes.TokenExchange + => throw new ArgumentException(SR.FormatID0517(type), nameof(type)), + + _ => Configure(options => options.GrantTypes.Add(type)) + }; } /// diff --git a/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs b/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs index 36491060..624ec52e 100644 --- a/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs +++ b/test/OpenIddict.Server.Tests/OpenIddictServerBuilderTests.cs @@ -537,6 +537,27 @@ public class OpenIddictServerBuilderTests Assert.Equal("type", exception.ParamName); } + [Theory] + [InlineData(GrantTypes.AuthorizationCode)] + [InlineData(GrantTypes.ClientCredentials)] + [InlineData(GrantTypes.DeviceCode)] + [InlineData(GrantTypes.Implicit)] + [InlineData(GrantTypes.Password)] + [InlineData(GrantTypes.RefreshToken)] + [InlineData(GrantTypes.TokenExchange)] + public void AllowCustomFlow_ThrowsAnExceptionForStandardGrantType(string type) + { + // Arrange + var services = CreateServices(); + var builder = CreateBuilder(services); + + // Act and assert + var exception = Assert.ThrowsAny(() => builder.AllowCustomFlow(type)); + + Assert.Equal("type", exception.ParamName); + Assert.StartsWith(SR.FormatID0517(type), exception.Message); + } + [Fact] public void AllowCustomFlow_CustomFlowIsAdded() {