public async Task OnGeneratingClaims_AddsRedirectUriIfPresentOnTheRequest() { // Arrange var expectedRedirectUri = "http://wwww.example.com/callback"; var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage() { RedirectUri = expectedRedirectUri }, new RequestGrants()); var options = new IdentityServiceOptions() { Issuer = "http://www.example.com/Identity" }; var claimsProvider = new DefaultTokenClaimsProvider(Options.Create(options)); context.InitializeForToken(TokenTypes.AuthorizationCode); // Act await claimsProvider.OnGeneratingClaims(context); // Assert Assert.Single( context.CurrentClaims, c => c.Type.Equals(IdentityServiceClaimTypes.RedirectUri, StringComparison.Ordinal) && c.Value.Equals(expectedRedirectUri)); }
public async Task OnGeneratingClaims_AddsGrantedTokensForAuthorizationCode( string scopes, string tokens) { // Arrange var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage(), new RequestGrants() { Scopes = scopes.Split(' ').Select(CreateScope).ToList() }); var expectedTokens = tokens.Split(' ').OrderBy(t => t).ToArray(); var claimsProvider = new GrantedTokensTokenClaimsProvider(); context.InitializeForToken(TokenTypes.AuthorizationCode); // Act await claimsProvider.OnGeneratingClaims(context); var granted = context.CurrentClaims .Where(c => c.Type.Equals(IdentityServiceClaimTypes.GrantedToken)) .OrderBy(c => c.Value) .Select(c => c.Value) .ToArray(); // Assert Assert.Equal(expectedTokens, granted); }
public async Task OnGeneratingClaims_AddsIssuerForAccessTokenAndIdToken(string tokenType) { // Arrange var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage(), new RequestGrants()); var options = new IdentityServiceOptions() { Issuer = "http://www.example.com/Identity" }; var claimsProvider = new DefaultTokenClaimsProvider(Options.Create(options)); context.InitializeForToken(tokenType); // Act await claimsProvider.OnGeneratingClaims(context); // Assert Assert.Single( context.CurrentClaims, c => c.Type.Equals(IdentityServiceClaimTypes.Issuer, StringComparison.Ordinal)); }
public Task OnGeneratingClaims(TokenGeneratingContext context) { if (context.CurrentToken.Equals(TokenTypes.IdToken) || context.CurrentToken.Equals(TokenTypes.AccessToken)) { var userId = context.User.FindFirstValue(_options.ClaimsIdentity.UserIdClaimType); var applicationId = context.Application.FindFirstValue(IdentityServiceClaimTypes.ObjectId); var unHashedSubjectBits = Encoding.ASCII.GetBytes($"{userId}/{applicationId}"); var hashing = CryptographyHelpers.CreateSHA256(); var subject = Base64UrlEncoder.Encode(hashing.ComputeHash(unHashedSubjectBits)); Claim existingClaim = null; foreach (var claim in context.CurrentClaims) { if (claim.Type.Equals(IdentityServiceClaimTypes.Subject, StringComparison.Ordinal)) { existingClaim = claim; } } if (existingClaim != null) { context.CurrentClaims.Remove(existingClaim); } context.CurrentClaims.Add(new Claim(IdentityServiceClaimTypes.Subject, subject)); } return(Task.CompletedTask); }
public async Task OnGeneratingClaims_AddsNonceToCodeAccessAndIdToken_WhenPresentInTheRequest(string tokenType) { // Arrange var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage() { Nonce = "nonce-value", RequestType = OpenIdConnectRequestType.Authentication }, new RequestGrants() { Claims = new List <Claim> { new Claim(IdentityServiceClaimTypes.Nonce, "invalid-nonce") } }); var claimsProvider = new NonceTokenClaimsProvider(); context.InitializeForToken(tokenType); // Act await claimsProvider.OnGeneratingClaims(context); var claims = context.CurrentClaims; // Assert Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Nonce) && c.Value.Equals("nonce-value")); }
public static void AddExtensionsAmbientClaims( this TokenGeneratingContext context, string policy, string version, string tenantId) { context.AmbientClaims.Add(new Claim(IdentityServiceExtensionsAmbientClaimTypes.Policy, policy)); context.AmbientClaims.Add(new Claim(IdentityServiceExtensionsAmbientClaimTypes.Version, version)); context.AmbientClaims.Add(new Claim(IdentityServiceExtensionsAmbientClaimTypes.TenantId, tenantId)); }
public async Task OnGeneratingClaims_AddsNonce_WhenPresentInTheGrantClaimsOfATokenRequest(string tokenType) { // Arrange var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage() { RequestType = OpenIdConnectRequestType.Token, // Makes sure we ignore the value from the request // for non authorization requests even when its present. Nonce = "invalid-value" }, new RequestGrants() { Claims = new List <Claim> { new Claim(IdentityServiceClaimTypes.Nonce, "nonce-value") } }); var claimsProvider = new NonceTokenClaimsProvider(); context.InitializeForToken(tokenType); // Act await claimsProvider.OnGeneratingClaims(context); var claims = context.CurrentClaims; // Assert Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Nonce) && c.Value.Equals("nonce-value")); }
public Task OnGeneratingClaims(TokenGeneratingContext context) { if (context.IsContextForTokenTypes(TokenTypes.IdToken)) { var accessToken = context .IssuedTokens.SingleOrDefault(t => t.Token.Kind == TokenTypes.AccessToken); var authorizationCode = context .IssuedTokens.SingleOrDefault(t => t.Token.Kind == TokenTypes.AuthorizationCode); if (accessToken != null) { context.CurrentClaims.Add(new Claim( IdentityServiceClaimTypes.AccessTokenHash, GetTokenHash(accessToken.SerializedValue))); } if (authorizationCode != null) { context.CurrentClaims.Add(new Claim( IdentityServiceClaimTypes.CodeHash, GetTokenHash(authorizationCode.SerializedValue))); } } return(Task.CompletedTask); }
public Task AddParameters(TokenGeneratingContext context, OpenIdConnectMessage response) { var clientInfo = CreateClientInfo(context); response.Parameters.Add(ClientInfo, clientInfo); return(Task.CompletedTask); }
public async Task OnGeneratingClaims_AddsAllScopesToAuthorizationCode() { // Arrange var applicationScopes = new List <ApplicationScope> { ApplicationScope.OpenId, new ApplicationScope("resourceId", "custom") }; var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage() { RequestType = OpenIdConnectRequestType.Authentication }, new RequestGrants() { Scopes = applicationScopes.ToList() }); var claimsProvider = new ScopesTokenClaimsProvider(); context.InitializeForToken(TokenTypes.AuthorizationCode); // Act await claimsProvider.OnGeneratingClaims(context); var claims = context.CurrentClaims; // Assert Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Scope) && c.Value.Equals("openid custom")); Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Resource) && c.Value.Equals("resourceId")); }
public async Task OnGeneratingClaims_AddsCustomScopesFromRequest_ToAccessTokenOnAuthorization() { // Arrange var applicationScopes = new List <ApplicationScope> { ApplicationScope.OpenId, new ApplicationScope("resourceId", "custom") }; var expectedResourceValue = applicationScopes.FirstOrDefault(s => s.ClientId != null)?.ClientId; var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage() { ClientId = "clientId" }, new RequestGrants() { Scopes = applicationScopes.ToList() }); var claimsProvider = new ScopesTokenClaimsProvider(); context.InitializeForToken(TokenTypes.AccessToken); // Act await claimsProvider.OnGeneratingClaims(context); var claims = context.CurrentClaims; // Assert Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Scope) && c.Value.Equals("custom")); Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Audience) && c.Value.Equals("resourceId")); Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.AuthorizedParty) && c.Value.Equals("clientId")); }
public async Task OnGeneratingClaims_AddsAtHashAndCHashClaimsWhenAvailable( string accessToken, string code) { // Arrange var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage { }, new RequestGrants { }); if (accessToken != null) { context.InitializeForToken(TokenTypes.AccessToken); context.AddToken(new TokenResult(new TestToken(TokenTypes.AccessToken), accessToken)); } if (code != null) { context.InitializeForToken(TokenTypes.AuthorizationCode); context.AddToken(new TokenResult(new TestToken(TokenTypes.AuthorizationCode), code)); } // Reference time var hasher = new Mock <ITokenHasher>(); hasher.Setup(h => h.HashToken("access_token", It.IsAny <string>())) .Returns("access_token_hash"); hasher.Setup(h => h.HashToken("code", It.IsAny <string>())) .Returns("code_hash"); var claimsProvider = new TokenHashTokenClaimsProvider(hasher.Object); context.InitializeForToken(TokenTypes.IdToken); // Act await claimsProvider.OnGeneratingClaims(context); var claims = context.CurrentClaims; // Assert if (accessToken != null) { Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.AccessTokenHash) && c.Value.Equals("access_token_hash")); } else { Assert.DoesNotContain(claims, c => c.Type.Equals(IdentityServiceClaimTypes.AccessTokenHash)); } if (code != null) { Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.CodeHash) && c.Value.Equals("code_hash")); } else { Assert.DoesNotContain(claims, c => c.Type.Equals(IdentityServiceClaimTypes.CodeHash)); } }
public async Task OnGeneratingClaims_DoesNotAddNonce_WhenNotPresentInTheRequest(string tokenType) { // Arrange var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage() { RequestType = OpenIdConnectRequestType.Authentication }, new RequestGrants() { // Makes sure we don't add the nonce in an authorization request // even if for some reason ends up in the claims grant (which is not // used in authentication). Claims = new List <Claim> { new Claim(IdentityServiceClaimTypes.Nonce, "nonce-value") } }); var claimsProvider = new NonceTokenClaimsProvider(); context.InitializeForToken(tokenType); // Act await claimsProvider.OnGeneratingClaims(context); var claims = context.CurrentClaims; // Assert Assert.DoesNotContain(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Nonce)); }
public string CreateClientInfo(TokenGeneratingContext context) { var userId = context.User.Claims.Single(c => string.Equals(c.Type, _options.ClaimsIdentity.UserIdClaimType, StringComparison.Ordinal)).Value; var tentantId = context.AmbientClaims.Single(c => string.Equals(c.Type, IdentityServiceExtensionsAmbientClaimTypes.TenantId, StringComparison.Ordinal)).Value; var json = JsonConvert.SerializeObject(new ClientInfoModel { UserId = userId, TenantId = tentantId }); return WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(json)); }
private void AddAmbientClaims(TokenGeneratingContext context) { context.AddExtensionsAmbientClaims( policy: IdentityServiceConstants.DefaultPolicy, version: IdentityServiceConstants.Version, tenantId: IdentityServiceConstants.TenantId ); }
private void AddClaimsForAccessToken(TokenGeneratingContext context, string resource) { var scopes = context.RequestGrants.Scopes; var accessTokenScopes = GetAccessTokenScopes(scopes); context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Scope, GetScopeValue(scopes, excludeCanonical: true)); context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Audience, resource); context.AddClaimToCurrentToken(IdentityServiceClaimTypes.AuthorizedParty, context.RequestParameters.ClientId); }
public Task OnGeneratingClaims(TokenGeneratingContext context) { var resource = context.RequestGrants.Scopes.FirstOrDefault(rg => rg.ClientId != null)?.ClientId; if (context.IsContextForTokenTypes(TokenTypes.AccessToken) && resource != null) { // For access tokens we use the scopes from the set of granted scopes, this takes into account the // fact that a token request can ask for a subset of the scopes granted during authorization, either // on a code exchange or on a refresh token grant flow. AddClaimsForAccessToken(context, resource); return(Task.CompletedTask); } if (context.IsContextForTokenTypes(TokenTypes.AuthorizationCode)) { context.AddClaimToCurrentToken( IdentityServiceClaimTypes.Scope, GetScopeValue(context.RequestGrants.Scopes, excludeCanonical: false)); if (resource != null) { context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Resource, resource); } return(Task.CompletedTask); } if (context.IsContextForTokenTypes(TokenTypes.RefreshToken)) { // For refresh tokens the scope claim never changes as the set of scopes granted for a refresh token // should not change no matter what scopes are sent on a token request. var scopeClaim = context .RequestGrants .Claims .Single(c => c.Type.Equals(IdentityServiceClaimTypes.Scope, StringComparison.Ordinal)); var resourceClaim = context .RequestGrants .Claims .SingleOrDefault(c => c.Type.Equals(IdentityServiceClaimTypes.Resource, StringComparison.Ordinal)); context.AddClaimToCurrentToken(scopeClaim); if (resourceClaim != null) { context.AddClaimToCurrentToken(resourceClaim); } } return(Task.CompletedTask); }
public Task OnGeneratingClaims(TokenGeneratingContext context) { var nonce = GetNonce(context); if (context.IsContextForTokenTypes( TokenTypes.IdToken, TokenTypes.AccessToken, TokenTypes.AuthorizationCode) && nonce != null) { context.AddClaimToCurrentToken(IdentityServiceClaimTypes.Nonce, nonce); } return(Task.CompletedTask); }
private static void MapFromPrincipal( TokenGeneratingContext context, ClaimsPrincipal user, TokenMapping claimsDefinition) { foreach (var mapping in claimsDefinition) { var foundClaims = user.FindAll(mapping.Alias); ValidateCardinality(mapping, foundClaims, claimsDefinition.Source); foreach (var userClaim in foundClaims) { context.AddClaimToCurrentToken(mapping.Name, userClaim.Value); } } }
private static void MapFromContext( TokenGeneratingContext context, IList <Claim> ambientClaims, TokenMapping claimsDefinition) { foreach (var mapping in claimsDefinition) { var ctxValues = ambientClaims.Where(c => c.Type == mapping.Alias); ValidateCardinality(mapping, ctxValues, claimsDefinition.Source); foreach (var ctxValue in ctxValues) { context.AddClaimToCurrentToken(mapping.Name, ctxValue.Value); } } }
public Task OnGeneratingClaims(TokenGeneratingContext context) { if (context.IsContextForTokenTypes(TokenTypes.AuthorizationCode) && context.RequestParameters.Parameters.ContainsKey(ProofOfKeyForCodeExchangeParameterNames.CodeChallenge)) { context.AddClaimToCurrentToken( IdentityServiceClaimTypes.CodeChallenge, context.RequestParameters.Parameters[ProofOfKeyForCodeExchangeParameterNames.CodeChallenge]); context.AddClaimToCurrentToken( IdentityServiceClaimTypes.CodeChallengeMethod, context.RequestParameters.Parameters[ProofOfKeyForCodeExchangeParameterNames.CodeChallengeMethod]); } return(Task.CompletedTask); }
private IEnumerable <string> GetGrantedTokensForAuthorizationCode(TokenGeneratingContext context) { if (context.RequestGrants.Scopes.Any(s => s.ClientId != null)) { yield return(TokenTypes.AccessToken); } if (context.RequestGrants.Scopes.Contains(ApplicationScope.OpenId)) { yield return(TokenTypes.IdToken); } if (context.RequestGrants.Scopes.Contains(ApplicationScope.OfflineAccess)) { yield return(TokenTypes.RefreshToken); } }
public Task OnGeneratingClaims(TokenGeneratingContext context) { var options = GetOptions(context.CurrentToken); context.CurrentClaims.Add(new Claim( IdentityServiceClaimTypes.NotBefore, _timeStampManager.GetTimeStampInEpochTime(options.NotValidBefore))); context.CurrentClaims.Add(new Claim( IdentityServiceClaimTypes.IssuedAt, _timeStampManager.GetCurrentTimeStampInEpochTime())); context.CurrentClaims.Add(new Claim( IdentityServiceClaimTypes.Expires, _timeStampManager.GetTimeStampInEpochTime(options.NotValidAfter))); return(Task.CompletedTask); }
public async Task OnGeneratingClaims_AddsAllScopesFromGrantClaims_ToRefreshTokenOnTokenRequest() { // Arrange // This is just to prove that we always transfer the scope and resource claims from the grant // into the refresh token untouched. var applicationScopes = new List <ApplicationScope> { ApplicationScope.OpenId, new ApplicationScope("resourceId", "custom"), new ApplicationScope("resourceId", "custom2") }; var expectedResourceValue = applicationScopes.FirstOrDefault(s => s.ClientId != null)?.ClientId; var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage() { ClientId = "clientId" }, new RequestGrants() { Scopes = applicationScopes.ToList(), Claims = new List <Claim> { new Claim(IdentityServiceClaimTypes.Resource, "ridClaim"), new Claim(IdentityServiceClaimTypes.Scope, "openid custom3") } }); var claimsProvider = new ScopesTokenClaimsProvider(); context.InitializeForToken(TokenTypes.RefreshToken); // Act await claimsProvider.OnGeneratingClaims(context); var claims = context.CurrentClaims; // Assert Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Scope) && c.Value.Equals("openid custom3")); Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Resource) && c.Value.Equals("ridClaim")); }
public async Task OnGeneratingClaims_AddsCustomScopesFromRequest_ToAccessTokenOnTokenRequest() { // Arrange var applicationScopes = new List <ApplicationScope> { ApplicationScope.OpenId, new ApplicationScope("resourceId", "custom"), new ApplicationScope("resourceId", "custom2") }; var expectedResourceValue = applicationScopes.FirstOrDefault(s => s.ClientId != null)?.ClientId; var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage() { ClientId = "clientId" }, new RequestGrants() { Scopes = applicationScopes.ToList(), // This is just to prove that we always pick the values for the scope related claims // from the set of granted scopes (for access tokens). Claims = new List <Claim> { new Claim(IdentityServiceClaimTypes.Resource, "ridClaim"), new Claim(IdentityServiceClaimTypes.Scope, "custom3") } }); var claimsProvider = new ScopesTokenClaimsProvider(); context.InitializeForToken(TokenTypes.AccessToken); // Act await claimsProvider.OnGeneratingClaims(context); var claims = context.CurrentClaims; // Assert Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Scope) && c.Value.Equals("custom custom2")); Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Audience) && c.Value.Equals("resourceId")); Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.AuthorizedParty) && c.Value.Equals("clientId")); }
public Task OnGeneratingClaims(TokenGeneratingContext context) { if (context.IsContextForTokenTypes(TokenTypes.AuthorizationCode)) { foreach (var grantedToken in GetGrantedTokensForAuthorizationCode(context)) { context.AddClaimToCurrentToken(IdentityServiceClaimTypes.GrantedToken, grantedToken); } } if (context.IsContextForTokenTypes(TokenTypes.RefreshToken)) { foreach (var grantedToken in context.RequestGrants.Tokens) { context.AddClaimToCurrentToken(IdentityServiceClaimTypes.GrantedToken, grantedToken); } } return(Task.CompletedTask); }
public async Task OnGeneratingClaims_AddsGrantedTokensForRefreshToken() { // Arrange var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage(), new RequestGrants() { Tokens = new List <string> { TokenTypes.AccessToken, TokenTypes.IdToken, TokenTypes.RefreshToken } }); var expectedTokens = new[] { TokenTypes.AccessToken, TokenTypes.IdToken, TokenTypes.RefreshToken }; var claimsProvider = new GrantedTokensTokenClaimsProvider(); context.InitializeForToken(TokenTypes.RefreshToken); // Act await claimsProvider.OnGeneratingClaims(context); var granted = context.CurrentClaims .Where(c => c.Type.Equals(IdentityServiceClaimTypes.GrantedToken)) .OrderBy(c => c.Value) .Select(c => c.Value) .ToArray(); // Assert Assert.Equal(expectedTokens, granted); }
public async Task OnGeneratingClaims_AddsIssuedAtNotBeforeAndExpires_ForAllTokenTypes( string tokenType, string issuedAt, string notBefore, string expires) { // Arrange var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage { }, new RequestGrants { }); // Reference time var reference = new DateTimeOffset(2000, 01, 01, 0, 0, 0, TimeSpan.Zero); var timestampManager = new TestTimeStampManager(reference); var options = new IdentityServiceOptions(); SetTimeStampOptions(options.AuthorizationCodeOptions, 1); SetTimeStampOptions(options.AccessTokenOptions, 2); SetTimeStampOptions(options.IdTokenOptions, 3); SetTimeStampOptions(options.RefreshTokenOptions, 4); var claimsProvider = new TimestampsTokenClaimsProvider(timestampManager, Options.Create(options)); context.InitializeForToken(tokenType); // Act await claimsProvider.OnGeneratingClaims(context); var claims = context.CurrentClaims; // Assert Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.IssuedAt) && c.Value.Equals(issuedAt)); Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.NotBefore) && c.Value.Equals(notBefore)); Assert.Single(claims, c => c.Type.Equals(IdentityServiceClaimTypes.Expires) && c.Value.Equals(expires)); }
public async Task OnGeneratingClaims_DoesNothing_IfChallengeNotPresent() { // Arrange var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage(new Dictionary <string, string[]> { [ProofOfKeyForCodeExchangeParameterNames.CodeChallengeMethod] = new[] { "S256" }, }), new RequestGrants()); context.InitializeForToken(TokenTypes.AuthorizationCode); var provider = new ProofOfKeyForCodeExchangeTokenClaimsProvider(); // Act await provider.OnGeneratingClaims(context); // Assert Assert.Empty(context.CurrentClaims); }
public async Task OnGeneratingClaims_AddsCodeChallengeAndChallengeMethod_ToTheAuthorizationCode() { // Arrange var context = new TokenGeneratingContext( new ClaimsPrincipal(), new ClaimsPrincipal(), new OpenIdConnectMessage(new Dictionary <string, string[]> { [ProofOfKeyForCodeExchangeParameterNames.CodeChallenge] = new[] { "challenge" }, [ProofOfKeyForCodeExchangeParameterNames.CodeChallengeMethod] = new[] { "S256" }, }), new RequestGrants()); context.InitializeForToken(TokenTypes.AuthorizationCode); var provider = new ProofOfKeyForCodeExchangeTokenClaimsProvider(); // Act await provider.OnGeneratingClaims(context); // Assert Assert.Contains(context.CurrentClaims, c => c.Type == IdentityServiceClaimTypes.CodeChallenge && c.Value == "challenge"); Assert.Contains(context.CurrentClaims, c => c.Type == IdentityServiceClaimTypes.CodeChallengeMethod && c.Value == "S256"); }