diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictMessage.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictMessage.cs
index fa14dadd..f8b7ad76 100644
--- a/src/OpenIddict.Abstractions/Primitives/OpenIddictMessage.cs
+++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictMessage.cs
@@ -42,6 +42,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict message.
///
/// The message parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictMessage(JsonElement parameters)
{
if (parameters.ValueKind != JsonValueKind.Object)
@@ -51,6 +52,12 @@ namespace OpenIddict.Abstractions
foreach (var parameter in parameters.EnumerateObject())
{
+ // Ignore parameters whose name is null or empty.
+ if (string.IsNullOrEmpty(parameter.Name))
+ {
+ continue;
+ }
+
// While generally discouraged, JSON objects can contain multiple properties with
// the same name. In this case, the last occurrence replaces the previous ones.
if (HasParameter(parameter.Name))
@@ -66,6 +73,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict message.
///
/// The message parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictMessage(IEnumerable> parameters)
{
if (parameters is null)
@@ -75,6 +83,12 @@ namespace OpenIddict.Abstractions
foreach (var parameter in parameters)
{
+ // Ignore parameters whose name is null or empty.
+ if (string.IsNullOrEmpty(parameter.Key))
+ {
+ continue;
+ }
+
AddParameter(parameter.Key, parameter.Value);
}
}
@@ -83,6 +97,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict message.
///
/// The message parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictMessage(IEnumerable> parameters)
{
if (parameters is null)
@@ -92,6 +107,12 @@ namespace OpenIddict.Abstractions
foreach (var parameter in parameters.GroupBy(parameter => parameter.Key))
{
+ // Ignore parameters whose name is null or empty.
+ if (string.IsNullOrEmpty(parameter.Key))
+ {
+ continue;
+ }
+
var values = parameter.Select(parameter => parameter.Value).ToArray();
// Note: the core OAuth 2.0 specification requires that request parameters
@@ -111,6 +132,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict message.
///
/// The message parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictMessage(IEnumerable> parameters)
{
if (parameters is null)
@@ -120,16 +142,21 @@ namespace OpenIddict.Abstractions
foreach (var parameter in parameters)
{
+ // Ignore parameters whose name is null or empty.
+ if (string.IsNullOrEmpty(parameter.Key))
+ {
+ continue;
+ }
+
// Note: the core OAuth 2.0 specification requires that request parameters
// not be present more than once but derived specifications like the
// token exchange specification deliberately allow specifying multiple
// parameters with the same name to represent a multi-valued parameter.
AddParameter(parameter.Key, parameter.Value?.Length switch
{
- null => default,
- 0 => default,
- 1 => parameter.Value[0],
- _ => parameter.Value
+ null or 0 => default,
+ 1 => parameter.Value[0],
+ _ => parameter.Value
});
}
}
@@ -138,6 +165,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict message.
///
/// The message parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictMessage(IEnumerable> parameters)
{
if (parameters is null)
@@ -147,6 +175,12 @@ namespace OpenIddict.Abstractions
foreach (var parameter in parameters)
{
+ // Ignore parameters whose name is null or empty.
+ if (string.IsNullOrEmpty(parameter.Key))
+ {
+ continue;
+ }
+
// Note: the core OAuth 2.0 specification requires that request parameters
// not be present more than once but derived specifications like the
// token exchange specification deliberately allow specifying multiple
diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs
index d6a05640..020d84bd 100644
--- a/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs
+++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs
@@ -118,8 +118,7 @@ namespace OpenIddict.Abstractions
var (left, right) when ReferenceEquals(left, right) => true,
// If one of the two parameters is null, return false.
- (null, _) => false,
- (_, null) => false,
+ (null, _) or (_, null) => false,
// If the two parameters are string arrays, use SequenceEqual().
(string?[] left, string?[] right) => left.SequenceEqual(right),
@@ -516,8 +515,7 @@ namespace OpenIddict.Abstractions
{
// Note: undefined JsonElement values are assimilated to null values.
case null:
- case JsonElement { ValueKind: JsonValueKind.Undefined }:
- case JsonElement { ValueKind: JsonValueKind.Null }:
+ case JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined }:
writer.WriteNullValue();
break;
@@ -583,8 +581,8 @@ namespace OpenIddict.Abstractions
/// The converted value.
public static explicit operator bool?(OpenIddictParameter? parameter) => parameter?.Value switch
{
- // When the parameter is a null value, return null.
- null => null,
+ // When the parameter is a null value or a JsonElement representing null, return null.
+ null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
// When the parameter is a boolean value, return it as-is.
bool value => value,
@@ -592,10 +590,6 @@ namespace OpenIddict.Abstractions
// When the parameter is a string value, try to parse it.
string value => bool.TryParse(value, out var result) ? (bool?) result : null,
- // When the parameter is a JsonElement representing null, return null.
- JsonElement { ValueKind: JsonValueKind.Undefined } => null,
- JsonElement { ValueKind: JsonValueKind.Null } => null,
-
// When the parameter is a JsonElement representing a boolean, return it as-is.
JsonElement { ValueKind: JsonValueKind.False } => false,
JsonElement { ValueKind: JsonValueKind.True } => true,
@@ -625,7 +619,7 @@ namespace OpenIddict.Abstractions
// When the parameter is a string starting with '{' or '[' (which would correspond
// to a JSON object or array), try to deserialize it to get a JsonElement instance.
- string { Length: > 0 } value when value[0] == '{' || value[0] == '[' =>
+ string { Length: > 0 } value when value[0] is '{' or '[' =>
DeserializeElement(value) ??
DeserializeElement(SerializeObject(value)) ?? default,
@@ -705,8 +699,8 @@ namespace OpenIddict.Abstractions
/// The converted value.
public static explicit operator long?(OpenIddictParameter? parameter) => parameter?.Value switch
{
- // When the parameter is a null value, return null.
- null => null,
+ // When the parameter is a null value or a JsonElement representing null, return null.
+ null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
// When the parameter is an integer, return it as-is.
long value => value,
@@ -715,10 +709,6 @@ namespace OpenIddict.Abstractions
string value
=> long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) ? (long?) result : null,
- // When the parameter is a JsonElement representing null, return null.
- JsonElement { ValueKind: JsonValueKind.Undefined } => null,
- JsonElement { ValueKind: JsonValueKind.Null } => null,
-
// When the parameter is a JsonElement representing a number, return it as-is.
JsonElement { ValueKind: JsonValueKind.Number } value
=> value.TryGetInt64(out var result) ? (long?) result : null,
@@ -738,8 +728,8 @@ namespace OpenIddict.Abstractions
/// The converted value.
public static explicit operator string?(OpenIddictParameter? parameter) => parameter?.Value switch
{
- // When the parameter is a null value, return null.
- null => null,
+ // When the parameter is a null value or a JsonElement representing null, return null.
+ null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
// When the parameter is a string value, return it as-is.
string value => value,
@@ -750,10 +740,6 @@ namespace OpenIddict.Abstractions
// When the parameter is an integer, use its string representation.
long value => value.ToString(CultureInfo.InvariantCulture),
- // When the parameter is a JsonElement representing null, return null.
- JsonElement { ValueKind: JsonValueKind.Undefined } => null,
- JsonElement { ValueKind: JsonValueKind.Null } => null,
-
// When the parameter is a JsonElement representing a string, return it as-is.
JsonElement { ValueKind: JsonValueKind.String } value => value.GetString(),
@@ -778,8 +764,8 @@ namespace OpenIddict.Abstractions
{
return parameter?.Value switch
{
- // When the parameter is a null value, return a null array.
- null => null,
+ // When the parameter is a null value or a JsonElement representing null, return null.
+ null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => null,
// When the parameter is already an array of strings, return it as-is.
string?[] value => value,
@@ -793,10 +779,6 @@ namespace OpenIddict.Abstractions
// When the parameter is an integer, return an array with its string representation.
long value => new string?[] { value.ToString(CultureInfo.InvariantCulture) },
- // When the parameter is a JsonElement representing null, return null.
- JsonElement { ValueKind: JsonValueKind.Undefined } => null,
- JsonElement { ValueKind: JsonValueKind.Null } => null,
-
// When the parameter is a JsonElement representing a string, return an array with a single entry.
JsonElement { ValueKind: JsonValueKind.String } value => new string?[] { value.GetString() },
@@ -893,16 +875,14 @@ namespace OpenIddict.Abstractions
{
return parameter.Value switch
{
- null => true,
+ null or JsonElement { ValueKind: JsonValueKind.Null or JsonValueKind.Undefined } => true,
string value => string.IsNullOrEmpty(value),
string?[] value => value.Length == 0,
- JsonElement { ValueKind: JsonValueKind.Undefined } => true,
- JsonElement { ValueKind: JsonValueKind.Null } => true,
- JsonElement { ValueKind: JsonValueKind.String } value => string.IsNullOrEmpty(value.GetString()),
- JsonElement { ValueKind: JsonValueKind.Array } value => value.GetArrayLength() == 0,
- JsonElement { ValueKind: JsonValueKind.Object } value => IsEmptyNode(value),
+ JsonElement { ValueKind: JsonValueKind.String } value => string.IsNullOrEmpty(value.GetString()),
+ JsonElement { ValueKind: JsonValueKind.Array } value => value.GetArrayLength() == 0,
+ JsonElement { ValueKind: JsonValueKind.Object } value => IsEmptyNode(value),
_ => false
};
diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictRequest.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictRequest.cs
index 9bdc44a2..cd2e222d 100644
--- a/src/OpenIddict.Abstractions/Primitives/OpenIddictRequest.cs
+++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictRequest.cs
@@ -36,6 +36,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict request.
///
/// The request parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictRequest(JsonElement parameters)
: base(parameters)
{
@@ -45,6 +46,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict request.
///
/// The request parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictRequest(IEnumerable> parameters)
: base(parameters)
{
@@ -54,6 +56,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict request.
///
/// The request parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictRequest(IEnumerable> parameters)
: base(parameters)
{
@@ -63,6 +66,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict request.
///
/// The request parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictRequest(IEnumerable> parameters)
: base(parameters)
{
@@ -72,6 +76,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict request.
///
/// The request parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictRequest(IEnumerable> parameters)
: base(parameters)
{
diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictResponse.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictResponse.cs
index 1d242c86..bdf1beda 100644
--- a/src/OpenIddict.Abstractions/Primitives/OpenIddictResponse.cs
+++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictResponse.cs
@@ -36,6 +36,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict response.
///
/// The response parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictResponse(JsonElement parameters)
: base(parameters)
{
@@ -45,6 +46,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict response.
///
/// The response parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictResponse(IEnumerable> parameters)
: base(parameters)
{
@@ -54,6 +56,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict response.
///
/// The response parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictResponse(IEnumerable> parameters)
: base(parameters)
{
@@ -63,6 +66,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict response.
///
/// The response parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictResponse(IEnumerable> parameters)
: base(parameters)
{
@@ -72,6 +76,7 @@ namespace OpenIddict.Abstractions
/// Initializes a new OpenIddict response.
///
/// The response parameters.
+ /// Parameters with a null or empty key are always ignored.
public OpenIddictResponse(IEnumerable> parameters)
: base(parameters)
{
diff --git a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
index 985b5a50..ac5b97a1 100644
--- a/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
+++ b/src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
@@ -365,12 +365,12 @@ namespace OpenIddict.Server.AspNetCore
context.Transaction.Response.AddParameter(parameter.Key, parameter.Value switch
{
OpenIddictParameter value => value,
- JsonElement value => value,
- bool value => value,
- int value => value,
- long value => value,
- string value => value,
- string[] value => value,
+ JsonElement value => new OpenIddictParameter(value),
+ bool value => new OpenIddictParameter(value),
+ int value => new OpenIddictParameter(value),
+ long value => new OpenIddictParameter(value),
+ string value => new OpenIddictParameter(value),
+ string[] value => new OpenIddictParameter(value),
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0115))
});
@@ -816,12 +816,9 @@ namespace OpenIddict.Server.AspNetCore
{
null => 200, // Note: the default code may be replaced by another handler (e.g when doing redirects).
- Errors.InvalidClient => 401,
- Errors.InvalidToken => 401,
- Errors.MissingToken => 401,
+ Errors.InvalidClient or Errors.InvalidToken or Errors.MissingToken => 401,
- Errors.InsufficientAccess => 403,
- Errors.InsufficientScope => 403,
+ Errors.InsufficientAccess or Errors.InsufficientScope => 403,
_ => 400
};
@@ -921,12 +918,12 @@ namespace OpenIddict.Server.AspNetCore
// were specified in the request form instead of the HTTP headers, as allowed by the specification.
var scheme = context.Transaction.Response.Error switch
{
- Errors.InvalidClient => Schemes.Basic,
+ Errors.InvalidClient => Schemes.Basic,
- Errors.InvalidToken => Schemes.Bearer,
- Errors.MissingToken => Schemes.Bearer,
- Errors.InsufficientAccess => Schemes.Bearer,
- Errors.InsufficientScope => Schemes.Bearer,
+ Errors.InvalidToken or
+ Errors.MissingToken or
+ Errors.InsufficientAccess or
+ Errors.InsufficientScope => Schemes.Bearer,
_ => null
};
diff --git a/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs b/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs
index 94b6ad14..9113ce8c 100644
--- a/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs
+++ b/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs
@@ -243,30 +243,26 @@ namespace OpenIddict.Server.DataProtection
SetArrayProperty(properties, Properties.Scopes, principal.GetScopes());
// Copy the principal and exclude the claim that were mapped to authentication properties.
- principal = principal.Clone(claim => claim.Type switch
- {
- Claims.Private.AccessTokenLifetime => false,
- Claims.Private.Audience => false,
- Claims.Private.AuthorizationCodeLifetime => false,
- Claims.Private.AuthorizationId => false,
- Claims.Private.CodeChallenge => false,
- Claims.Private.CodeChallengeMethod => false,
- Claims.Private.CreationDate => false,
- Claims.Private.DeviceCodeId => false,
- Claims.Private.DeviceCodeLifetime => false,
- Claims.Private.ExpirationDate => false,
- Claims.Private.IdentityTokenLifetime => false,
- Claims.Private.Nonce => false,
- Claims.Private.Presenter => false,
- Claims.Private.RedirectUri => false,
- Claims.Private.RefreshTokenLifetime => false,
- Claims.Private.Resource => false,
- Claims.Private.Scope => false,
- Claims.Private.TokenId => false,
- Claims.Private.UserCodeLifetime => false,
-
- _ => true
- });
+ principal = principal.Clone(claim => claim.Type is not (
+ Claims.Private.AccessTokenLifetime or
+ Claims.Private.Audience or
+ Claims.Private.AuthorizationCodeLifetime or
+ Claims.Private.AuthorizationId or
+ Claims.Private.CodeChallenge or
+ Claims.Private.CodeChallengeMethod or
+ Claims.Private.CreationDate or
+ Claims.Private.DeviceCodeId or
+ Claims.Private.DeviceCodeLifetime or
+ Claims.Private.ExpirationDate or
+ Claims.Private.IdentityTokenLifetime or
+ Claims.Private.Nonce or
+ Claims.Private.Presenter or
+ Claims.Private.RedirectUri or
+ Claims.Private.RefreshTokenLifetime or
+ Claims.Private.Resource or
+ Claims.Private.Scope or
+ Claims.Private.TokenId or
+ Claims.Private.UserCodeLifetime));
Write(writer, principal.Identity.AuthenticationType, principal, properties);
writer.Flush();
diff --git a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
index b0ec2f95..749df1b1 100644
--- a/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
+++ b/src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
@@ -753,12 +753,9 @@ namespace OpenIddict.Server.Owin
{
null => 200, // Note: the default code may be replaced by another handler (e.g when doing redirects).
- Errors.InvalidClient => 401,
- Errors.InvalidToken => 401,
- Errors.MissingToken => 401,
+ Errors.InvalidClient or Errors.InvalidToken or Errors.MissingToken => 401,
- Errors.InsufficientAccess => 403,
- Errors.InsufficientScope => 403,
+ Errors.InsufficientAccess or Errors.InsufficientScope => 403,
_ => 400
};
@@ -858,12 +855,12 @@ namespace OpenIddict.Server.Owin
// were specified in the request form instead of the HTTP headers, as allowed by the specification.
var scheme = context.Transaction.Response.Error switch
{
- Errors.InvalidClient => Schemes.Basic,
+ Errors.InvalidClient => Schemes.Basic,
- Errors.InvalidToken => Schemes.Bearer,
- Errors.MissingToken => Schemes.Bearer,
- Errors.InsufficientAccess => Schemes.Bearer,
- Errors.InsufficientScope => Schemes.Bearer,
+ Errors.InvalidToken or
+ Errors.MissingToken or
+ Errors.InsufficientAccess or
+ Errors.InsufficientScope => Schemes.Bearer,
_ => null
};
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs
index c8c03e4d..649aabd3 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Discovery.cs
@@ -689,26 +689,26 @@ namespace OpenIddict.Server
var algorithm = credentials.Algorithm switch
{
#if SUPPORTS_ECDSA
- SecurityAlgorithms.EcdsaSha256 => SecurityAlgorithms.EcdsaSha256,
- SecurityAlgorithms.EcdsaSha384 => SecurityAlgorithms.EcdsaSha384,
- SecurityAlgorithms.EcdsaSha512 => SecurityAlgorithms.EcdsaSha512,
- SecurityAlgorithms.EcdsaSha256Signature => SecurityAlgorithms.EcdsaSha256,
- SecurityAlgorithms.EcdsaSha384Signature => SecurityAlgorithms.EcdsaSha384,
- SecurityAlgorithms.EcdsaSha512Signature => SecurityAlgorithms.EcdsaSha512,
+ SecurityAlgorithms.EcdsaSha256 or SecurityAlgorithms.EcdsaSha256Signature
+ => SecurityAlgorithms.EcdsaSha256,
+ SecurityAlgorithms.EcdsaSha384 or SecurityAlgorithms.EcdsaSha384Signature
+ => SecurityAlgorithms.EcdsaSha384,
+ SecurityAlgorithms.EcdsaSha512 or SecurityAlgorithms.EcdsaSha512Signature
+ => SecurityAlgorithms.EcdsaSha512,
#endif
- SecurityAlgorithms.RsaSha256 => SecurityAlgorithms.RsaSha256,
- SecurityAlgorithms.RsaSha384 => SecurityAlgorithms.RsaSha384,
- SecurityAlgorithms.RsaSha512 => SecurityAlgorithms.RsaSha512,
- SecurityAlgorithms.RsaSha256Signature => SecurityAlgorithms.RsaSha256,
- SecurityAlgorithms.RsaSha384Signature => SecurityAlgorithms.RsaSha384,
- SecurityAlgorithms.RsaSha512Signature => SecurityAlgorithms.RsaSha512,
-
- SecurityAlgorithms.RsaSsaPssSha256 => SecurityAlgorithms.RsaSsaPssSha256,
- SecurityAlgorithms.RsaSsaPssSha384 => SecurityAlgorithms.RsaSsaPssSha384,
- SecurityAlgorithms.RsaSsaPssSha512 => SecurityAlgorithms.RsaSsaPssSha512,
- SecurityAlgorithms.RsaSsaPssSha256Signature => SecurityAlgorithms.RsaSsaPssSha256,
- SecurityAlgorithms.RsaSsaPssSha384Signature => SecurityAlgorithms.RsaSsaPssSha384,
- SecurityAlgorithms.RsaSsaPssSha512Signature => SecurityAlgorithms.RsaSsaPssSha512,
+ SecurityAlgorithms.RsaSha256 or SecurityAlgorithms.RsaSha256Signature
+ => SecurityAlgorithms.RsaSha256,
+ SecurityAlgorithms.RsaSha384 or SecurityAlgorithms.RsaSha384Signature
+ => SecurityAlgorithms.RsaSha384,
+ SecurityAlgorithms.RsaSha512 or SecurityAlgorithms.RsaSha512Signature
+ => SecurityAlgorithms.RsaSha512,
+
+ SecurityAlgorithms.RsaSsaPssSha256 or SecurityAlgorithms.RsaSsaPssSha256Signature
+ => SecurityAlgorithms.RsaSsaPssSha256,
+ SecurityAlgorithms.RsaSsaPssSha384 or SecurityAlgorithms.RsaSsaPssSha384Signature
+ => SecurityAlgorithms.RsaSsaPssSha384,
+ SecurityAlgorithms.RsaSsaPssSha512 or SecurityAlgorithms.RsaSsaPssSha512Signature
+ => SecurityAlgorithms.RsaSsaPssSha512,
_ => null
};
@@ -1108,26 +1108,26 @@ namespace OpenIddict.Server
Alg = credentials.Algorithm switch
{
#if SUPPORTS_ECDSA
- SecurityAlgorithms.EcdsaSha256 => SecurityAlgorithms.EcdsaSha256,
- SecurityAlgorithms.EcdsaSha384 => SecurityAlgorithms.EcdsaSha384,
- SecurityAlgorithms.EcdsaSha512 => SecurityAlgorithms.EcdsaSha512,
- SecurityAlgorithms.EcdsaSha256Signature => SecurityAlgorithms.EcdsaSha256,
- SecurityAlgorithms.EcdsaSha384Signature => SecurityAlgorithms.EcdsaSha384,
- SecurityAlgorithms.EcdsaSha512Signature => SecurityAlgorithms.EcdsaSha512,
+ SecurityAlgorithms.EcdsaSha256 or SecurityAlgorithms.EcdsaSha256Signature
+ => SecurityAlgorithms.EcdsaSha256,
+ SecurityAlgorithms.EcdsaSha384 or SecurityAlgorithms.EcdsaSha384Signature
+ => SecurityAlgorithms.EcdsaSha384,
+ SecurityAlgorithms.EcdsaSha512 or SecurityAlgorithms.EcdsaSha512Signature
+ => SecurityAlgorithms.EcdsaSha512,
#endif
- SecurityAlgorithms.RsaSha256 => SecurityAlgorithms.RsaSha256,
- SecurityAlgorithms.RsaSha384 => SecurityAlgorithms.RsaSha384,
- SecurityAlgorithms.RsaSha512 => SecurityAlgorithms.RsaSha512,
- SecurityAlgorithms.RsaSha256Signature => SecurityAlgorithms.RsaSha256,
- SecurityAlgorithms.RsaSha384Signature => SecurityAlgorithms.RsaSha384,
- SecurityAlgorithms.RsaSha512Signature => SecurityAlgorithms.RsaSha512,
-
- SecurityAlgorithms.RsaSsaPssSha256 => SecurityAlgorithms.RsaSsaPssSha256,
- SecurityAlgorithms.RsaSsaPssSha384 => SecurityAlgorithms.RsaSsaPssSha384,
- SecurityAlgorithms.RsaSsaPssSha512 => SecurityAlgorithms.RsaSsaPssSha512,
- SecurityAlgorithms.RsaSsaPssSha256Signature => SecurityAlgorithms.RsaSsaPssSha256,
- SecurityAlgorithms.RsaSsaPssSha384Signature => SecurityAlgorithms.RsaSsaPssSha384,
- SecurityAlgorithms.RsaSsaPssSha512Signature => SecurityAlgorithms.RsaSsaPssSha512,
+ SecurityAlgorithms.RsaSha256 or SecurityAlgorithms.RsaSha256Signature
+ => SecurityAlgorithms.RsaSha256,
+ SecurityAlgorithms.RsaSha384 or SecurityAlgorithms.RsaSha384Signature
+ => SecurityAlgorithms.RsaSha384,
+ SecurityAlgorithms.RsaSha512 or SecurityAlgorithms.RsaSha512Signature
+ => SecurityAlgorithms.RsaSha512,
+
+ SecurityAlgorithms.RsaSsaPssSha256 or SecurityAlgorithms.RsaSsaPssSha256Signature
+ => SecurityAlgorithms.RsaSsaPssSha256,
+ SecurityAlgorithms.RsaSsaPssSha384 or SecurityAlgorithms.RsaSsaPssSha384Signature
+ => SecurityAlgorithms.RsaSsaPssSha384,
+ SecurityAlgorithms.RsaSsaPssSha512 or SecurityAlgorithms.RsaSsaPssSha512Signature
+ => SecurityAlgorithms.RsaSsaPssSha512,
_ => null
},
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs
index e3c8e451..d80e691a 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs
@@ -1628,7 +1628,7 @@ namespace OpenIddict.Server
// When an explicit scope parameter has been included in the token request,
// the authorization server MUST ensure that it doesn't contain scopes
- // that were not allowed during the initial authorization/token request.
+ // that were not granted during the initial authorization/token request.
// See https://tools.ietf.org/html/rfc6749#section-6 for more information.
else if (!scopes.IsSupersetOf(context.Request.GetScopes()))
{
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs
index 4bfff7c7..4d821633 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs
@@ -976,23 +976,16 @@ namespace OpenIddict.Server
context.Username = context.Principal.Identity.Name;
context.Scopes.UnionWith(context.Principal.GetScopes());
- foreach (var grouping in context.Principal.Claims.GroupBy(claim => claim.Type))
+ foreach (var group in context.Principal.Claims.GroupBy(claim => claim.Type))
{
// Exclude standard claims, that are already handled via strongly-typed properties.
// Make sure to always update this list when adding new built-in claim properties.
- var type = grouping.Key;
- switch (type)
+ var type = group.Key;
+ if (type is Claims.Audience or Claims.ExpiresAt or Claims.IssuedAt or
+ Claims.Issuer or Claims.NotBefore or Claims.Scope or
+ Claims.Subject or Claims.TokenType or Claims.TokenUsage)
{
- case Claims.Audience:
- case Claims.ExpiresAt:
- case Claims.IssuedAt:
- case Claims.Issuer:
- case Claims.NotBefore:
- case Claims.Scope:
- case Claims.Subject:
- case Claims.TokenType:
- case Claims.TokenUsage:
- continue;
+ continue;
}
// Exclude OpenIddict-specific metadata claims, that are always considered private.
@@ -1001,7 +994,7 @@ namespace OpenIddict.Server
continue;
}
- var claims = grouping.ToList();
+ var claims = group.ToList();
context.Claims[type] = claims.Count switch
{
// When there's only one claim with the same type, directly
@@ -1018,12 +1011,12 @@ namespace OpenIddict.Server
{
ClaimValueTypes.Boolean => bool.Parse(claim.Value),
- ClaimValueTypes.Integer => int.Parse(claim.Value, CultureInfo.InvariantCulture),
- ClaimValueTypes.Integer32 => int.Parse(claim.Value, CultureInfo.InvariantCulture),
+ ClaimValueTypes.Integer or ClaimValueTypes.Integer32
+ => int.Parse(claim.Value, CultureInfo.InvariantCulture),
+
ClaimValueTypes.Integer64 => long.Parse(claim.Value, CultureInfo.InvariantCulture),
- JsonClaimValueTypes.Json => DeserializeElement(claim.Value),
- JsonClaimValueTypes.JsonArray => DeserializeElement(claim.Value),
+ JsonClaimValueTypes.Json or JsonClaimValueTypes.JsonArray => DeserializeElement(claim.Value),
_ => new OpenIddictParameter(claim.Value)
};
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.cs
index 2b1fa782..6aa6a4c3 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.cs
@@ -187,13 +187,13 @@ namespace OpenIddict.Server
var (token, type) = context.EndpointType switch
{
- OpenIddictServerEndpointType.Authorization => (context.Request.IdTokenHint, TokenTypeHints.IdToken),
- OpenIddictServerEndpointType.Logout => (context.Request.IdTokenHint, TokenTypeHints.IdToken),
+ OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Logout
+ => (context.Request.IdTokenHint, TokenTypeHints.IdToken),
// Tokens received by the introspection and revocation endpoints can be of any type.
// Additional token type filtering is made by the endpoint themselves, if needed.
- OpenIddictServerEndpointType.Introspection => (context.Request.Token, null),
- OpenIddictServerEndpointType.Revocation => (context.Request.Token, null),
+ OpenIddictServerEndpointType.Introspection or OpenIddictServerEndpointType.Revocation
+ => (context.Request.Token, null),
OpenIddictServerEndpointType.Token when context.Request.IsAuthorizationCodeGrantType()
=> (context.Request.Code, TokenTypeHints.AuthorizationCode),
@@ -407,7 +407,7 @@ namespace OpenIddict.Server
{
// If no specific token type is expected, accept all token types at this stage.
// Additional filtering can be made based on the resolved/actual token type.
- var type when string.IsNullOrEmpty(type) => null,
+ null or { Length: 0 } => null,
// For access tokens, both "at+jwt" and "application/at+jwt" are valid.
TokenTypeHints.AccessToken => new[]
@@ -481,13 +481,15 @@ namespace OpenIddict.Server
// Store the token type (resolved from "typ" or "token_usage") as a special private claim.
context.Principal.SetTokenType(result.TokenType switch
{
- var type when string.IsNullOrEmpty(type) => throw new InvalidOperationException(SR.GetResourceString(SR.ID0025)),
+ null or { Length: 0 } => throw new InvalidOperationException(SR.GetResourceString(SR.ID0025)),
- JsonWebTokenTypes.AccessToken => TokenTypeHints.AccessToken,
- JsonWebTokenTypes.Prefixes.Application + JsonWebTokenTypes.AccessToken => TokenTypeHints.AccessToken,
+ // Both at+jwt and application/at+jwt are supported for access tokens.
+ JsonWebTokenTypes.AccessToken or JsonWebTokenTypes.Prefixes.Application + JsonWebTokenTypes.AccessToken
+ => TokenTypeHints.AccessToken,
- JsonWebTokenTypes.IdentityToken => TokenTypeHints.IdToken,
- JsonWebTokenTypes.Prefixes.Application + JsonWebTokenTypes.IdentityToken => TokenTypeHints.IdToken,
+ // Both JWT and application/JWT are supported for identity tokens.
+ JsonWebTokenTypes.IdentityToken or JsonWebTokenTypes.Prefixes.Application + JsonWebTokenTypes.IdentityToken
+ => TokenTypeHints.IdToken,
JsonWebTokenTypes.Private.AuthorizationCode => TokenTypeHints.AuthorizationCode,
JsonWebTokenTypes.Private.DeviceCode => TokenTypeHints.DeviceCode,
@@ -749,8 +751,8 @@ namespace OpenIddict.Server
},
description: context.EndpointType switch
{
- OpenIddictServerEndpointType.Authorization => context.Localizer[SR.ID2009],
- OpenIddictServerEndpointType.Logout => context.Localizer[SR.ID2009],
+ OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Logout
+ => context.Localizer[SR.ID2009],
OpenIddictServerEndpointType.Token when context.Request.IsAuthorizationCodeGrantType()
=> context.Localizer[SR.ID2001],
@@ -1090,11 +1092,9 @@ namespace OpenIddict.Server
Debug.Assert(context.Principal is not null, SR.GetResourceString(SR.ID4006));
// Don't validate the lifetime of id_tokens used as id_token_hints.
- switch (context.EndpointType)
+ if (context.EndpointType is OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Logout)
{
- case OpenIddictServerEndpointType.Authorization:
- case OpenIddictServerEndpointType.Logout:
- return default;
+ return default;
}
var date = context.Principal.GetExpirationDate();
@@ -1152,16 +1152,15 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context));
}
- return context.EndpointType switch
+ if (context.EndpointType is not (OpenIddictServerEndpointType.Authorization or
+ OpenIddictServerEndpointType.Token or
+ OpenIddictServerEndpointType.Userinfo or
+ OpenIddictServerEndpointType.Verification))
{
- OpenIddictServerEndpointType.Authorization or
- OpenIddictServerEndpointType.Token or
- OpenIddictServerEndpointType.Userinfo or
- OpenIddictServerEndpointType.Verification
- => default,
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0006));
+ }
- _ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006)),
- };
+ return default;
}
}
@@ -1190,20 +1189,22 @@ namespace OpenIddict.Server
context.Response.Error ??= context.EndpointType switch
{
- OpenIddictServerEndpointType.Authorization => Errors.AccessDenied,
- OpenIddictServerEndpointType.Token => Errors.InvalidGrant,
- OpenIddictServerEndpointType.Userinfo => Errors.InsufficientAccess,
- OpenIddictServerEndpointType.Verification => Errors.AccessDenied,
+ OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
+ => Errors.AccessDenied,
+
+ OpenIddictServerEndpointType.Token => Errors.InvalidGrant,
+ OpenIddictServerEndpointType.Userinfo => Errors.InsufficientAccess,
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006))
};
context.Response.ErrorDescription ??= context.EndpointType switch
{
- OpenIddictServerEndpointType.Authorization => context.Localizer[SR.ID2015],
- OpenIddictServerEndpointType.Verification => context.Localizer[SR.ID2015],
- OpenIddictServerEndpointType.Token => context.Localizer[SR.ID2024],
- OpenIddictServerEndpointType.Userinfo => context.Localizer[SR.ID2025],
+ OpenIddictServerEndpointType.Authorization or OpenIddictServerEndpointType.Verification
+ => context.Localizer[SR.ID2015],
+
+ OpenIddictServerEndpointType.Token => context.Localizer[SR.ID2024],
+ OpenIddictServerEndpointType.Userinfo => context.Localizer[SR.ID2025],
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0006))
};
@@ -1356,15 +1357,12 @@ namespace OpenIddict.Server
Debug.Assert(context.Principal is not null, SR.GetResourceString(SR.ID4006));
- switch (context.EndpointType)
+ if (context.EndpointType is not (OpenIddictServerEndpointType.Authorization or
+ OpenIddictServerEndpointType.Device or
+ OpenIddictServerEndpointType.Token or
+ OpenIddictServerEndpointType.Verification))
{
- case OpenIddictServerEndpointType.Authorization:
- case OpenIddictServerEndpointType.Device:
- case OpenIddictServerEndpointType.Token:
- case OpenIddictServerEndpointType.Verification:
- break;
-
- default: throw new InvalidOperationException(SR.GetResourceString(SR.ID0010));
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0010));
}
if (context.Principal.Identity is null)
@@ -2521,16 +2519,12 @@ namespace OpenIddict.Server
}
// Clone the principal and exclude the private claims mapped to standard JWT claims.
- var principal = context.AccessTokenPrincipal.Clone(claim => claim.Type switch
- {
- Claims.Private.Audience => false,
- Claims.Private.CreationDate => false,
- Claims.Private.ExpirationDate => false,
- Claims.Private.Scope => false,
- Claims.Private.TokenType => false,
-
- _ => true
- });
+ var principal = context.AccessTokenPrincipal.Clone(claim => claim.Type is not (
+ Claims.Private.Audience or
+ Claims.Private.CreationDate or
+ Claims.Private.ExpirationDate or
+ Claims.Private.Scope or
+ Claims.Private.TokenType));
if (principal is null)
{
@@ -2786,14 +2780,10 @@ namespace OpenIddict.Server
}
// Clone the principal and exclude the claim mapped to standard JWT claims.
- var principal = context.AuthorizationCodePrincipal.Clone(claim => claim.Type switch
- {
- Claims.Private.CreationDate => false,
- Claims.Private.ExpirationDate => false,
- Claims.Private.TokenType => false,
-
- _ => true
- });
+ var principal = context.AuthorizationCodePrincipal.Clone(claim => claim.Type is not (
+ Claims.Private.CreationDate or
+ Claims.Private.ExpirationDate or
+ Claims.Private.TokenType));
if (principal is null)
{
@@ -3036,14 +3026,10 @@ namespace OpenIddict.Server
}
// Clone the principal and exclude the claim mapped to standard JWT claims.
- var principal = context.DeviceCodePrincipal.Clone(claim => claim.Type switch
- {
- Claims.Private.CreationDate => false,
- Claims.Private.ExpirationDate => false,
- Claims.Private.TokenType => false,
-
- _ => true
- });
+ var principal = context.DeviceCodePrincipal.Clone(claim => claim.Type is not (
+ Claims.Private.CreationDate or
+ Claims.Private.ExpirationDate or
+ Claims.Private.TokenType));
if (principal is null)
{
@@ -3370,14 +3356,10 @@ namespace OpenIddict.Server
}
// Clone the principal and exclude the claim mapped to standard JWT claims.
- var principal = context.RefreshTokenPrincipal.Clone(claim => claim.Type switch
- {
- Claims.Private.CreationDate => false,
- Claims.Private.ExpirationDate => false,
- Claims.Private.TokenType => false,
-
- _ => true
- });
+ var principal = context.RefreshTokenPrincipal.Clone(claim => claim.Type is not (
+ Claims.Private.CreationDate or
+ Claims.Private.ExpirationDate or
+ Claims.Private.TokenType));
if (principal is null)
{
@@ -3657,14 +3639,10 @@ namespace OpenIddict.Server
}
// Clone the principal and exclude the claim mapped to standard JWT claims.
- var principal = context.UserCodePrincipal.Clone(claim => claim.Type switch
- {
- Claims.Private.CreationDate => false,
- Claims.Private.ExpirationDate => false,
- Claims.Private.TokenType => false,
-
- _ => true
- });
+ var principal = context.UserCodePrincipal.Clone(claim => claim.Type is not (
+ Claims.Private.CreationDate or
+ Claims.Private.ExpirationDate or
+ Claims.Private.TokenType));
if (principal is null)
{
@@ -3883,43 +3861,40 @@ namespace OpenIddict.Server
{
var algorithm = credentials.Digest switch
{
- SecurityAlgorithms.Sha256 => HashAlgorithmName.SHA256,
- SecurityAlgorithms.Sha384 => HashAlgorithmName.SHA384,
- SecurityAlgorithms.Sha512 => HashAlgorithmName.SHA512,
- SecurityAlgorithms.Sha256Digest => HashAlgorithmName.SHA256,
- SecurityAlgorithms.Sha384Digest => HashAlgorithmName.SHA384,
- SecurityAlgorithms.Sha512Digest => HashAlgorithmName.SHA512,
+ SecurityAlgorithms.Sha256 or SecurityAlgorithms.Sha256Digest => HashAlgorithmName.SHA256,
+ SecurityAlgorithms.Sha384 or SecurityAlgorithms.Sha384Digest => HashAlgorithmName.SHA384,
+ SecurityAlgorithms.Sha512 or SecurityAlgorithms.Sha512Digest => HashAlgorithmName.SHA512,
_ => credentials.Algorithm switch
{
#if SUPPORTS_ECDSA
- SecurityAlgorithms.EcdsaSha256 => HashAlgorithmName.SHA256,
- SecurityAlgorithms.EcdsaSha384 => HashAlgorithmName.SHA384,
- SecurityAlgorithms.EcdsaSha512 => HashAlgorithmName.SHA512,
- SecurityAlgorithms.EcdsaSha256Signature => HashAlgorithmName.SHA256,
- SecurityAlgorithms.EcdsaSha384Signature => HashAlgorithmName.SHA384,
- SecurityAlgorithms.EcdsaSha512Signature => HashAlgorithmName.SHA512,
+ SecurityAlgorithms.EcdsaSha256 or SecurityAlgorithms.EcdsaSha256Signature
+ => HashAlgorithmName.SHA256,
+ SecurityAlgorithms.EcdsaSha384 or SecurityAlgorithms.EcdsaSha384Signature
+ => HashAlgorithmName.SHA384,
+ SecurityAlgorithms.EcdsaSha512 or SecurityAlgorithms.EcdsaSha512Signature
+ => HashAlgorithmName.SHA512,
#endif
- SecurityAlgorithms.HmacSha256 => HashAlgorithmName.SHA256,
- SecurityAlgorithms.HmacSha384 => HashAlgorithmName.SHA384,
- SecurityAlgorithms.HmacSha512 => HashAlgorithmName.SHA512,
- SecurityAlgorithms.HmacSha256Signature => HashAlgorithmName.SHA256,
- SecurityAlgorithms.HmacSha384Signature => HashAlgorithmName.SHA384,
- SecurityAlgorithms.HmacSha512Signature => HashAlgorithmName.SHA512,
-
- SecurityAlgorithms.RsaSha256 => HashAlgorithmName.SHA256,
- SecurityAlgorithms.RsaSha384 => HashAlgorithmName.SHA384,
- SecurityAlgorithms.RsaSha512 => HashAlgorithmName.SHA512,
- SecurityAlgorithms.RsaSha256Signature => HashAlgorithmName.SHA256,
- SecurityAlgorithms.RsaSha384Signature => HashAlgorithmName.SHA384,
- SecurityAlgorithms.RsaSha512Signature => HashAlgorithmName.SHA512,
-
- SecurityAlgorithms.RsaSsaPssSha256 => HashAlgorithmName.SHA256,
- SecurityAlgorithms.RsaSsaPssSha384 => HashAlgorithmName.SHA384,
- SecurityAlgorithms.RsaSsaPssSha512 => HashAlgorithmName.SHA512,
- SecurityAlgorithms.RsaSsaPssSha256Signature => HashAlgorithmName.SHA256,
- SecurityAlgorithms.RsaSsaPssSha384Signature => HashAlgorithmName.SHA384,
- SecurityAlgorithms.RsaSsaPssSha512Signature => HashAlgorithmName.SHA512,
+ SecurityAlgorithms.HmacSha256 or SecurityAlgorithms.HmacSha256Signature
+ => HashAlgorithmName.SHA256,
+ SecurityAlgorithms.HmacSha384 or SecurityAlgorithms.HmacSha384Signature
+ => HashAlgorithmName.SHA384,
+ SecurityAlgorithms.HmacSha512 or SecurityAlgorithms.HmacSha512Signature
+ => HashAlgorithmName.SHA512,
+
+ SecurityAlgorithms.RsaSha256 or SecurityAlgorithms.RsaSha256Signature
+ => HashAlgorithmName.SHA256,
+ SecurityAlgorithms.RsaSha384 or SecurityAlgorithms.RsaSha384Signature
+ => HashAlgorithmName.SHA384,
+ SecurityAlgorithms.RsaSha512 or SecurityAlgorithms.RsaSha512Signature
+ => HashAlgorithmName.SHA512,
+
+ SecurityAlgorithms.RsaSsaPssSha256 or SecurityAlgorithms.RsaSsaPssSha256Signature
+ => HashAlgorithmName.SHA256,
+ SecurityAlgorithms.RsaSsaPssSha384 or SecurityAlgorithms.RsaSsaPssSha384Signature
+ => HashAlgorithmName.SHA384,
+ SecurityAlgorithms.RsaSsaPssSha512 or SecurityAlgorithms.RsaSsaPssSha512Signature
+ => HashAlgorithmName.SHA512,
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0267))
}
@@ -4053,15 +4028,11 @@ namespace OpenIddict.Server
}
// Clone the principal and exclude the claim mapped to standard JWT claims.
- var principal = context.IdentityTokenPrincipal.Clone(claim => claim.Type switch
- {
- Claims.Private.Audience => false,
- Claims.Private.CreationDate => false,
- Claims.Private.ExpirationDate => false,
- Claims.Private.TokenType => false,
-
- _ => true
- });
+ var principal = context.IdentityTokenPrincipal.Clone(claim => claim.Type is not (
+ Claims.Private.Audience or
+ Claims.Private.CreationDate or
+ Claims.Private.ExpirationDate or
+ Claims.Private.TokenType));
if (principal is null)
{
diff --git a/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs b/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
index 1fed4b76..ba56ccd6 100644
--- a/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
+++ b/src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
@@ -372,11 +372,9 @@ namespace OpenIddict.Validation.AspNetCore
{
null => 200,
- Errors.InvalidToken => 401,
- Errors.MissingToken => 401,
+ Errors.InvalidToken or Errors.MissingToken => 401,
- Errors.InsufficientAccess => 403,
- Errors.InsufficientScope => 403,
+ Errors.InsufficientAccess or Errors.InsufficientScope => 403,
_ => 400
};
@@ -469,10 +467,10 @@ namespace OpenIddict.Validation.AspNetCore
var scheme = context.Transaction.Response.Error switch
{
- Errors.InvalidToken => Schemes.Bearer,
- Errors.MissingToken => Schemes.Bearer,
- Errors.InsufficientAccess => Schemes.Bearer,
- Errors.InsufficientScope => Schemes.Bearer,
+ Errors.InvalidToken or
+ Errors.MissingToken or
+ Errors.InsufficientAccess or
+ Errors.InsufficientScope => Schemes.Bearer,
_ => null
};
diff --git a/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs b/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs
index ae91c96c..c63bbad8 100644
--- a/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs
+++ b/src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs
@@ -374,11 +374,9 @@ namespace OpenIddict.Validation.Owin
{
null => 200,
- Errors.InvalidToken => 401,
- Errors.MissingToken => 401,
+ Errors.InvalidToken or Errors.MissingToken => 401,
- Errors.InsufficientAccess => 403,
- Errors.InsufficientScope => 403,
+ Errors.InsufficientAccess or Errors.InsufficientScope => 403,
_ => 400
};
@@ -476,10 +474,10 @@ namespace OpenIddict.Validation.Owin
var scheme = context.Transaction.Response.Error switch
{
- Errors.InvalidToken => Schemes.Bearer,
- Errors.MissingToken => Schemes.Bearer,
- Errors.InsufficientAccess => Schemes.Bearer,
- Errors.InsufficientScope => Schemes.Bearer,
+ Errors.InvalidToken or
+ Errors.MissingToken or
+ Errors.InsufficientAccess or
+ Errors.InsufficientScope => Schemes.Bearer,
_ => null
};
diff --git a/src/OpenIddict.Validation/OpenIddictValidationHandlers.Introspection.cs b/src/OpenIddict.Validation/OpenIddictValidationHandlers.Introspection.cs
index 51c63305..96c77331 100644
--- a/src/OpenIddict.Validation/OpenIddictValidationHandlers.Introspection.cs
+++ b/src/OpenIddict.Validation/OpenIddictValidationHandlers.Introspection.cs
@@ -176,7 +176,7 @@ namespace OpenIddict.Validation
foreach (var parameter in context.Response.GetParameters())
{
- if (ValidateClaimType(parameter.Key, parameter.Value))
+ if (ValidateClaimType(parameter.Key, parameter.Value.Value))
{
continue;
}
@@ -190,66 +190,26 @@ namespace OpenIddict.Validation
return default;
- static bool ValidateClaimType(string name, OpenIddictParameter value)
+ static bool ValidateClaimType(string name, object? value) => name switch
{
- switch ((name, value.Value))
- {
- // The 'aud' claim CAN be represented either as a unique string or as an array of multiple strings.
- case (Claims.Audience, string _):
- case (Claims.Audience, string[] _):
- case (Claims.Audience, JsonElement element) when element.ValueKind == JsonValueKind.String ||
- (element.ValueKind == JsonValueKind.Array && ValidateArrayChildren(element, JsonValueKind.String)):
- return true;
-
- // The 'exp', 'iat' and 'nbf' claims MUST be formatted as numeric date values.
- case (Claims.ExpiresAt, long _):
- case (Claims.ExpiresAt, JsonElement element) when element.ValueKind == JsonValueKind.Number:
- return true;
-
- case (Claims.IssuedAt, long _):
- case (Claims.IssuedAt, JsonElement element) when element.ValueKind == JsonValueKind.Number:
- return true;
-
- case (Claims.NotBefore, long _):
- case (Claims.NotBefore, JsonElement element) when element.ValueKind == JsonValueKind.Number:
- return true;
-
- // The 'jti' claim MUST be formatted as a unique string.
- case (Claims.JwtId, string _):
- case (Claims.JwtId, JsonElement element) when element.ValueKind == JsonValueKind.String:
- return true;
-
- // The 'iss' claim MUST be formatted as a unique string.
- case (Claims.Issuer, string _):
- case (Claims.Issuer, JsonElement element) when element.ValueKind == JsonValueKind.String:
- return true;
-
- // The 'scope' claim MUST be formatted as a unique string.
- case (Claims.Scope, string _):
- case (Claims.Scope, JsonElement element) when element.ValueKind == JsonValueKind.String:
- return true;
-
- // The 'token_usage' claim MUST be formatted as a unique string.
- case (Claims.TokenUsage, string _):
- case (Claims.TokenUsage, JsonElement element) when element.ValueKind == JsonValueKind.String:
- return true;
-
- // If the previously listed claims are represented differently,
- // return false to indicate the claims validation logic failed.
- case (Claims.Audience, _):
- case (Claims.ExpiresAt, _):
- case (Claims.IssuedAt, _):
- case (Claims.Issuer, _):
- case (Claims.NotBefore, _):
- case (Claims.JwtId, _):
- case (Claims.Scope, _):
- case (Claims.TokenUsage, _):
- return false;
-
- // Claims that are not in the well-known list can be of any type.
- default: return true;
- }
- }
+ // The 'aud' claim MUST be represented either as a unique string or as an array of multiple strings.
+ Claims.Audience when value is string or string[] => true,
+ Claims.Audience when value is JsonElement { ValueKind: JsonValueKind.String } => true,
+ Claims.Audience when value is JsonElement { ValueKind: JsonValueKind.Array } element &&
+ ValidateArrayChildren(element, JsonValueKind.String) => true,
+ Claims.Audience => false,
+
+ // The 'exp', 'iat' and 'nbf' claims MUST be formatted as numeric date values.
+ Claims.ExpiresAt or Claims.IssuedAt or Claims.NotBefore
+ => value is long or JsonElement { ValueKind: JsonValueKind.Number },
+
+ // The 'jti', 'iss', 'scope' and 'token_usage' claims MUST be formatted as a unique string.
+ Claims.JwtId or Claims.Issuer or Claims.Scope or Claims.TokenUsage
+ => value is string or JsonElement { ValueKind: JsonValueKind.String },
+
+ // Claims that are not in the well-known list can be of any type.
+ _ => true
+ };
static bool ValidateArrayChildren(JsonElement element, JsonValueKind kind)
{
@@ -411,27 +371,26 @@ namespace OpenIddict.Validation
continue;
}
- switch ((name: parameter.Key, value: parameter.Value.Value))
+ // Ignore all protocol claims that shouldn't be mapped to CLR claims.
+ if (parameter.Key is Claims.Active or Claims.Issuer or Claims.NotBefore or
+ Claims.TokenType or Claims.TokenUsage)
{
- // Ignore all protocol claims that are not mapped to CLR claims.
- case (Claims.Active, _):
- case (Claims.Issuer, _):
- case (Claims.NotBefore, _):
- case (Claims.TokenType, _):
- case (Claims.TokenUsage, _):
- continue;
+ continue;
+ }
+ switch (parameter.Value.Value)
+ {
// Claims represented as arrays are split and mapped to multiple CLR claims.
- case (var name, JsonElement value) when value.ValueKind == JsonValueKind.Array:
+ case JsonElement { ValueKind: JsonValueKind.Array } value:
foreach (var element in value.EnumerateArray())
{
- identity.AddClaim(new Claim(name, element.ToString(),
+ identity.AddClaim(new Claim(parameter.Key, element.ToString(),
GetClaimValueType(value.ValueKind), issuer, issuer, identity));
}
break;
- case (var name, JsonElement value):
- identity.AddClaim(new Claim(name, value.ToString(),
+ case JsonElement value:
+ identity.AddClaim(new Claim(parameter.Key, value.ToString(),
GetClaimValueType(value.ValueKind), issuer, issuer, identity));
break;
@@ -440,24 +399,25 @@ namespace OpenIddict.Validation
// However, to support responses resolved from custom locations and parameters manually added
// by the application using the events model, the CLR primitive types are also supported.
- case (var name, bool value):
- identity.AddClaim(new Claim(name, value.ToString(), ClaimValueTypes.Boolean, issuer, issuer, identity));
+ case bool value:
+ identity.AddClaim(new Claim(parameter.Key, value.ToString(),
+ ClaimValueTypes.Boolean, issuer, issuer, identity));
break;
- case (var name, long value):
- identity.AddClaim(new Claim(name, value.ToString(CultureInfo.InvariantCulture),
+ case long value:
+ identity.AddClaim(new Claim(parameter.Key, value.ToString(CultureInfo.InvariantCulture),
ClaimValueTypes.Integer64, issuer, issuer, identity));
break;
- case (var name, string value):
- identity.AddClaim(new Claim(name, value, ClaimValueTypes.String, issuer, issuer, identity));
+ case string value:
+ identity.AddClaim(new Claim(parameter.Key, value, ClaimValueTypes.String, issuer, issuer, identity));
break;
// Claims represented as arrays are split and mapped to multiple CLR claims.
- case (var name, string[] value):
+ case string[] value:
for (var index = 0; index < value.Length; index++)
{
- identity.AddClaim(new Claim(name, value[index], ClaimValueTypes.String, issuer, issuer, identity));
+ identity.AddClaim(new Claim(parameter.Key, value[index], ClaimValueTypes.String, issuer, issuer, identity));
}
break;
}
@@ -469,15 +429,13 @@ namespace OpenIddict.Validation
static string GetClaimValueType(JsonValueKind kind) => kind switch
{
- JsonValueKind.True => ClaimValueTypes.Boolean,
- JsonValueKind.False => ClaimValueTypes.Boolean,
+ JsonValueKind.True or JsonValueKind.False => ClaimValueTypes.Boolean,
+
JsonValueKind.String => ClaimValueTypes.String,
JsonValueKind.Number => ClaimValueTypes.Integer64,
- JsonValueKind.Array => JsonClaimValueTypes.JsonArray,
- JsonValueKind.Object => JsonClaimValueTypes.Json,
-
- _ => JsonClaimValueTypes.Json
+ JsonValueKind.Array => JsonClaimValueTypes.JsonArray,
+ JsonValueKind.Object or _ => JsonClaimValueTypes.Json
};
}
}
diff --git a/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs b/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs
index d7c3c350..9cbe75a1 100644
--- a/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs
+++ b/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs
@@ -220,7 +220,7 @@ namespace OpenIddict.Validation
{
// If no specific token type is expected, accept all token types at this stage.
// Additional filtering can be made based on the resolved/actual token type.
- var type when string.IsNullOrEmpty(type) => null,
+ null or { Length: 0 } => null,
// For access tokens, both "at+jwt" and "application/at+jwt" are valid.
TokenTypeHints.AccessToken => new[]
@@ -265,10 +265,11 @@ namespace OpenIddict.Validation
// Store the token type (resolved from "typ" or "token_usage") as a special private claim.
context.Principal.SetTokenType(result.TokenType switch
{
- var type when string.IsNullOrEmpty(type) => throw new InvalidOperationException(SR.GetResourceString(SR.ID0025)),
+ null or { Length: 0 } => throw new InvalidOperationException(SR.GetResourceString(SR.ID0025)),
- JsonWebTokenTypes.AccessToken => TokenTypeHints.AccessToken,
- JsonWebTokenTypes.Prefixes.Application + JsonWebTokenTypes.AccessToken => TokenTypeHints.AccessToken,
+ // Both at+jwt and application/at+jwt are supported for access tokens.
+ JsonWebTokenTypes.AccessToken or JsonWebTokenTypes.Prefixes.Application + JsonWebTokenTypes.AccessToken
+ => TokenTypeHints.AccessToken,
_ => throw new InvalidOperationException(SR.GetResourceString(SR.ID0003))
});
diff --git a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictMessageTests.cs b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictMessageTests.cs
index 008f910b..d192f982 100644
--- a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictMessageTests.cs
+++ b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictMessageTests.cs
@@ -18,24 +18,6 @@ namespace OpenIddict.Abstractions.Tests.Primitives
{
public class OpenIddictMessageTests
{
- [Theory]
- [InlineData(null)]
- [InlineData("")]
- public void Constructor_ThrowsAnExceptionForNullOrEmptyParameterNames(string name)
- {
- // Arrange, act and assert
- var exception = Assert.Throws(delegate
- {
- return new OpenIddictMessage(new[]
- {
- new KeyValuePair(name, "Fabrikam")
- });
- });
-
- Assert.Equal("name", exception.ParamName);
- Assert.StartsWith(SR.GetResourceString(SR.ID0190), exception.Message);
- }
-
[Fact]
public void Constructor_ThrowsAnExceptionForInvalidJsonElement()
{
@@ -79,6 +61,21 @@ namespace OpenIddict.Abstractions.Tests.Primitives
Assert.Equal(42, (long) message.GetParameter("parameter"));
}
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void Constructor_IgnoresNullOrEmptyParameterNames(string name)
+ {
+ // Arrange and act
+ var message = new OpenIddictMessage(new[]
+ {
+ new KeyValuePair(name, "Fabrikam")
+ });
+
+ // Assert
+ Assert.Equal(0, message.Count);
+ }
+
[Fact]
public void Constructor_PreservesEmptyParameters()
{
@@ -94,7 +91,7 @@ namespace OpenIddict.Abstractions.Tests.Primitives
}
[Fact]
- public void Constructor_AllowsDuplicateParameters()
+ public void Constructor_CombinesDuplicateParameters()
{
// Arrange and act
var message = new OpenIddictMessage(new[]