diff --git a/samples/Mvc.Server/Controllers/AuthorizationController.cs b/samples/Mvc.Server/Controllers/AuthorizationController.cs
index 7623bd8f..2b9d07c0 100644
--- a/samples/Mvc.Server/Controllers/AuthorizationController.cs
+++ b/samples/Mvc.Server/Controllers/AuthorizationController.cs
@@ -191,7 +191,7 @@ namespace Mvc.Server
scopes : principal.GetScopes());
}
- principal.SetInternalAuthorizationId(await _authorizationManager.GetIdAsync(authorization));
+ principal.SetAuthorizationId(await _authorizationManager.GetIdAsync(authorization));
foreach (var claim in principal.Claims)
{
@@ -281,7 +281,7 @@ namespace Mvc.Server
scopes : principal.GetScopes());
}
- principal.SetInternalAuthorizationId(await _authorizationManager.GetIdAsync(authorization));
+ principal.SetAuthorizationId(await _authorizationManager.GetIdAsync(authorization));
foreach (var claim in principal.Claims)
{
diff --git a/src/OpenIddict.Abstractions/OpenIddictConstants.cs b/src/OpenIddict.Abstractions/OpenIddictConstants.cs
index 8685ea27..5bdb04ef 100644
--- a/src/OpenIddict.Abstractions/OpenIddictConstants.cs
+++ b/src/OpenIddict.Abstractions/OpenIddictConstants.cs
@@ -88,13 +88,16 @@ namespace OpenIddict.Abstractions
public static class Private
{
public const string AccessTokenLifetime = "oi_act_lft";
- public const string AuthorizationId = "oi_au_id";
+ public const string Audience = "oi_aud";
public const string AuthorizationCodeLifetime = "oi_auc_lft";
+ public const string AuthorizationId = "oi_au_id";
public const string ClaimDestinationsMap = "oi_cl_dstn";
public const string CodeChallenge = "oi_cd_chlg";
public const string CodeChallengeMethod = "oi_cd_chlg_meth";
+ public const string CreationDate = "oi_crt_dt";
public const string DeviceCodeId = "oi_dvc_id";
public const string DeviceCodeLifetime = "oi_dvc_lft";
+ public const string ExpirationDate = "oi_exp_dt";
public const string IdentityTokenLifetime = "oi_idt_lft";
public const string Nonce = "oi_nce";
public const string Presenter = "oi_prst";
diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs
index 83c4660d..a72e24a0 100644
--- a/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs
+++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictExtensions.cs
@@ -903,6 +903,27 @@ namespace OpenIddict.Abstractions
return identity.FindAll(type).Select(claim => claim.Value).Distinct(StringComparer.Ordinal).ToImmutableArray();
}
+ ///
+ /// Determines whether the claims identity contains at least one claim of the specified type.
+ ///
+ /// The claims identity.
+ /// The claim type.
+ /// true if the identity contains at least one claim of the specified type.
+ public static bool HasClaim([NotNull] this ClaimsIdentity identity, [NotNull] string type)
+ {
+ if (identity == null)
+ {
+ throw new ArgumentNullException(nameof(identity));
+ }
+
+ if (string.IsNullOrEmpty(type))
+ {
+ throw new ArgumentException("The claim type cannot be null or empty.", nameof(type));
+ }
+
+ return identity.FindAll(type).Any();
+ }
+
///
/// Gets the claim values corresponding to the given type.
///
@@ -924,6 +945,27 @@ namespace OpenIddict.Abstractions
return principal.FindAll(type).Select(claim => claim.Value).Distinct(StringComparer.Ordinal).ToImmutableArray();
}
+ ///
+ /// Determines whether the claims principal contains at least one claim of the specified type.
+ ///
+ /// The claims principal.
+ /// The claim type.
+ /// true if the principal contains at least one claim of the specified type.
+ public static bool HasClaim([NotNull] this ClaimsPrincipal principal, [NotNull] string type)
+ {
+ if (principal == null)
+ {
+ throw new ArgumentNullException(nameof(principal));
+ }
+
+ if (string.IsNullOrEmpty(type))
+ {
+ throw new ArgumentException("The claim type cannot be null or empty.", nameof(type));
+ }
+
+ return principal.FindAll(type).Any();
+ }
+
///
/// Removes all the claims corresponding to the given type.
///
@@ -1113,18 +1155,18 @@ namespace OpenIddict.Abstractions
throw new ArgumentNullException(nameof(principal));
}
- var claim = principal.FindFirst(Claims.IssuedAt);
+ var claim = principal.FindFirst(Claims.Private.CreationDate);
if (claim == null)
{
return null;
}
- if (!long.TryParse(claim.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
+ if (!DateTimeOffset.TryParseExact(claim.Value, "r", CultureInfo.InvariantCulture, DateTimeStyles.None, out var value))
{
return null;
}
- return DateTimeOffset.FromUnixTimeSeconds(value);
+ return value;
}
///
@@ -1139,18 +1181,18 @@ namespace OpenIddict.Abstractions
throw new ArgumentNullException(nameof(principal));
}
- var claim = principal.FindFirst(Claims.ExpiresAt);
+ var claim = principal.FindFirst(Claims.Private.ExpirationDate);
if (claim == null)
{
return null;
}
- if (!long.TryParse(claim.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
+ if (!DateTimeOffset.TryParseExact(claim.Value, "r", CultureInfo.InvariantCulture, DateTimeStyles.None, out var value))
{
return null;
}
- return DateTimeOffset.FromUnixTimeSeconds(value);
+ return value;
}
///
@@ -1159,7 +1201,7 @@ namespace OpenIddict.Abstractions
/// The claims principal.
/// The audiences list or an empty set if the claims cannot be found.
public static ImmutableArray GetAudiences([NotNull] this ClaimsPrincipal principal)
- => principal.GetClaims(Claims.Audience);
+ => principal.GetClaims(Claims.Private.Audience);
///
/// Gets the presenters list stored in the claims principal.
@@ -1238,7 +1280,7 @@ namespace OpenIddict.Abstractions
///
/// The claims principal.
/// The unique identifier or null if the claim cannot be found.
- public static string GetInternalAuthorizationId([NotNull] this ClaimsPrincipal principal)
+ public static string GetAuthorizationId([NotNull] this ClaimsPrincipal principal)
=> principal.GetClaim(Claims.Private.AuthorizationId);
///
@@ -1246,7 +1288,7 @@ namespace OpenIddict.Abstractions
///
/// The claims principal.
/// The unique identifier or null if the claim cannot be found.
- public static string GetInternalTokenId([NotNull] this ClaimsPrincipal principal)
+ public static string GetTokenId([NotNull] this ClaimsPrincipal principal)
=> principal.GetClaim(Claims.Private.TokenId);
///
@@ -1263,14 +1305,7 @@ namespace OpenIddict.Abstractions
/// The claims principal.
/// true if the principal contains at least one audience.
public static bool HasAudience([NotNull] this ClaimsPrincipal principal)
- {
- if (principal == null)
- {
- throw new ArgumentNullException(nameof(principal));
- }
-
- return principal.FindAll(Claims.Audience).Any();
- }
+ => principal.HasClaim(Claims.Private.Audience);
///
/// Determines whether the claims principal contains the given audience.
@@ -1290,7 +1325,7 @@ namespace OpenIddict.Abstractions
throw new ArgumentException("The audience cannot be null or empty.", nameof(audience));
}
- return principal.HasClaim(Claims.Audience, audience);
+ return principal.HasClaim(Claims.Private.Audience, audience);
}
///
@@ -1299,14 +1334,7 @@ namespace OpenIddict.Abstractions
/// The claims principal.
/// true if the principal contains at least one presenter.
public static bool HasPresenter([NotNull] this ClaimsPrincipal principal)
- {
- if (principal == null)
- {
- throw new ArgumentNullException(nameof(principal));
- }
-
- return principal.FindAll(Claims.Private.Presenter).Any();
- }
+ => principal.HasClaim(Claims.Private.Presenter);
///
/// Determines whether the claims principal contains the given presenter.
@@ -1335,14 +1363,7 @@ namespace OpenIddict.Abstractions
/// The claims principal.
/// true if the principal contains at least one resource.
public static bool HasResource([NotNull] this ClaimsPrincipal principal)
- {
- if (principal == null)
- {
- throw new ArgumentNullException(nameof(principal));
- }
-
- return principal.FindAll(Claims.Private.Resource).Any();
- }
+ => principal.HasClaim(Claims.Private.Resource);
///
/// Determines whether the claims principal contains the given resource.
@@ -1371,14 +1392,7 @@ namespace OpenIddict.Abstractions
/// The claims principal.
/// true if the principal contains at least one scope.
public static bool HasScope([NotNull] this ClaimsPrincipal principal)
- {
- if (principal == null)
- {
- throw new ArgumentNullException(nameof(principal));
- }
-
- return principal.FindAll(Claims.Private.Scope).Any();
- }
+ => principal.HasClaim(Claims.Private.Scope);
///
/// Determines whether the claims principal contains the given scope.
@@ -1429,7 +1443,7 @@ namespace OpenIddict.Abstractions
/// The creation date
/// The claims principal.
public static ClaimsPrincipal SetCreationDate([NotNull] this ClaimsPrincipal principal, [CanBeNull] DateTimeOffset? date)
- => SetDateClaim(principal, Claims.IssuedAt, date);
+ => principal.SetClaim(Claims.Private.CreationDate, date?.ToString("r", CultureInfo.InvariantCulture));
///
/// Sets the expiration date in the claims principal.
@@ -1438,7 +1452,7 @@ namespace OpenIddict.Abstractions
/// The expiration date
/// The claims principal.
public static ClaimsPrincipal SetExpirationDate([NotNull] this ClaimsPrincipal principal, [CanBeNull] DateTimeOffset? date)
- => SetDateClaim(principal, Claims.ExpiresAt, date);
+ => principal.SetClaim(Claims.Private.ExpirationDate, date?.ToString("r", CultureInfo.InvariantCulture));
///
/// Sets the audiences list in the claims principal.
@@ -1449,7 +1463,7 @@ namespace OpenIddict.Abstractions
/// The claims principal.
public static ClaimsPrincipal SetAudiences(
[NotNull] this ClaimsPrincipal principal, [CanBeNull] ImmutableArray audiences)
- => principal.SetClaims(Claims.Audience, audiences);
+ => principal.SetClaims(Claims.Private.Audience, audiences);
///
/// Sets the audiences list in the claims principal.
@@ -1632,7 +1646,7 @@ namespace OpenIddict.Abstractions
/// The claims principal.
/// The unique identifier to store.
/// The claims principal.
- public static ClaimsPrincipal SetInternalAuthorizationId([NotNull] this ClaimsPrincipal principal, string identifier)
+ public static ClaimsPrincipal SetAuthorizationId([NotNull] this ClaimsPrincipal principal, string identifier)
=> principal.SetClaim(Claims.Private.AuthorizationId, identifier);
///
@@ -1641,7 +1655,7 @@ namespace OpenIddict.Abstractions
/// The claims principal.
/// The unique identifier to store.
/// The claims principal.
- public static ClaimsPrincipal SetInternalTokenId([NotNull] this ClaimsPrincipal principal, string identifier)
+ public static ClaimsPrincipal SetTokenId([NotNull] this ClaimsPrincipal principal, string identifier)
=> principal.SetClaim(Claims.Private.TokenId, identifier);
///
@@ -1779,24 +1793,5 @@ namespace OpenIddict.Abstractions
return null;
}
-
- private static ClaimsPrincipal SetDateClaim(ClaimsPrincipal principal, string type, DateTimeOffset? date)
- {
- if (principal == null)
- {
- throw new ArgumentNullException(nameof(principal));
- }
-
- principal.RemoveClaims(type);
-
- if (date.HasValue)
- {
- var value = date?.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture);
- var claim = new Claim(type, value, ClaimValueTypes.Integer64);
- ((ClaimsIdentity)principal.Identity).AddClaim(claim);
- }
-
- return principal;
- }
}
}
diff --git a/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionConstants.cs b/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionConstants.cs
index 2ec90bba..c37539d8 100644
--- a/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionConstants.cs
+++ b/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionConstants.cs
@@ -16,6 +16,8 @@ namespace OpenIddict.Server.DataProtection
public const string CodeChallenge = ".code_challenge";
public const string CodeChallengeMethod = ".code_challenge_method";
public const string DataProtector = ".data_protector";
+ public const string DeviceCodeId = ".device_code_id";
+ public const string DeviceCodeLifetime = ".device_code_lifetime";
public const string Expires = ".expires";
public const string IdentityTokenLifetime = ".identity_token_lifetime";
public const string InternalAuthorizationId = ".internal_authorization_id";
@@ -27,6 +29,7 @@ namespace OpenIddict.Server.DataProtection
public const string RefreshTokenLifetime = ".refresh_token_lifetime";
public const string Resources = ".resources";
public const string Scopes = ".scopes";
+ public const string UserCodeLifetime = ".user_code_lifetime";
}
public static class Purposes
diff --git a/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs b/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs
index d8a0947d..8a8a2c4a 100644
--- a/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs
+++ b/src/OpenIddict.Server.DataProtection/OpenIddictServerDataProtectionFormatter.cs
@@ -7,7 +7,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
-using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Claims;
@@ -41,8 +40,6 @@ namespace OpenIddict.Server.DataProtection
return principal
.SetAudiences(GetArrayProperty(properties, Properties.Audiences))
- .SetCreationDate(GetDateProperty(properties, Properties.Issued))
- .SetExpirationDate(GetDateProperty(properties, Properties.Expires))
.SetPresenters(GetArrayProperty(properties, Properties.Presenters))
.SetResources(GetArrayProperty(properties, Properties.Resources))
.SetScopes(GetArrayProperty(properties, Properties.Scopes))
@@ -52,11 +49,16 @@ namespace OpenIddict.Server.DataProtection
.SetClaim(Claims.Private.AuthorizationId, GetProperty(properties, Properties.InternalAuthorizationId))
.SetClaim(Claims.Private.CodeChallenge, GetProperty(properties, Properties.CodeChallenge))
.SetClaim(Claims.Private.CodeChallengeMethod, GetProperty(properties, Properties.CodeChallengeMethod))
+ .SetClaim(Claims.Private.CreationDate, GetProperty(properties, Properties.Issued))
+ .SetClaim(Claims.Private.DeviceCodeId, GetProperty(properties, Properties.DeviceCodeId))
+ .SetClaim(Claims.Private.DeviceCodeLifetime, GetProperty(properties, Properties.DeviceCodeLifetime))
.SetClaim(Claims.Private.IdentityTokenLifetime, GetProperty(properties, Properties.IdentityTokenLifetime))
+ .SetClaim(Claims.Private.ExpirationDate, GetProperty(properties, Properties.Expires))
.SetClaim(Claims.Private.Nonce, GetProperty(properties, Properties.Nonce))
.SetClaim(Claims.Private.RedirectUri, GetProperty(properties, Properties.OriginalRedirectUri))
.SetClaim(Claims.Private.RefreshTokenLifetime, GetProperty(properties, Properties.RefreshTokenLifetime))
- .SetClaim(Claims.Private.TokenId, GetProperty(properties, Properties.InternalTokenId));
+ .SetClaim(Claims.Private.TokenId, GetProperty(properties, Properties.InternalTokenId))
+ .SetClaim(Claims.Private.UserCodeLifetime, GetProperty(properties, Properties.UserCodeLifetime));
static (ClaimsPrincipal principal, ImmutableDictionary properties) Read(BinaryReader reader, int version)
{
@@ -177,10 +179,6 @@ namespace OpenIddict.Server.DataProtection
static ImmutableArray GetArrayProperty(IReadOnlyDictionary properties, string name)
=> properties.TryGetValue(name, out var value) ?
JsonSerializer.Deserialize>(value) : ImmutableArray.Create();
-
- static DateTimeOffset? GetDateProperty(IReadOnlyDictionary properties, string name)
- => properties.TryGetValue(name, out var value) ? (DateTimeOffset?)
- DateTimeOffset.ParseExact(value, "r", CultureInfo.InvariantCulture) : null;
}
public void WriteToken([NotNull] BinaryWriter writer, [NotNull] ClaimsPrincipal principal)
@@ -201,20 +199,23 @@ namespace OpenIddict.Server.DataProtection
// can't include authentication properties. To ensure tokens can be used with previous versions
// of OpenIddict (1.x/2.x), well-known claims are manually mapped to their properties equivalents.
- SetProperty(properties, Properties.Issued, principal.GetCreationDate()?.ToString("r", CultureInfo.InvariantCulture));
- SetProperty(properties, Properties.Expires, principal.GetExpirationDate()?.ToString("r", CultureInfo.InvariantCulture));
+ SetProperty(properties, Properties.Issued, principal.GetClaim(Claims.Private.CreationDate));
+ SetProperty(properties, Properties.Expires, principal.GetClaim(Claims.Private.ExpirationDate));
SetProperty(properties, Properties.AccessTokenLifetime, principal.GetClaim(Claims.Private.AccessTokenLifetime));
SetProperty(properties, Properties.AuthorizationCodeLifetime, principal.GetClaim(Claims.Private.AuthorizationCodeLifetime));
+ SetProperty(properties, Properties.DeviceCodeLifetime, principal.GetClaim(Claims.Private.DeviceCodeLifetime));
SetProperty(properties, Properties.IdentityTokenLifetime, principal.GetClaim(Claims.Private.IdentityTokenLifetime));
SetProperty(properties, Properties.RefreshTokenLifetime, principal.GetClaim(Claims.Private.RefreshTokenLifetime));
+ SetProperty(properties, Properties.UserCodeLifetime, principal.GetClaim(Claims.Private.UserCodeLifetime));
SetProperty(properties, Properties.CodeChallenge, principal.GetClaim(Claims.Private.CodeChallenge));
SetProperty(properties, Properties.CodeChallengeMethod, principal.GetClaim(Claims.Private.CodeChallengeMethod));
- SetProperty(properties, Properties.InternalAuthorizationId, principal.GetInternalAuthorizationId());
- SetProperty(properties, Properties.InternalTokenId, principal.GetInternalTokenId());
+ SetProperty(properties, Properties.InternalAuthorizationId, principal.GetAuthorizationId());
+ SetProperty(properties, Properties.InternalTokenId, principal.GetTokenId());
+ SetProperty(properties, Properties.DeviceCodeId, principal.GetClaim(Claims.Private.DeviceCodeId));
SetProperty(properties, Properties.Nonce, principal.GetClaim(Claims.Private.Nonce));
SetProperty(properties, Properties.OriginalRedirectUri, principal.GetClaim(Claims.Private.RedirectUri));
@@ -226,15 +227,16 @@ namespace OpenIddict.Server.DataProtection
// Copy the principal and exclude the claim that were mapped to authentication properties.
principal = principal.Clone(claim => claim.Type switch
{
- Claims.Audience => false,
- Claims.ExpiresAt => false,
- Claims.IssuedAt => false,
-
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,
@@ -243,6 +245,7 @@ namespace OpenIddict.Server.DataProtection
Claims.Private.Resource => false,
Claims.Private.Scope => false,
Claims.Private.TokenId => false,
+ Claims.Private.UserCodeLifetime => false,
_ => true
});
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs
index 4cc3acc5..0b42edaf 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs
@@ -997,7 +997,7 @@ namespace OpenIddict.Server
}
// Extract the token identifier from the authentication principal.
- var identifier = context.Principal.GetInternalTokenId();
+ var identifier = context.Principal.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
context.Logger.LogError("The revocation request was rejected because the token had no internal identifier.");
diff --git a/src/OpenIddict.Server/OpenIddictServerHandlers.cs b/src/OpenIddict.Server/OpenIddictServerHandlers.cs
index f3bb8c68..42943982 100644
--- a/src/OpenIddict.Server/OpenIddictServerHandlers.cs
+++ b/src/OpenIddict.Server/OpenIddictServerHandlers.cs
@@ -543,24 +543,73 @@ namespace OpenIddict.Server
return default;
}
- if (!context.Principal.HasTokenType(TokenTypeHints.AccessToken))
+ // To reduce the size of tokens, some of the private claims used by OpenIddict
+ // are mapped to their standard equivalent before being removed from the token.
+ // This handler is responsible of adding back the private claims to the principal
+ // when receiving the token (e.g "oi_prst" is resolved from the "scope" claim).
+
+ // In OpenIddict 3.0, the creation date of a token is stored in "oi_crt_dt".
+ // If the claim doesn't exist, try to infer it from the standard "iat" JWT claim.
+ if (!context.Principal.HasClaim(Claims.Private.CreationDate))
+ {
+ var date = context.Principal.GetClaim(Claims.IssuedAt);
+ if (!string.IsNullOrEmpty(date) &&
+ long.TryParse(date, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
+ {
+ context.Principal.SetCreationDate(DateTimeOffset.FromUnixTimeSeconds(value));
+ }
+ }
+
+ // In OpenIddict 3.0, the expiration date of a token is stored in "oi_exp_dt".
+ // If the claim doesn't exist, try to infer it from the standard "exp" JWT claim.
+ if (!context.Principal.HasClaim(Claims.Private.ExpirationDate))
{
- return default;
+ var date = context.Principal.GetClaim(Claims.ExpiresAt);
+ if (!string.IsNullOrEmpty(date) &&
+ long.TryParse(date, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
+ {
+ context.Principal.SetExpirationDate(DateTimeOffset.FromUnixTimeSeconds(value));
+ }
+ }
+
+ // In OpenIddict 3.0, the audiences allowed to receive a token are stored in "oi_aud".
+ // If no such claim exists, try to infer them from the standard "aud" JWT claims.
+ if (!context.Principal.HasAudience())
+ {
+ var audiences = context.Principal.GetClaims(Claims.Audience);
+ if (audiences.Any())
+ {
+ context.Principal.SetAudiences(audiences);
+ }
}
- // Map the standardized "azp" and "scope" claims to their "oi_" equivalent so that
- // the ClaimsPrincipal extensions exposed by OpenIddict return consistent results.
+ // In OpenIddict 3.0, the presenters allowed to use a token are stored in "oi_prst".
+ // If no such claim exists, try to infer them from the standard "azp" and "client_id" JWT claims.
+ //
+ // Note: in previous OpenIddict versions, the presenters were represented in JWT tokens
+ // using the "azp" claim (defined by OpenID Connect), for which a single value could be
+ // specified. To ensure presenters stored in JWT tokens created by OpenIddict 1.x/2.x
+ // can still be read with OpenIddict 3.0, the presenter is automatically inferred from
+ // the "azp" or "client_id" claim if no "oi_prst" claim was found in the principal.
if (!context.Principal.HasPresenter())
{
- context.Principal.SetPresenters(context.Principal.GetClaims(Claims.AuthorizedParty));
+ var presenter = context.Principal.GetClaim(Claims.AuthorizedParty) ??
+ context.Principal.GetClaim(Claims.ClientId);
+
+ if (!string.IsNullOrEmpty(presenter))
+ {
+ context.Principal.SetPresenters(presenter);
+ }
}
+ // In OpenIddict 3.0, the scopes granted to an application are stored in "oi_scp".
+ //
// Note: in previous OpenIddict versions, scopes were represented as a JSON array
// and deserialized as multiple claims. In OpenIddict 3.0, the public "scope" claim
// is formatted as a unique space-separated string containing all the granted scopes.
// To ensure access tokens generated by previous versions are still correctly handled,
// both formats (unique space-separated string or multiple scope claims) must be supported.
- // Visit https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-03 for more information.
+ // Visit https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-04 for more information.
if (!context.Principal.HasScope())
{
var scopes = context.Principal.GetClaims(Claims.Scope);
@@ -569,7 +618,10 @@ namespace OpenIddict.Server
scopes = scopes[0].Split(Separators.Space, StringSplitOptions.RemoveEmptyEntries).ToImmutableArray();
}
- context.Principal.SetScopes(scopes);
+ if (scopes.Any())
+ {
+ context.Principal.SetScopes(scopes);
+ }
}
return default;
@@ -634,8 +686,8 @@ namespace OpenIddict.Server
context.Principal = context.Principal
.SetCreationDate(await _tokenManager.GetCreationDateAsync(token))
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token))
- .SetInternalAuthorizationId(await _tokenManager.GetAuthorizationIdAsync(token))
- .SetInternalTokenId(await _tokenManager.GetIdAsync(token))
+ .SetAuthorizationId(await _tokenManager.GetAuthorizationIdAsync(token))
+ .SetTokenId(await _tokenManager.GetIdAsync(token))
.SetTokenType(await _tokenManager.GetTypeAsync(token));
}
}
@@ -771,7 +823,7 @@ namespace OpenIddict.Server
// Extract the token identifier from the authentication principal.
// If no token identifier can be found, this indicates that the token
// has no backing database entry (e.g an access token or an identity token).
- var identifier = context.Principal.GetInternalTokenId();
+ var identifier = context.Principal.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
return;
@@ -816,7 +868,7 @@ namespace OpenIddict.Server
await _tokenManager.TryRevokeAsync(token);
// Then, try to revoke the authorization and the associated token entries.
- await TryRevokeAuthorizationChainAsync(context.Principal.GetInternalAuthorizationId());
+ await TryRevokeAuthorizationChainAsync(context.Principal.GetAuthorizationId());
context.Logger.LogError("The token '{Identifier}' has already been redeemed.", identifier);
@@ -897,8 +949,8 @@ namespace OpenIddict.Server
// Restore the creation/expiration dates/identifiers from the token entry metadata.
context.Principal.SetCreationDate(await _tokenManager.GetCreationDateAsync(token))
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token))
- .SetInternalAuthorizationId(await _tokenManager.GetAuthorizationIdAsync(token))
- .SetInternalTokenId(await _tokenManager.GetIdAsync(token))
+ .SetAuthorizationId(await _tokenManager.GetAuthorizationIdAsync(token))
+ .SetTokenId(await _tokenManager.GetIdAsync(token))
.SetTokenType(await _tokenManager.GetTypeAsync(token));
async ValueTask TryRevokeAuthorizationChainAsync(string identifier)
@@ -919,7 +971,7 @@ namespace OpenIddict.Server
await foreach (var token in _tokenManager.FindByAuthorizationIdAsync(identifier))
{
// Don't change the status of the token used in the token request.
- if (string.Equals(context.Principal.GetInternalTokenId(),
+ if (string.Equals(context.Principal.GetTokenId(),
await _tokenManager.GetIdAsync(token), StringComparison.Ordinal))
{
continue;
@@ -969,7 +1021,7 @@ namespace OpenIddict.Server
throw new ArgumentNullException(nameof(context));
}
- var identifier = context.Principal.GetInternalAuthorizationId();
+ var identifier = context.Principal.GetAuthorizationId();
if (string.IsNullOrEmpty(identifier))
{
return;
@@ -1286,7 +1338,7 @@ namespace OpenIddict.Server
throw new InvalidOperationException("The authentication context cannot be found.");
// Extract the device code identifier from the authentication principal.
- var identifier = notification.Principal.GetInternalTokenId();
+ var identifier = notification.Principal.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The token identifier cannot be extracted from the principal.");
@@ -1741,7 +1793,7 @@ namespace OpenIddict.Server
}
// If an authorization identifier was explicitly specified, don't create an ad-hoc authorization.
- if (!string.IsNullOrEmpty(context.Principal.GetInternalAuthorizationId()))
+ if (!string.IsNullOrEmpty(context.Principal.GetAuthorizationId()))
{
return;
}
@@ -1791,7 +1843,7 @@ namespace OpenIddict.Server
// Attach the unique identifier of the ad hoc authorization to the authentication principal
// so that it is attached to all the derived tokens, allowing batched revocations support.
- context.Principal.SetInternalAuthorizationId(identifier);
+ context.Principal.SetAuthorizationId(identifier);
}
}
@@ -1893,10 +1945,11 @@ namespace OpenIddict.Server
principal.SetExpirationDate(principal.GetCreationDate() + lifetime.Value);
}
- // Set the public audiences collection using the private resource claims stored in the principal.
+ // Set the audiences based on the resource claims stored in the principal.
principal.SetAudiences(context.Principal.GetResources());
- // Store the client_id as a public client_id claim, if available.
+ // Store the client identifier in the public client_id claim, if available.
+ // See https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-04 for more information.
principal.SetClaim(Claims.ClientId, context.ClientId);
// When receiving a grant_type=refresh_token request, determine whether the client application
@@ -2271,6 +2324,10 @@ namespace OpenIddict.Server
principal.SetAudiences(context.ClientId);
}
+ // Use the client_id as the authorized party, if available.
+ // See https://openid.net/specs/openid-connect-core-1_0.html#IDToken for more information.
+ principal.SetClaim(Claims.AuthorizedParty, context.ClientId);
+
// If a nonce was present in the authorization request, it MUST be included in the id_token generated
// by the token endpoint. For that, OpenIddict simply flows the nonce as an authorization code claim.
// See http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation for more information.
@@ -2278,6 +2335,7 @@ namespace OpenIddict.Server
{
OpenIddictServerEndpointType.Authorization => context.Request.Nonce,
OpenIddictServerEndpointType.Token => context.Principal.GetClaim(Claims.Private.Nonce),
+
_ => null
});
@@ -2428,7 +2486,7 @@ namespace OpenIddict.Server
// Extract the token identifier from the authentication principal.
// If no token identifier can be found, this indicates that the token has no backing database entry.
- var identifier = context.Principal.GetInternalTokenId();
+ var identifier = context.Principal.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
return;
@@ -2517,7 +2575,7 @@ namespace OpenIddict.Server
// If the operation fails, silently ignore the error and keep processing the request:
// this may indicate that one of the revoked tokens was modified by a concurrent request.
- var identifier = context.Principal.GetInternalAuthorizationId();
+ var identifier = context.Principal.GetAuthorizationId();
if (string.IsNullOrEmpty(identifier))
{
return;
@@ -2526,7 +2584,7 @@ namespace OpenIddict.Server
await foreach (var token in _tokenManager.FindByAuthorizationIdAsync(identifier))
{
// Don't change the status of the token used in the token request.
- if (string.Equals(context.Principal.GetInternalTokenId(),
+ if (string.Equals(context.Principal.GetTokenId(),
await _tokenManager.GetIdAsync(token), StringComparison.Ordinal))
{
continue;
@@ -2590,7 +2648,7 @@ namespace OpenIddict.Server
// Extract the token identifier from the authentication principal.
// If no token identifier can be found, this indicates that the token has no backing database entry.
- var identifier = context.Principal.GetInternalTokenId();
+ var identifier = context.Principal.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
return;
@@ -2670,12 +2728,12 @@ namespace OpenIddict.Server
var principal = context.AccessTokenPrincipal;
if (principal == null)
{
- throw new InvalidOperationException("A token entry cannot be created from a null principal.");
+ throw new InvalidOperationException("A token cannot be created from a null principal.");
}
var descriptor = new OpenIddictTokenDescriptor
{
- AuthorizationId = principal.GetInternalAuthorizationId(),
+ AuthorizationId = principal.GetAuthorizationId(),
CreationDate = principal.GetCreationDate(),
ExpirationDate = principal.GetExpirationDate(),
Principal = principal,
@@ -2705,7 +2763,7 @@ namespace OpenIddict.Server
var identifier = await _tokenManager.GetIdAsync(token);
// Attach the token identifier to the principal so that it can be stored in the token.
- principal.SetInternalTokenId(identifier);
+ principal.SetTokenId(identifier);
context.Logger.LogTrace("The token entry for access token '{Identifier}' was successfully created.", identifier);
}
@@ -2746,55 +2804,78 @@ namespace OpenIddict.Server
return default;
}
- // Copy the principal and exclude the presenters/scopes private claims,
- // that are manually mapped to public standard azp/scope JWT claims.
- var principal = context.AccessTokenPrincipal.Clone(claim => claim.Type switch
+ // Clone the principal and exclude the private claims mapped to standard JWT claims.
+ var principal = context.AccessTokenPrincipal?.Clone(claim => claim.Type switch
{
- Claims.Private.Presenter => false,
- Claims.Private.Scope => false,
+ Claims.Private.Audience => false,
+ Claims.Private.CreationDate => false,
+ Claims.Private.ExpirationDate => false,
+ Claims.Private.Scope => false,
+ Claims.Private.TokenType => false,
_ => true
});
- // Set the authorized party using the first presenter (typically the client identifier), if available.
- principal.SetClaim(Claims.AuthorizedParty, context.AccessTokenPrincipal.GetPresenters().FirstOrDefault());
+ if (principal == null)
+ {
+ throw new InvalidOperationException("A token entry cannot be created from a null principal.");
+ }
+
+ var claims = new Dictionary(StringComparer.Ordinal);
+
+ // Set the public audience claims using the private audience claims from the principal.
+ // Note: when there's a single audience, represent it as a unique string claim.
+ var audiences = context.AccessTokenPrincipal.GetAudiences();
+ if (audiences.Any())
+ {
+ claims.Add(Claims.Audience, audiences.Length switch
+ {
+ 1 => audiences.ElementAt(0),
+ _ => audiences
+ });
+ }
// Set the public scope claim using the private scope claims from the principal.
// Note: scopes are deliberately formatted as a single space-separated
// string to respect the usual representation of the standard scope claim.
- // See https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-02.
- principal.SetClaim(Claims.Scope, string.Join(" ", context.AccessTokenPrincipal.GetScopes()));
+ // See https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-04.
+ var scopes = context.AccessTokenPrincipal.GetScopes();
+ if (scopes.Any())
+ {
+ claims.Add(Claims.Scope, string.Join(" ", scopes));
+ }
- var token = context.Options.JsonWebTokenHandler.CreateToken(new SecurityTokenDescriptor
+ var descriptor = new SecurityTokenDescriptor
{
AdditionalHeaderClaims = new Dictionary(StringComparer.Ordinal)
{
[JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.AccessToken
},
+ Claims = claims,
+ Expires = context.AccessTokenPrincipal.GetExpirationDate()?.UtcDateTime,
+ IssuedAt = context.AccessTokenPrincipal.GetCreationDate()?.UtcDateTime,
Issuer = context.Issuer?.AbsoluteUri,
SigningCredentials = context.Options.SigningCredentials.FirstOrDefault(credentials =>
credentials.Key is SymmetricSecurityKey) ?? context.Options.SigningCredentials.First(),
Subject = (ClaimsIdentity) principal.Identity
- });
+ };
+
+ var token = context.Options.JsonWebTokenHandler.CreateToken(descriptor);
if (!context.Options.DisableAccessTokenEncryption)
{
token = context.Options.JsonWebTokenHandler.EncryptToken(token,
- context.Options.EncryptionCredentials.FirstOrDefault(
+ encryptingCredentials: context.Options.EncryptionCredentials.FirstOrDefault(
credentials => credentials.Key is SymmetricSecurityKey) ??
context.Options.EncryptionCredentials.First(),
- new Dictionary(StringComparer.Ordinal)
- {
- [JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.AccessToken
- });
+ additionalHeaderClaims: descriptor.AdditionalHeaderClaims);
}
context.Response.AccessToken = token;
context.Logger.LogTrace("The access token '{Identifier}' was successfully created: {Payload}. " +
"The principal used to create the token contained the following claims: {Claims}.",
- context.AccessTokenPrincipal.GetClaim(Claims.JwtId),
- context.Response.AccessToken, principal.Claims);
+ principal.GetClaim(Claims.JwtId), token, principal.Claims);
return default;
}
@@ -2857,7 +2938,7 @@ namespace OpenIddict.Server
throw new InvalidOperationException("A token entry cannot be created from a null principal.");
}
- var identifier = principal.GetInternalTokenId();
+ var identifier = principal.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The token identifier cannot be extracted from the principal.");
@@ -2954,7 +3035,7 @@ namespace OpenIddict.Server
var descriptor = new OpenIddictTokenDescriptor
{
- AuthorizationId = principal.GetInternalAuthorizationId(),
+ AuthorizationId = principal.GetAuthorizationId(),
CreationDate = principal.GetCreationDate(),
ExpirationDate = principal.GetExpirationDate(),
Principal = principal,
@@ -2984,7 +3065,7 @@ namespace OpenIddict.Server
var identifier = await _tokenManager.GetIdAsync(token);
// Attach the token identifier to the principal so that it can be stored in the token.
- principal.SetInternalTokenId(identifier);
+ principal.SetTokenId(identifier);
context.Logger.LogTrace("The token entry for authorization code '{Identifier}' was successfully created.", identifier);
}
@@ -3025,20 +3106,37 @@ namespace OpenIddict.Server
return default;
}
+ // 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
+ });
+
+ if (principal == null)
+ {
+ throw new InvalidOperationException("A token cannot be created from a null principal.");
+ }
+
var descriptor = new SecurityTokenDescriptor
{
AdditionalHeaderClaims = new Dictionary(StringComparer.Ordinal)
{
[JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.Private.AuthorizationCode
},
+ Expires = context.AuthorizationCodePrincipal.GetExpirationDate()?.UtcDateTime,
+ IssuedAt = context.AuthorizationCodePrincipal.GetCreationDate()?.UtcDateTime,
Issuer = context.Issuer?.AbsoluteUri,
SigningCredentials = context.Options.SigningCredentials.FirstOrDefault(credentials =>
credentials.Key is SymmetricSecurityKey) ?? context.Options.SigningCredentials.First(),
- Subject = (ClaimsIdentity) context.AuthorizationCodePrincipal.Identity
+ Subject = (ClaimsIdentity) principal.Identity
};
// Attach claims destinations to the JWT claims collection.
- var destinations = context.AuthorizationCodePrincipal.GetDestinations();
+ var destinations = principal.GetDestinations();
if (destinations.Count != 0)
{
descriptor.Claims = new Dictionary(StringComparer.Ordinal)
@@ -3049,21 +3147,18 @@ namespace OpenIddict.Server
// Sign and encrypt the authorization code.
var token = context.Options.JsonWebTokenHandler.CreateToken(descriptor);
+
token = context.Options.JsonWebTokenHandler.EncryptToken(token,
- context.Options.EncryptionCredentials.FirstOrDefault(
+ encryptingCredentials: context.Options.EncryptionCredentials.FirstOrDefault(
credentials => credentials.Key is SymmetricSecurityKey) ??
context.Options.EncryptionCredentials.First(),
- new Dictionary(StringComparer.Ordinal)
- {
- [JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.Private.AuthorizationCode
- });
+ additionalHeaderClaims: descriptor.AdditionalHeaderClaims);
context.Response.Code = token;
context.Logger.LogTrace("The authorization code '{Identifier}' was successfully created: {Payload}. " +
"The principal used to create the token contained the following claims: {Claims}.",
- context.AuthorizationCodePrincipal.GetClaim(Claims.JwtId), token,
- context.AuthorizationCodePrincipal.Claims);
+ principal.GetClaim(Claims.JwtId), token, principal.Claims);
return default;
}
@@ -3126,7 +3221,7 @@ namespace OpenIddict.Server
throw new InvalidOperationException("A token entry cannot be created from a null principal.");
}
- var identifier = principal.GetInternalTokenId();
+ var identifier = principal.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The token identifier cannot be extracted from the principal.");
@@ -3228,7 +3323,7 @@ namespace OpenIddict.Server
var descriptor = new OpenIddictTokenDescriptor
{
- AuthorizationId = principal.GetInternalAuthorizationId(),
+ AuthorizationId = principal.GetAuthorizationId(),
CreationDate = principal.GetCreationDate(),
ExpirationDate = principal.GetExpirationDate(),
Principal = principal,
@@ -3258,7 +3353,7 @@ namespace OpenIddict.Server
var identifier = await _tokenManager.GetIdAsync(token);
// Attach the token identifier to the principal so that it can be stored in the token.
- principal.SetInternalTokenId(identifier);
+ principal.SetTokenId(identifier);
context.Logger.LogTrace("The token entry for device code '{Identifier}' was successfully created.", identifier);
}
@@ -3299,20 +3394,37 @@ namespace OpenIddict.Server
return default;
}
+ // 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
+ });
+
+ if (principal == null)
+ {
+ throw new InvalidOperationException("A token cannot be created from a null principal.");
+ }
+
var descriptor = new SecurityTokenDescriptor
{
AdditionalHeaderClaims = new Dictionary(StringComparer.Ordinal)
{
[JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.Private.DeviceCode
},
+ Expires = context.DeviceCodePrincipal.GetExpirationDate()?.UtcDateTime,
+ IssuedAt = context.DeviceCodePrincipal.GetCreationDate()?.UtcDateTime,
Issuer = context.Issuer?.AbsoluteUri,
SigningCredentials = context.Options.SigningCredentials.FirstOrDefault(credentials =>
credentials.Key is SymmetricSecurityKey) ?? context.Options.SigningCredentials.First(),
- Subject = (ClaimsIdentity) context.DeviceCodePrincipal.Identity
+ Subject = (ClaimsIdentity) principal.Identity
};
// Attach claims destinations to the JWT claims collection.
- var destinations = context.DeviceCodePrincipal.GetDestinations();
+ var destinations = principal.GetDestinations();
if (destinations.Count != 0)
{
descriptor.Claims = new Dictionary(StringComparer.Ordinal)
@@ -3323,21 +3435,18 @@ namespace OpenIddict.Server
// Sign and encrypt the device code.
var token = context.Options.JsonWebTokenHandler.CreateToken(descriptor);
+
token = context.Options.JsonWebTokenHandler.EncryptToken(token,
- context.Options.EncryptionCredentials.FirstOrDefault(
+ encryptingCredentials: context.Options.EncryptionCredentials.FirstOrDefault(
credentials => credentials.Key is SymmetricSecurityKey) ??
context.Options.EncryptionCredentials.First(),
- new Dictionary(StringComparer.Ordinal)
- {
- [JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.Private.DeviceCode
- });
+ additionalHeaderClaims: descriptor.AdditionalHeaderClaims);
context.Response.DeviceCode = token;
context.Logger.LogTrace("The device code '{Identifier}' was successfully created: {Payload}. " +
"The principal used to create the token contained the following claims: {Claims}.",
- context.DeviceCodePrincipal.GetClaim(Claims.JwtId), token,
- context.DeviceCodePrincipal.Claims);
+ principal.GetClaim(Claims.JwtId), token, principal.Claims);
return default;
}
@@ -3405,7 +3514,7 @@ namespace OpenIddict.Server
throw new InvalidOperationException("A token entry cannot be created from a null principal.");
}
- var identifier = principal.GetInternalTokenId();
+ var identifier = principal.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The token identifier cannot be extracted from the principal.");
@@ -3598,7 +3707,7 @@ namespace OpenIddict.Server
var descriptor = new OpenIddictTokenDescriptor
{
- AuthorizationId = principal.GetInternalAuthorizationId(),
+ AuthorizationId = principal.GetAuthorizationId(),
CreationDate = principal.GetCreationDate(),
ExpirationDate = principal.GetExpirationDate(),
Principal = principal,
@@ -3628,7 +3737,7 @@ namespace OpenIddict.Server
var identifier = await _tokenManager.GetIdAsync(token);
// Attach the token identifier to the principal so that it can be stored in the token.
- principal.SetInternalTokenId(identifier);
+ principal.SetTokenId(identifier);
context.Logger.LogTrace("The token entry for refresh token '{Identifier}' was successfully created.", identifier);
}
@@ -3669,20 +3778,37 @@ namespace OpenIddict.Server
return default;
}
+ // 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
+ });
+
+ if (principal == null)
+ {
+ throw new InvalidOperationException("A token cannot be created from a null principal.");
+ }
+
var descriptor = new SecurityTokenDescriptor
{
AdditionalHeaderClaims = new Dictionary(StringComparer.Ordinal)
{
[JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.Private.RefreshToken
},
+ Expires = context.RefreshTokenPrincipal.GetExpirationDate()?.UtcDateTime,
+ IssuedAt = context.RefreshTokenPrincipal.GetCreationDate()?.UtcDateTime,
Issuer = context.Issuer?.AbsoluteUri,
SigningCredentials = context.Options.SigningCredentials.FirstOrDefault(credentials =>
credentials.Key is SymmetricSecurityKey) ?? context.Options.SigningCredentials.First(),
- Subject = (ClaimsIdentity) context.RefreshTokenPrincipal.Identity
+ Subject = (ClaimsIdentity) principal.Identity
};
// Attach claims destinations to the JWT claims collection.
- var destinations = context.RefreshTokenPrincipal.GetDestinations();
+ var destinations = principal.GetDestinations();
if (destinations.Count != 0)
{
descriptor.Claims = new Dictionary(StringComparer.Ordinal)
@@ -3693,21 +3819,18 @@ namespace OpenIddict.Server
// Sign and encrypt the refresh token.
var token = context.Options.JsonWebTokenHandler.CreateToken(descriptor);
+
token = context.Options.JsonWebTokenHandler.EncryptToken(token,
- context.Options.EncryptionCredentials.FirstOrDefault(
+ encryptingCredentials: context.Options.EncryptionCredentials.FirstOrDefault(
credentials => credentials.Key is SymmetricSecurityKey) ??
context.Options.EncryptionCredentials.First(),
- new Dictionary(StringComparer.Ordinal)
- {
- [JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.Private.RefreshToken
- });
+ additionalHeaderClaims: descriptor.AdditionalHeaderClaims);
context.Response.RefreshToken = token;
context.Logger.LogTrace("The refresh token '{Identifier}' was successfully created: {Payload}. " +
"The principal used to create the token contained the following claims: {Claims}.",
- context.RefreshTokenPrincipal.GetClaim(Claims.JwtId), token,
- context.RefreshTokenPrincipal.Claims);
+ principal.GetClaim(Claims.JwtId), token, principal.Claims);
return default;
}
@@ -3770,7 +3893,7 @@ namespace OpenIddict.Server
throw new InvalidOperationException("A token entry cannot be created from a null principal.");
}
- var identifier = principal.GetInternalTokenId();
+ var identifier = principal.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The token identifier cannot be extracted from the principal.");
@@ -3844,7 +3967,7 @@ namespace OpenIddict.Server
throw new InvalidOperationException("A token entry cannot be created from a null principal.");
}
- var identifier = context.DeviceCodePrincipal.GetInternalTokenId();
+ var identifier = context.DeviceCodePrincipal.GetTokenId();
if (!string.IsNullOrEmpty(identifier))
{
principal.SetClaim(Claims.Private.DeviceCodeId, identifier);
@@ -3913,7 +4036,7 @@ namespace OpenIddict.Server
var descriptor = new OpenIddictTokenDescriptor
{
- AuthorizationId = principal.GetInternalAuthorizationId(),
+ AuthorizationId = principal.GetAuthorizationId(),
CreationDate = principal.GetCreationDate(),
ExpirationDate = principal.GetExpirationDate(),
Principal = principal,
@@ -3943,7 +4066,7 @@ namespace OpenIddict.Server
var identifier = await _tokenManager.GetIdAsync(token);
// Attach the token identifier to the principal so that it can be stored in the token.
- principal.SetInternalTokenId(identifier);
+ principal.SetTokenId(identifier);
context.Logger.LogTrace("The token entry for user code '{Identifier}' was successfully created.", identifier);
}
@@ -3984,34 +4107,49 @@ namespace OpenIddict.Server
return default;
}
- // Sign and encrypt the user code.
- var token = context.Options.JsonWebTokenHandler.CreateToken(new SecurityTokenDescriptor
+ // 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
+ });
+
+ if (principal == null)
+ {
+ throw new InvalidOperationException("A token cannot be created from a null principal.");
+ }
+
+ var descriptor = new SecurityTokenDescriptor
{
AdditionalHeaderClaims = new Dictionary(StringComparer.Ordinal)
{
[JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.Private.UserCode
},
+ Expires = context.UserCodePrincipal.GetExpirationDate()?.UtcDateTime,
+ IssuedAt = context.UserCodePrincipal.GetCreationDate()?.UtcDateTime,
Issuer = context.Issuer?.AbsoluteUri,
SigningCredentials = context.Options.SigningCredentials.FirstOrDefault(credentials =>
credentials.Key is SymmetricSecurityKey) ?? context.Options.SigningCredentials.First(),
- Subject = (ClaimsIdentity) context.UserCodePrincipal.Identity
- });
+ Subject = (ClaimsIdentity) principal.Identity
+ };
+
+ // Sign and encrypt the user code.
+ var token = context.Options.JsonWebTokenHandler.CreateToken(descriptor);
token = context.Options.JsonWebTokenHandler.EncryptToken(token,
- context.Options.EncryptionCredentials.FirstOrDefault(
+ encryptingCredentials: context.Options.EncryptionCredentials.FirstOrDefault(
credentials => credentials.Key is SymmetricSecurityKey) ??
context.Options.EncryptionCredentials.First(),
- new Dictionary(StringComparer.Ordinal)
- {
- [JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.Private.UserCode
- });
+ additionalHeaderClaims: descriptor.AdditionalHeaderClaims);
context.Response.UserCode = token;
context.Logger.LogTrace("The user code '{Identifier}' was successfully created: {Payload}. " +
"The principal used to create the token contained the following claims: {Claims}.",
- context.UserCodePrincipal.GetClaim(Claims.JwtId), token,
- context.UserCodePrincipal.Claims);
+ principal.GetClaim(Claims.JwtId), token, principal.Claims);
return default;
}
@@ -4074,7 +4212,7 @@ namespace OpenIddict.Server
throw new InvalidOperationException("A token entry cannot be created from a null principal.");
}
- var identifier = principal.GetInternalTokenId();
+ var identifier = principal.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The token identifier cannot be extracted from the principal.");
@@ -4315,7 +4453,7 @@ namespace OpenIddict.Server
var descriptor = new OpenIddictTokenDescriptor
{
- AuthorizationId = principal.GetInternalAuthorizationId(),
+ AuthorizationId = principal.GetAuthorizationId(),
CreationDate = principal.GetCreationDate(),
ExpirationDate = principal.GetExpirationDate(),
Principal = principal,
@@ -4345,7 +4483,7 @@ namespace OpenIddict.Server
var identifier = await _tokenManager.GetIdAsync(token);
// Attach the token identifier to the principal so that it can be stored in the token.
- principal.SetInternalTokenId(identifier);
+ principal.SetTokenId(identifier);
context.Logger.LogTrace("The token entry for identity token '{Identifier}' was successfully created.", identifier);
}
@@ -4386,23 +4524,59 @@ namespace OpenIddict.Server
return default;
}
- // Sign and attach the identity token.
- context.Response.IdToken = context.Options.JsonWebTokenHandler.CreateToken(new SecurityTokenDescriptor
+ // 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
+ });
+
+ if (principal == null)
+ {
+ throw new InvalidOperationException("A token cannot be created from a null principal.");
+ }
+
+ var claims = new Dictionary(StringComparer.Ordinal);
+
+ // Set the public audience claims using the private audience claims from the principal.
+ // Note: when there's a single audience, represent it as a unique string claim.
+ var audiences = context.IdentityTokenPrincipal.GetAudiences();
+ if (audiences.Any())
+ {
+ claims.Add(Claims.Audience, audiences.Length switch
+ {
+ 1 => audiences.ElementAt(0),
+ _ => audiences
+ });
+ }
+
+ var descriptor = new SecurityTokenDescriptor
{
AdditionalHeaderClaims = new Dictionary(StringComparer.Ordinal)
{
[JwtHeaderParameterNames.Typ] = JsonWebTokenTypes.IdentityToken
},
+ Claims = claims,
+ Expires = context.IdentityTokenPrincipal.GetExpirationDate()?.UtcDateTime,
+ IssuedAt = context.IdentityTokenPrincipal.GetCreationDate()?.UtcDateTime,
Issuer = context.Issuer?.AbsoluteUri,
SigningCredentials = context.Options.SigningCredentials.First(credentials =>
credentials.Key is AsymmetricSecurityKey),
- Subject = (ClaimsIdentity) context.IdentityTokenPrincipal.Identity
- });
+ Subject = (ClaimsIdentity) principal.Identity
+ };
+
+ // Sign and attach the identity token.
+ var token = context.Options.JsonWebTokenHandler.CreateToken(descriptor);
+
+ context.Response.IdToken = token;
context.Logger.LogTrace("The identity token '{Identifier}' was successfully created: {Payload}. " +
"The principal used to create the token contained the following claims: {Claims}.",
- context.IdentityTokenPrincipal.GetClaim(Claims.JwtId),
- context.Response.IdToken, context.IdentityTokenPrincipal.Claims);
+ principal.GetClaim(Claims.JwtId), token, principal.Claims);
return default;
}
diff --git a/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionConstants.cs b/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionConstants.cs
index 0d181d8d..6b7b54e4 100644
--- a/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionConstants.cs
+++ b/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionConstants.cs
@@ -16,6 +16,8 @@ namespace OpenIddict.Validation.DataProtection
public const string CodeChallenge = ".code_challenge";
public const string CodeChallengeMethod = ".code_challenge_method";
public const string DataProtector = ".data_protector";
+ public const string DeviceCodeId = ".device_code_id";
+ public const string DeviceCodeLifetime = ".device_code_lifetime";
public const string Expires = ".expires";
public const string IdentityTokenLifetime = ".identity_token_lifetime";
public const string InternalAuthorizationId = ".internal_authorization_id";
@@ -27,6 +29,7 @@ namespace OpenIddict.Validation.DataProtection
public const string RefreshTokenLifetime = ".refresh_token_lifetime";
public const string Resources = ".resources";
public const string Scopes = ".scopes";
+ public const string UserCodeLifetime = ".user_code_lifetime";
}
public static class Purposes
diff --git a/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionFormatter.cs b/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionFormatter.cs
index b47676b1..b8704d81 100644
--- a/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionFormatter.cs
+++ b/src/OpenIddict.Validation.DataProtection/OpenIddictValidationDataProtectionFormatter.cs
@@ -7,7 +7,6 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
-using System.Globalization;
using System.IO;
using System.Security.Claims;
using System.Text.Json;
@@ -39,8 +38,6 @@ namespace OpenIddict.Validation.DataProtection
return principal
.SetAudiences(GetArrayProperty(properties, Properties.Audiences))
- .SetCreationDate(GetDateProperty(properties, Properties.Issued))
- .SetExpirationDate(GetDateProperty(properties, Properties.Expires))
.SetPresenters(GetArrayProperty(properties, Properties.Presenters))
.SetResources(GetArrayProperty(properties, Properties.Resources))
.SetScopes(GetArrayProperty(properties, Properties.Scopes))
@@ -50,11 +47,16 @@ namespace OpenIddict.Validation.DataProtection
.SetClaim(Claims.Private.AuthorizationId, GetProperty(properties, Properties.InternalAuthorizationId))
.SetClaim(Claims.Private.CodeChallenge, GetProperty(properties, Properties.CodeChallenge))
.SetClaim(Claims.Private.CodeChallengeMethod, GetProperty(properties, Properties.CodeChallengeMethod))
+ .SetClaim(Claims.Private.CreationDate, GetProperty(properties, Properties.Issued))
+ .SetClaim(Claims.Private.DeviceCodeId, GetProperty(properties, Properties.DeviceCodeId))
+ .SetClaim(Claims.Private.DeviceCodeLifetime, GetProperty(properties, Properties.DeviceCodeLifetime))
.SetClaim(Claims.Private.IdentityTokenLifetime, GetProperty(properties, Properties.IdentityTokenLifetime))
+ .SetClaim(Claims.Private.ExpirationDate, GetProperty(properties, Properties.Expires))
.SetClaim(Claims.Private.Nonce, GetProperty(properties, Properties.Nonce))
.SetClaim(Claims.Private.RedirectUri, GetProperty(properties, Properties.OriginalRedirectUri))
.SetClaim(Claims.Private.RefreshTokenLifetime, GetProperty(properties, Properties.RefreshTokenLifetime))
- .SetClaim(Claims.Private.TokenId, GetProperty(properties, Properties.InternalTokenId));
+ .SetClaim(Claims.Private.TokenId, GetProperty(properties, Properties.InternalTokenId))
+ .SetClaim(Claims.Private.UserCodeLifetime, GetProperty(properties, Properties.UserCodeLifetime));
static (ClaimsPrincipal principal, ImmutableDictionary properties) Read(BinaryReader reader, int version)
{
@@ -175,10 +177,6 @@ namespace OpenIddict.Validation.DataProtection
static ImmutableArray GetArrayProperty(IReadOnlyDictionary properties, string name)
=> properties.TryGetValue(name, out var value) ?
JsonSerializer.Deserialize>(value) : ImmutableArray.Create();
-
- static DateTimeOffset? GetDateProperty(IReadOnlyDictionary properties, string name)
- => properties.TryGetValue(name, out var value) ? (DateTimeOffset?)
- DateTimeOffset.ParseExact(value, "r", CultureInfo.InvariantCulture) : null;
}
}
}
diff --git a/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs b/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs
index cead04db..c67ed299 100644
--- a/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs
+++ b/src/OpenIddict.Validation/OpenIddictValidationHandlers.cs
@@ -7,6 +7,7 @@
using System;
using System.Collections.Immutable;
using System.ComponentModel;
+using System.Globalization;
using System.Linq;
using System.Security.Claims;
using System.Text;
@@ -382,19 +383,73 @@ namespace OpenIddict.Validation
return default;
}
- // Map the standardized "azp" and "scope" claims to their "oi_" equivalent so that
- // the ClaimsPrincipal extensions exposed by OpenIddict return consistent results.
+ // To reduce the size of tokens, some of the private claims used by OpenIddict
+ // are mapped to their standard equivalent before being removed from the token.
+ // This handler is responsible of adding back the private claims to the principal
+ // when receiving the token (e.g "oi_prst" is resolved from the "scope" claim).
+
+ // In OpenIddict 3.0, the creation date of a token is stored in "oi_crt_dt".
+ // If the claim doesn't exist, try to infer it from the standard "iat" JWT claim.
+ if (!context.Principal.HasClaim(Claims.Private.CreationDate))
+ {
+ var date = context.Principal.GetClaim(Claims.IssuedAt);
+ if (!string.IsNullOrEmpty(date) &&
+ long.TryParse(date, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
+ {
+ context.Principal.SetCreationDate(DateTimeOffset.FromUnixTimeSeconds(value));
+ }
+ }
+
+ // In OpenIddict 3.0, the expiration date of a token is stored in "oi_exp_dt".
+ // If the claim doesn't exist, try to infer it from the standard "exp" JWT claim.
+ if (!context.Principal.HasClaim(Claims.Private.ExpirationDate))
+ {
+ var date = context.Principal.GetClaim(Claims.ExpiresAt);
+ if (!string.IsNullOrEmpty(date) &&
+ long.TryParse(date, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
+ {
+ context.Principal.SetExpirationDate(DateTimeOffset.FromUnixTimeSeconds(value));
+ }
+ }
+
+ // In OpenIddict 3.0, the audiences allowed to receive a token are stored in "oi_aud".
+ // If no such claim exists, try to infer them from the standard "aud" JWT claims.
+ if (!context.Principal.HasAudience())
+ {
+ var audiences = context.Principal.GetClaims(Claims.Audience);
+ if (audiences.Any())
+ {
+ context.Principal.SetAudiences(audiences);
+ }
+ }
+
+ // In OpenIddict 3.0, the presenters allowed to use a token are stored in "oi_prst".
+ // If no such claim exists, try to infer them from the standard "azp" and "client_id" JWT claims.
+ //
+ // Note: in previous OpenIddict versions, the presenters were represented in JWT tokens
+ // using the "azp" claim (defined by OpenID Connect), for which a single value could be
+ // specified. To ensure presenters stored in JWT tokens created by OpenIddict 1.x/2.x
+ // can still be read with OpenIddict 3.0, the presenter is automatically inferred from
+ // the "azp" or "client_id" claim if no "oi_prst" claim was found in the principal.
if (!context.Principal.HasPresenter())
{
- context.Principal.SetPresenters(context.Principal.GetClaims(Claims.AuthorizedParty));
+ var presenter = context.Principal.GetClaim(Claims.AuthorizedParty) ??
+ context.Principal.GetClaim(Claims.ClientId);
+
+ if (!string.IsNullOrEmpty(presenter))
+ {
+ context.Principal.SetPresenters(presenter);
+ }
}
+ // In OpenIddict 3.0, the scopes granted to an application are stored in "oi_scp".
+ //
// Note: in previous OpenIddict versions, scopes were represented as a JSON array
// and deserialized as multiple claims. In OpenIddict 3.0, the public "scope" claim
// is formatted as a unique space-separated string containing all the granted scopes.
// To ensure access tokens generated by previous versions are still correctly handled,
// both formats (unique space-separated string or multiple scope claims) must be supported.
- // Visit https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-03 for more information.
+ // Visit https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-04 for more information.
if (!context.Principal.HasScope())
{
var scopes = context.Principal.GetClaims(Claims.Scope);
@@ -403,7 +458,10 @@ namespace OpenIddict.Validation
scopes = scopes[0].Split(Separators.Space, StringSplitOptions.RemoveEmptyEntries).ToImmutableArray();
}
- context.Principal.SetScopes(scopes);
+ if (scopes.Any())
+ {
+ context.Principal.SetScopes(scopes);
+ }
}
return default;
@@ -465,8 +523,8 @@ namespace OpenIddict.Validation
context.Principal = context.Principal
.SetCreationDate(await _tokenManager.GetCreationDateAsync(token))
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token))
- .SetInternalAuthorizationId(await _tokenManager.GetAuthorizationIdAsync(token))
- .SetInternalTokenId(await _tokenManager.GetIdAsync(token))
+ .SetAuthorizationId(await _tokenManager.GetAuthorizationIdAsync(token))
+ .SetTokenId(await _tokenManager.GetIdAsync(token))
.SetTokenType(await _tokenManager.GetTypeAsync(token));
}
}
@@ -682,7 +740,7 @@ namespace OpenIddict.Validation
throw new ArgumentNullException(nameof(context));
}
- var identifier = context.Principal.GetInternalTokenId();
+ var identifier = context.Principal.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
return;
@@ -703,8 +761,8 @@ namespace OpenIddict.Validation
// Restore the creation/expiration dates/identifiers from the token entry metadata.
context.Principal.SetCreationDate(await _tokenManager.GetCreationDateAsync(token))
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token))
- .SetInternalAuthorizationId(await _tokenManager.GetAuthorizationIdAsync(token))
- .SetInternalTokenId(await _tokenManager.GetIdAsync(token))
+ .SetAuthorizationId(await _tokenManager.GetAuthorizationIdAsync(token))
+ .SetTokenId(await _tokenManager.GetIdAsync(token))
.SetTokenType(await _tokenManager.GetTypeAsync(token));
}
}
@@ -745,7 +803,7 @@ namespace OpenIddict.Validation
throw new ArgumentNullException(nameof(context));
}
- var identifier = context.Principal.GetInternalAuthorizationId();
+ var identifier = context.Principal.GetAuthorizationId();
if (string.IsNullOrEmpty(identifier))
{
return;
diff --git a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs
index 6d31925a..63d2fda2 100644
--- a/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs
+++ b/test/OpenIddict.Abstractions.Tests/Primitives/OpenIddictExtensionsTests.cs
@@ -1497,7 +1497,8 @@ namespace OpenIddict.Abstractions.Tests.Primitives
public void GetClaim_ReturnsNullForMissingClaim()
{
// Arrange
- var principal = new ClaimsPrincipal();
+ var identity = new ClaimsIdentity();
+ var principal = new ClaimsPrincipal(identity);
// Act and assert
Assert.Null(principal.GetClaim("type"));
@@ -1531,33 +1532,26 @@ namespace OpenIddict.Abstractions.Tests.Primitives
public void GetCreationDate_ReturnsNullIfNoClaim()
{
// Arrange
- var principal = new ClaimsPrincipal();
-
- // Act
- var creationDate = principal.GetCreationDate();
+ var identity = new ClaimsIdentity();
+ var principal = new ClaimsPrincipal(identity);
- // Assert
- Assert.Null(creationDate);
+ // Act and assert
+ Assert.Null(principal.GetCreationDate());
}
- [Theory]
- [InlineData(null, null)]
- [InlineData("", null)]
- [InlineData(" ", null)]
- [InlineData("62", "62")]
- [InlineData("bad_data", null)]
- public void GetCreationDate_ReturnsCreationDate(string issuedAt, string expected)
+ [Fact]
+ public void GetCreationDate_ReturnsCreationDate()
{
// Arrange
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
- principal.SetClaim(Claims.IssuedAt, issuedAt);
+ principal.SetClaim(Claims.Private.CreationDate, "Wed, 01 Jan 2020 04:30:30 GMT");
// Act
- var creationDate = principal.GetCreationDate();
+ var date = principal.GetCreationDate();
// Assert
- Assert.Equal(ParseDateTimeOffset(expected), creationDate);
+ Assert.Equal(new DateTimeOffset(2020, 01, 01, 05, 30, 30, TimeSpan.FromHours(1)), date);
}
[Fact]
@@ -1578,31 +1572,23 @@ namespace OpenIddict.Abstractions.Tests.Primitives
// Arrange
var principal = new ClaimsPrincipal();
- // Act
- var expirationDate = principal.GetExpirationDate();
-
- // Assert
- Assert.Null(expirationDate);
+ // Act and assert
+ Assert.Null(principal.GetExpirationDate());
}
- [Theory]
- [InlineData(null, null)]
- [InlineData("", null)]
- [InlineData(" ", null)]
- [InlineData("62", "62")]
- [InlineData("bad_data", null)]
- public void GetExpirationDate_ReturnsExpirationDate(string expiresAt, string expected)
+ [Fact]
+ public void GetExpirationDate_ReturnsExpirationDate()
{
// Arrange
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
- principal.SetClaim(Claims.ExpiresAt, expiresAt);
+ principal.SetClaim(Claims.Private.ExpirationDate, "Wed, 01 Jan 2020 04:30:30 GMT");
// Act
- var expirationDate = principal.GetExpirationDate();
+ var date = principal.GetExpirationDate();
// Assert
- Assert.Equal(ParseDateTimeOffset(expected), expirationDate);
+ Assert.Equal(new DateTimeOffset(2020, 01, 01, 05, 30, 30, TimeSpan.FromHours(1)), date);
}
[Fact]
@@ -1629,7 +1615,7 @@ namespace OpenIddict.Abstractions.Tests.Primitives
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
- principal.SetClaims(Claims.Audience, audience.ToImmutableArray());
+ principal.SetClaims(Claims.Private.Audience, audience.ToImmutableArray());
// Act and assert
Assert.Equal(audiences, principal.GetAudiences());
@@ -1888,13 +1874,13 @@ namespace OpenIddict.Abstractions.Tests.Primitives
}
[Fact]
- public void GetInternalAuthorizationId_ThrowsAnExceptionForNullPrincipal()
+ public void GetAuthorizationId_ThrowsAnExceptionForNullPrincipal()
{
// Arrange
var principal = (ClaimsPrincipal) null;
// Act and assert
- var exception = Assert.Throws(() => principal.GetInternalAuthorizationId());
+ var exception = Assert.Throws(() => principal.GetAuthorizationId());
Assert.Equal("principal", exception.ParamName);
}
@@ -1902,7 +1888,7 @@ namespace OpenIddict.Abstractions.Tests.Primitives
[Theory]
[InlineData(null)]
[InlineData("identifier")]
- public void GetInternalAuthorizationId_ReturnsExpectedResult(string identifier)
+ public void GetAuthorizationId_ReturnsExpectedResult(string identifier)
{
// Arrange
var identity = new ClaimsIdentity();
@@ -1911,17 +1897,17 @@ namespace OpenIddict.Abstractions.Tests.Primitives
principal.SetClaim(Claims.Private.AuthorizationId, identifier);
// Act and assert
- Assert.Equal(identifier, principal.GetInternalAuthorizationId());
+ Assert.Equal(identifier, principal.GetAuthorizationId());
}
[Fact]
- public void GetInternalTokenId_ThrowsAnExceptionForNullPrincipal()
+ public void GetTokenId_ThrowsAnExceptionForNullPrincipal()
{
// Arrange
var principal = (ClaimsPrincipal) null;
// Act and assert
- var exception = Assert.Throws(() => principal.GetInternalTokenId());
+ var exception = Assert.Throws(() => principal.GetTokenId());
Assert.Equal("principal", exception.ParamName);
}
@@ -1929,7 +1915,7 @@ namespace OpenIddict.Abstractions.Tests.Primitives
[Theory]
[InlineData(null)]
[InlineData("identifier")]
- public void GetInternalTokenId_ReturnsExpectedResult(string identifier)
+ public void GetTokenId_ReturnsExpectedResult(string identifier)
{
// Arrange
var identity = new ClaimsIdentity();
@@ -1938,7 +1924,7 @@ namespace OpenIddict.Abstractions.Tests.Primitives
principal.SetClaim(Claims.Private.TokenId, identifier);
// Act and assert
- Assert.Equal(identifier, principal.GetInternalTokenId());
+ Assert.Equal(identifier, principal.GetTokenId());
}
[Fact]
@@ -2004,7 +1990,7 @@ namespace OpenIddict.Abstractions.Tests.Primitives
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
- principal.SetClaims(Claims.Audience, audience.ToImmutableArray());
+ principal.SetClaims(Claims.Private.Audience, audience.ToImmutableArray());
// Act and assert
Assert.Equal(result, principal.HasAudience());
@@ -2026,7 +2012,7 @@ namespace OpenIddict.Abstractions.Tests.Primitives
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
- principal.SetClaims(Claims.Audience, audience.ToImmutableArray());
+ principal.SetClaims(Claims.Private.Audience, audience.ToImmutableArray());
// Act and assert
Assert.Equal(result, principal.HasAudience("fabrikam"));
@@ -2294,6 +2280,92 @@ namespace OpenIddict.Abstractions.Tests.Primitives
Assert.Equal("value", identity.GetClaim("type"));
}
+ [Fact]
+ public void GetClaims_ThrowsAnExceptionForNullPrincipal()
+ {
+ // Arrange
+ var principal = (ClaimsPrincipal) null;
+
+ // Act and assert
+ var exception = Assert.Throws(() => principal.GetClaims("type"));
+
+ Assert.Equal("principal", exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void GetClaims_ThrowsAnExceptionForNullOrEmptyClaimType(string type)
+ {
+ // Arrange
+ var principal = new ClaimsPrincipal();
+
+ // Act and assert
+ var exception = Assert.Throws(() => principal.GetClaims(type));
+
+ Assert.Equal("type", exception.ParamName);
+ Assert.StartsWith("The claim type cannot be null or empty.", exception.Message);
+ }
+
+ [Fact]
+ public void GetClaims_ReturnsExpectedResult()
+ {
+ // Arrange
+ var identity = new ClaimsIdentity();
+ identity.AddClaim(new Claim(Claims.Name, "Bob le Bricoleur"));
+ identity.AddClaim(new Claim(Claims.Scope, Scopes.OpenId));
+ identity.AddClaim(new Claim(Claims.Scope, Scopes.Profile));
+
+ var principal = new ClaimsPrincipal(identity);
+
+ // Act and assert
+ Assert.Equal(new[] { Scopes.OpenId, Scopes.Profile }, principal.GetClaims(Claims.Scope));
+ }
+
+ [Fact]
+ public void HasClaim_ThrowsAnExceptionForNullPrincipal()
+ {
+ // Arrange
+ var principal = (ClaimsPrincipal) null;
+
+ // Act and assert
+ var exception = Assert.Throws(() => principal.HasClaim("type"));
+
+ Assert.Equal("principal", exception.ParamName);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ public void HasClaim_ThrowsAnExceptionForNullOrEmptyClaimType(string type)
+ {
+ // Arrange
+ var principal = new ClaimsPrincipal();
+
+ // Act and assert
+ var exception = Assert.Throws(() => principal.HasClaim(type));
+
+ Assert.Equal("type", exception.ParamName);
+ Assert.StartsWith("The claim type cannot be null or empty.", exception.Message);
+ }
+
+ [Fact]
+ public void HasClaim_ReturnsExpectedResult()
+ {
+ // Arrange
+ var identity = new ClaimsIdentity();
+ identity.AddClaim(new Claim(Claims.Name, "Bob le Bricoleur"));
+ identity.AddClaim(new Claim(Claims.Scope, Scopes.OpenId));
+ identity.AddClaim(new Claim(Claims.Scope, Scopes.Profile));
+
+ var principal = new ClaimsPrincipal(identity);
+
+ // Act and assert
+ Assert.True(principal.HasClaim(Claims.Name));
+ Assert.True(principal.HasClaim(Claims.Scope));
+ Assert.False(principal.HasClaim(Claims.Nickname));
+ }
+
[Fact]
public void RemoveClaims_ThrowsAnExceptionForNullPrincipal()
{
@@ -2413,25 +2485,23 @@ namespace OpenIddict.Abstractions.Tests.Primitives
var principal = (ClaimsPrincipal) null;
// Act and assert
- var exception = Assert.Throws(() => principal.SetCreationDate(default(DateTimeOffset)));
+ var exception = Assert.Throws(() => principal.SetCreationDate(date: null));
Assert.Equal("principal", exception.ParamName);
}
- [Theory]
- [InlineData(null)]
- [InlineData("62")]
- public void SetCreationDate_AddsIssuedAtClaim(string date)
+ [Fact]
+ public void SetCreationDate_AddsClaim()
{
// Arrange
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
// Act
- principal.SetCreationDate(ParseDateTimeOffset(date));
+ principal.SetCreationDate(new DateTimeOffset(2020, 01, 01, 05, 30, 30, TimeSpan.FromHours(1)));
// Assert
- Assert.Equal(date, principal.GetClaim(Claims.IssuedAt));
+ Assert.Equal("Wed, 01 Jan 2020 04:30:30 GMT", principal.GetClaim(Claims.Private.CreationDate));
}
[Fact]
@@ -2441,25 +2511,23 @@ namespace OpenIddict.Abstractions.Tests.Primitives
var principal = (ClaimsPrincipal) null;
// Act and assert
- var exception = Assert.Throws(() => principal.SetExpirationDate(default(DateTimeOffset)));
+ var exception = Assert.Throws(() => principal.SetExpirationDate(date: null));
Assert.Equal("principal", exception.ParamName);
}
- [Theory]
- [InlineData(null)]
- [InlineData("62")]
- public void SetExpirationDate_AddsExpiresAtClaim(string date)
+ [Fact]
+ public void SetExpirationDate_AddsClaim()
{
// Arrange
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
// Act
- principal.SetExpirationDate(ParseDateTimeOffset(date));
+ principal.SetExpirationDate(new DateTimeOffset(2020, 01, 01, 05, 30, 30, TimeSpan.FromHours(1)));
// Assert
- Assert.Equal(date, principal.GetClaim(Claims.ExpiresAt));
+ Assert.Equal("Wed, 01 Jan 2020 04:30:30 GMT", principal.GetClaim(Claims.Private.ExpirationDate));
}
[Fact]
@@ -2491,7 +2559,7 @@ namespace OpenIddict.Abstractions.Tests.Primitives
principal.SetAudiences(audiences);
// Assert
- Assert.Equal(audience, principal.GetClaims(Claims.Audience));
+ Assert.Equal(audience, principal.GetClaims(Claims.Private.Audience));
}
[Fact]
@@ -2799,13 +2867,13 @@ namespace OpenIddict.Abstractions.Tests.Primitives
}
[Fact]
- public void SetInternalAuthorizationId_ThrowsAnExceptionForNullPrincipal()
+ public void SetAuthorizationId_ThrowsAnExceptionForNullPrincipal()
{
// Arrange
var principal = (ClaimsPrincipal) null;
// Act and assert
- var exception = Assert.Throws(() => principal.SetInternalAuthorizationId(null));
+ var exception = Assert.Throws(() => principal.SetAuthorizationId(null));
Assert.Equal("principal", exception.ParamName);
}
@@ -2813,27 +2881,27 @@ namespace OpenIddict.Abstractions.Tests.Primitives
[Theory]
[InlineData(null)]
[InlineData("identifier")]
- public void SetInternalAuthorizationId_AddsScopes(string identifier)
+ public void SetAuthorizationId_AddsScopes(string identifier)
{
// Arrange
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
// Act
- principal.SetInternalAuthorizationId(identifier);
+ principal.SetAuthorizationId(identifier);
// Assert
Assert.Equal(identifier, principal.GetClaim(Claims.Private.AuthorizationId));
}
[Fact]
- public void SetInternalTokenId_ThrowsAnExceptionForNullPrincipal()
+ public void SetTokenId_ThrowsAnExceptionForNullPrincipal()
{
// Arrange
var principal = (ClaimsPrincipal) null;
// Act and assert
- var exception = Assert.Throws(() => principal.SetInternalTokenId(null));
+ var exception = Assert.Throws(() => principal.SetTokenId(null));
Assert.Equal("principal", exception.ParamName);
}
@@ -2841,14 +2909,14 @@ namespace OpenIddict.Abstractions.Tests.Primitives
[Theory]
[InlineData(null)]
[InlineData("identifier")]
- public void SetInternalTokenId_AddsScopes(string identifier)
+ public void SetTokenId_AddsScopes(string identifier)
{
// Arrange
var identity = new ClaimsIdentity();
var principal = new ClaimsPrincipal(identity);
// Act
- principal.SetInternalTokenId(identifier);
+ principal.SetTokenId(identifier);
// Assert
Assert.Equal(identifier, principal.GetClaim(Claims.Private.TokenId));
@@ -2890,14 +2958,5 @@ namespace OpenIddict.Abstractions.Tests.Primitives
return lifeT;
}
-
- private DateTimeOffset? ParseDateTimeOffset(string dateTimeOffset)
- {
- var dtOffset = string.IsNullOrWhiteSpace(dateTimeOffset)
- ? null
- : (DateTimeOffset?)DateTimeOffset.FromUnixTimeSeconds(long.Parse(dateTimeOffset, NumberStyles.Number, CultureInfo.InvariantCulture));
-
- return dtOffset;
- }
}
}
diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs
index b6a8bb17..7175a380 100644
--- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs
+++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Exchange.cs
@@ -1669,7 +1669,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -1733,7 +1733,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur")
.SetClaim(Claims.Private.CodeChallenge, "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM")
.SetClaim(Claims.Private.CodeChallengeMethod, CodeChallengeMethods.Sha256);
@@ -1885,7 +1885,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -1947,7 +1947,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2002,7 +2002,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2072,7 +2072,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2137,7 +2137,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2215,7 +2215,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2275,8 +2275,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2368,8 +2368,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2470,8 +2470,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2568,8 +2568,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2641,8 +2641,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2725,8 +2725,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2784,8 +2784,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2883,8 +2883,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2965,8 +2965,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -3061,8 +3061,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -3152,8 +3152,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -3234,8 +3234,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -3332,7 +3332,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(context.TokenType)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("0270F515-C5B1-4FBF-B673-D7CAF7CCDABC")
+ .SetTokenId("0270F515-C5B1-4FBF-B673-D7CAF7CCDABC")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
if (context.Request.IsAuthorizationCodeGrantType())
diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Introspection.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Introspection.cs
index 4ba20eb9..3f7efb60 100644
--- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Introspection.cs
+++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Introspection.cs
@@ -1219,8 +1219,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetAudiences("Fabrikam")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetTokenType(TokenTypeHints.AccessToken)
.SetClaim(Claims.Subject, "Bob le Magnifique");
@@ -1310,8 +1310,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetAudiences("Fabrikam")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetTokenType(TokenTypeHints.AccessToken)
.SetClaim(Claims.Subject, "Bob le Magnifique");
@@ -1408,8 +1408,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetAudiences("Fabrikam")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetTokenType(TokenTypeHints.AccessToken)
.SetClaim(Claims.Subject, "Bob le Magnifique");
@@ -1519,8 +1519,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetAudiences("Fabrikam")
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetTokenType(TokenTypeHints.AccessToken)
.SetClaim(Claims.Subject, "Bob le Magnifique");
diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Revocation.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Revocation.cs
index afa2c260..8d89ddbd 100644
--- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Revocation.cs
+++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.Revocation.cs
@@ -674,7 +674,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56");
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56");
return default;
});
@@ -732,7 +732,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56");
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56");
return default;
});
@@ -793,7 +793,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56");
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56");
return default;
});
diff --git a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs
index c9fd481d..796ac9a1 100644
--- a/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs
+++ b/test/OpenIddict.Server.IntegrationTests/OpenIddictServerIntegrationTests.cs
@@ -217,6 +217,106 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal("Bob le Magnifique", (string) response[Claims.Subject]);
}
+ [Fact]
+ public async Task ProcessAuthentication_IssuedAtIsMappedToCreationDate()
+ {
+ // Arrange
+ var client = CreateClient(options =>
+ {
+ options.EnableDegradedMode();
+ options.SetUserinfoEndpointUris("/authenticate");
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ context.SkipRequest();
+
+ return default;
+ }));
+
+ options.AddEventHandler(builder =>
+ {
+ builder.UseInlineHandler(context =>
+ {
+ Assert.Equal("access_token", context.Token);
+ Assert.Equal(TokenTypeHints.AccessToken, context.TokenType);
+
+ var identity = new ClaimsIdentity("Bearer");
+ identity.AddClaim(new Claim(Claims.IssuedAt, "1577836800", ClaimValueTypes.Integer64));
+
+ context.Principal = new ClaimsPrincipal(identity)
+ .SetTokenType(TokenTypeHints.AccessToken)
+ .SetClaim(Claims.Subject, "Bob le Magnifique");
+
+ return default;
+ });
+
+ builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500);
+ });
+ });
+
+ // Act
+ var response = await client.GetAsync("/authenticate", new OpenIddictRequest
+ {
+ AccessToken = "access_token"
+ });
+
+ // Assert
+ Assert.Equal("Bob le Magnifique", (string) response[Claims.Subject]);
+ Assert.Equal(1577836800, (long) response[Claims.IssuedAt]);
+ Assert.Equal("Wed, 01 Jan 2020 00:00:00 GMT", (string) response[Claims.Private.CreationDate]);
+ }
+
+ [Fact]
+ public async Task ProcessAuthentication_ExpiresAtIsMappedToExpirationDate()
+ {
+ // Arrange
+ var client = CreateClient(options =>
+ {
+ options.EnableDegradedMode();
+ options.SetUserinfoEndpointUris("/authenticate");
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ context.SkipRequest();
+
+ return default;
+ }));
+
+ options.AddEventHandler(builder =>
+ {
+ builder.UseInlineHandler(context =>
+ {
+ Assert.Equal("access_token", context.Token);
+ Assert.Equal(TokenTypeHints.AccessToken, context.TokenType);
+
+ var identity = new ClaimsIdentity("Bearer");
+ identity.AddClaim(new Claim(Claims.ExpiresAt, "2524608000", ClaimValueTypes.Integer64));
+
+ context.Principal = new ClaimsPrincipal(identity)
+ .SetTokenType(TokenTypeHints.AccessToken)
+ .SetClaim(Claims.Subject, "Bob le Magnifique");
+
+ return default;
+ });
+
+ builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500);
+ });
+ });
+
+ // Act
+ var response = await client.GetAsync("/authenticate", new OpenIddictRequest
+ {
+ AccessToken = "access_token"
+ });
+
+ // Assert
+ Assert.Equal("Bob le Magnifique", (string) response[Claims.Subject]);
+ Assert.Equal(2524608000, (long) response[Claims.ExpiresAt]);
+ Assert.Equal("Sat, 01 Jan 2050 00:00:00 GMT", (string) response[Claims.Private.ExpirationDate]);
+ }
+
[Fact]
public async Task ProcessAuthentication_AuthorizedPartyIsMappedToPresenter()
{
@@ -265,6 +365,150 @@ namespace OpenIddict.Server.FunctionalTests
Assert.Equal("Fabrikam", (string) response[Claims.Private.Presenter]);
}
+ [Fact]
+ public async Task ProcessAuthentication_ClientIdIsMappedToPresenter()
+ {
+ // Arrange
+ var client = CreateClient(options =>
+ {
+ options.EnableDegradedMode();
+ options.SetUserinfoEndpointUris("/authenticate");
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ context.SkipRequest();
+
+ return default;
+ }));
+
+ options.AddEventHandler(builder =>
+ {
+ builder.UseInlineHandler(context =>
+ {
+ Assert.Equal("access_token", context.Token);
+ Assert.Equal(TokenTypeHints.AccessToken, context.TokenType);
+
+ context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
+ .SetTokenType(TokenTypeHints.AccessToken)
+ .SetClaim(Claims.Subject, "Bob le Magnifique")
+ .SetClaim(Claims.ClientId, "Fabrikam");
+
+ return default;
+ });
+
+ builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500);
+ });
+ });
+
+ // Act
+ var response = await client.GetAsync("/authenticate", new OpenIddictRequest
+ {
+ AccessToken = "access_token"
+ });
+
+ // Assert
+ Assert.Equal("Bob le Magnifique", (string) response[Claims.Subject]);
+ Assert.Equal("Fabrikam", (string) response[Claims.ClientId]);
+ Assert.Equal("Fabrikam", (string) response[Claims.Private.Presenter]);
+ }
+
+ [Fact]
+ public async Task ProcessAuthentication_SinglePublicAudienceIsMappedToPrivateClaims()
+ {
+ // Arrange
+ var client = CreateClient(options =>
+ {
+ options.EnableDegradedMode();
+ options.SetUserinfoEndpointUris("/authenticate");
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ context.SkipRequest();
+
+ return default;
+ }));
+
+ options.AddEventHandler(builder =>
+ {
+ builder.UseInlineHandler(context =>
+ {
+ Assert.Equal("access_token", context.Token);
+ Assert.Equal(TokenTypeHints.AccessToken, context.TokenType);
+
+ context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
+ .SetTokenType(TokenTypeHints.AccessToken)
+ .SetClaim(Claims.Subject, "Bob le Magnifique")
+ .SetClaim(Claims.Audience, "Fabrikam");
+
+ return default;
+ });
+
+ builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500);
+ });
+ });
+
+ // Act
+ var response = await client.GetAsync("/authenticate", new OpenIddictRequest
+ {
+ AccessToken = "access_token"
+ });
+
+ // Assert
+ Assert.Equal("Bob le Magnifique", (string) response[Claims.Subject]);
+ Assert.Equal("Fabrikam", (string) response[Claims.Audience]);
+ Assert.Equal("Fabrikam", (string) response[Claims.Private.Audience]);
+ }
+
+ [Fact]
+ public async Task ProcessAuthentication_MultiplePublicAudiencesAreMappedToPrivateClaims()
+ {
+ // Arrange
+ var client = CreateClient(options =>
+ {
+ options.EnableDegradedMode();
+ options.SetUserinfoEndpointUris("/authenticate");
+
+ options.AddEventHandler(builder =>
+ builder.UseInlineHandler(context =>
+ {
+ context.SkipRequest();
+
+ return default;
+ }));
+
+ options.AddEventHandler(builder =>
+ {
+ builder.UseInlineHandler(context =>
+ {
+ Assert.Equal("access_token", context.Token);
+ Assert.Equal(TokenTypeHints.AccessToken, context.TokenType);
+
+ context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
+ .SetTokenType(TokenTypeHints.AccessToken)
+ .SetClaim(Claims.Subject, "Bob le Magnifique")
+ .SetClaims(Claims.Audience, ImmutableArray.Create("Fabrikam", "Contoso"));
+
+ return default;
+ });
+
+ builder.SetOrder(ValidateIdentityModelToken.Descriptor.Order - 500);
+ });
+ });
+
+ // Act
+ var response = await client.GetAsync("/authenticate", new OpenIddictRequest
+ {
+ AccessToken = "access_token"
+ });
+
+ // Assert
+ Assert.Equal("Bob le Magnifique", (string) response[Claims.Subject]);
+ Assert.Equal(new[] { "Fabrikam", "Contoso" }, (string[]) response[Claims.Audience]);
+ Assert.Equal(new[] { "Fabrikam", "Contoso" }, (string[]) response[Claims.Private.Audience]);
+ }
+
[Fact]
public async Task ProcessAuthentication_SinglePublicScopeIsMappedToPrivateClaims()
{
@@ -2666,7 +2910,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2736,7 +2980,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.AuthorizationCode)
.SetPresenters("Fabrikam")
- .SetInternalTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
+ .SetTokenId("3E228451-1555-46F7-A471-951EFBA23A56")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2821,7 +3065,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2886,7 +3130,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -2946,7 +3190,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -3030,8 +3274,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -3120,8 +3364,8 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
- .SetInternalAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetAuthorizationId("18D15F73-BE2B-6867-DC01-B3C1E8AFDED0")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -3197,7 +3441,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -3258,7 +3502,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -3320,7 +3564,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -3386,7 +3630,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;
@@ -3450,7 +3694,7 @@ namespace OpenIddict.Server.FunctionalTests
context.Principal = new ClaimsPrincipal(new ClaimsIdentity("Bearer"))
.SetTokenType(TokenTypeHints.RefreshToken)
.SetScopes(Scopes.OpenId, Scopes.OfflineAccess)
- .SetInternalTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
+ .SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103")
.SetClaim(Claims.Subject, "Bob le Bricoleur");
return default;