private static TokenManager GetTokenManager()
        {
            var options       = CreateOptions();
            var claimsManager = CreateClaimsManager(options);

            var factory                = new LoggerFactory();
            var protector              = new EphemeralDataProtectionProvider(factory).CreateProtector("test");
            var codeSerializer         = new TokenDataSerializer <AuthorizationCode>(options, ArrayPool <char> .Shared);
            var codeDataFormat         = new SecureDataFormat <AuthorizationCode>(codeSerializer, protector);
            var refreshTokenSerializer = new TokenDataSerializer <RefreshToken>(options, ArrayPool <char> .Shared);
            var refreshTokenDataFormat = new SecureDataFormat <RefreshToken>(refreshTokenSerializer, protector);

            var timeStampManager   = new TimeStampManager();
            var credentialsPolicy  = GetCredentialsPolicy(options, timeStampManager);
            var codeIssuer         = new AuthorizationCodeIssuer(claimsManager, codeDataFormat, new ProtocolErrorProvider());
            var accessTokenIssuer  = new JwtAccessTokenIssuer(claimsManager, credentialsPolicy, new JwtSecurityTokenHandler(), options);
            var idTokenIssuer      = new JwtIdTokenIssuer(claimsManager, credentialsPolicy, new JwtSecurityTokenHandler(), options);
            var refreshTokenIssuer = new RefreshTokenIssuer(claimsManager, refreshTokenDataFormat);

            return(new TokenManager(
                       codeIssuer,
                       accessTokenIssuer,
                       idTokenIssuer,
                       refreshTokenIssuer,
                       new ProtocolErrorProvider()));
        }
        public async Task JwtIdTokenIssuer_IncludesAllRequiredData()
        {
            // Arrange
            var options          = GetOptions();
            var hasher           = GetHasher();
            var expectedDateTime = new DateTimeOffset(2000, 01, 01, 0, 0, 0, TimeSpan.FromHours(1));
            var timeManager      = GetTimeManager(expectedDateTime, expectedDateTime.AddHours(1), expectedDateTime);
            var issuer           = new JwtIdTokenIssuer(GetClaimsManager(timeManager), GetSigningPolicy(options, timeManager), new JwtSecurityTokenHandler(), options);
            var context          = GetTokenGenerationContext(
                new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "user") })),
                new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(IdentityServiceClaimTypes.ClientId, "clientId") })));

            context.InitializeForToken(TokenTypes.IdToken);

            // Act
            await issuer.IssueIdTokenAsync(context);

            // Assert
            Assert.NotNull(context.IdToken);
            var result = Assert.IsType <IdToken>(context.IdToken.Token);

            Assert.NotNull(result);
            Assert.NotNull(result.Id);
            Assert.Equal("user", result.Subject);
            Assert.Equal("clientId", result.Audience);
            Assert.Equal(expectedDateTime, result.IssuedAt);
            Assert.Equal(expectedDateTime.AddHours(1), result.Expires);
            Assert.Equal(expectedDateTime, result.NotBefore);
            Assert.Equal("asdf", result.Nonce);
        }
        public async Task JwtIdTokenIssuer_SignsAccessToken()
        {
            // Arrange
            var expectedDateTime = new DateTimeOffset(2000, 01, 01, 0, 0, 0, TimeSpan.FromHours(1));
            var now         = DateTimeOffset.UtcNow;
            var expires     = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, TimeSpan.Zero);
            var timeManager = GetTimeManager(expectedDateTime, expires, expectedDateTime);

            var hasher  = GetHasher();
            var options = GetOptions();

            var handler = new JwtSecurityTokenHandler();

            var tokenValidationParameters = new TokenValidationParameters
            {
                IssuerSigningKey = options.Value.SigningKeys[0].Key,
                ValidAudiences   = new[] { "clientId" },
                ValidIssuers     = new[] { options.Value.Issuer }
            };

            var issuer  = new JwtIdTokenIssuer(GetClaimsManager(timeManager), GetSigningPolicy(options, timeManager), new JwtSecurityTokenHandler(), options);
            var context = GetTokenGenerationContext(
                new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "user") })),
                new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(IdentityServiceClaimTypes.ClientId, "clientId") })));

            context.InitializeForToken(TokenTypes.IdToken);

            // Act
            await issuer.IssueIdTokenAsync(context);

            // Assert
            Assert.NotNull(context.IdToken);
            Assert.NotNull(context.IdToken.SerializedValue);

            SecurityToken validatedToken;

            Assert.NotNull(handler.ValidateToken(context.IdToken.SerializedValue, tokenValidationParameters, out validatedToken));
            Assert.NotNull(validatedToken);

            var jwtToken = Assert.IsType <JwtSecurityToken>(validatedToken);
            var result   = Assert.IsType <IdToken>(context.IdToken.Token);

            Assert.Equal("http://www.example.com/issuer", jwtToken.Issuer);
            var tokenAudience = Assert.Single(jwtToken.Audiences);

            Assert.Equal("clientId", tokenAudience);
            Assert.Equal("user", jwtToken.Subject);

            Assert.Equal(expires, jwtToken.ValidTo);
            Assert.Equal(expectedDateTime.UtcDateTime, jwtToken.ValidFrom);
        }
        public async Task JwtIdTokenIssuer_Fails_IfUserIsMissingUserId()
        {
            // Arrange
            var options     = GetOptions();
            var timeManager = GetTimeManager();
            var hasher      = GetHasher();

            var issuer  = new JwtIdTokenIssuer(GetClaimsManager(), GetSigningPolicy(options, timeManager), new JwtSecurityTokenHandler(), options);
            var context = GetTokenGenerationContext();

            context.InitializeForToken(TokenTypes.IdToken);

            // Act
            var exception = await Assert.ThrowsAsync <InvalidOperationException>(
                () => issuer.IssueIdTokenAsync(context));

            // Assert
            Assert.Equal($"Missing '{ClaimTypes.NameIdentifier}' claim from the user.", exception.Message);
        }
        public async Task JwtIdTokenIssuer_IncludesNonceAndTokenHashesWhenPresent(string nonce, string code, string accessToken)
        {
            // Arrange
            var expectedCHash  = code != null ? $"#{code}" : null;
            var expectedAtHash = accessToken != null ? $"#{accessToken}" : null;

            var expectedDateTime = new DateTimeOffset(2000, 01, 01, 0, 0, 0, TimeSpan.FromHours(1));
            var expires          = DateTimeOffset.UtcNow.AddHours(1);
            var timeManager      = GetTimeManager(expectedDateTime, expires, expectedDateTime);

            var options = GetOptions();

            var handler = new JwtSecurityTokenHandler();

            var tokenValidationParameters = new TokenValidationParameters
            {
                IssuerSigningKey = options.Value.SigningKeys[0].Key,
                ValidAudiences   = new[] { "clientId" },
                ValidIssuers     = new[] { options.Value.Issuer }
            };

            var issuer  = new JwtIdTokenIssuer(GetClaimsManager(timeManager), GetSigningPolicy(options, timeManager), new JwtSecurityTokenHandler(), options);
            var context = GetTokenGenerationContext(
                new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "user") })),
                new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(IdentityServiceClaimTypes.ClientId, "clientId") })),
                nonce);

            if (code != null)
            {
                context.InitializeForToken(TokenTypes.AuthorizationCode);
                context.AddToken(new TokenResult(new AuthorizationCode(GetAuthorizationCodeClaims()), "code"));
            }

            if (accessToken != null)
            {
                context.InitializeForToken(TokenTypes.AccessToken);
                context.AddToken(new TokenResult(new AccessToken(GetAccessTokenClaims()), "accesstoken"));
            }

            context.InitializeForToken(TokenTypes.IdToken);

            // Act
            await issuer.IssueIdTokenAsync(context);

            // Assert
            Assert.NotNull(context.IdToken);
            Assert.NotNull(context.IdToken.SerializedValue);

            SecurityToken validatedToken;

            Assert.NotNull(handler.ValidateToken(context.IdToken.SerializedValue, tokenValidationParameters, out validatedToken));
            Assert.NotNull(validatedToken);

            var jwtToken = Assert.IsType <JwtSecurityToken>(validatedToken);
            var result   = Assert.IsType <IdToken>(context.IdToken.Token);

            Assert.Equal(nonce, result.Nonce);
            Assert.Equal(nonce, jwtToken.Payload.Nonce);
            Assert.Equal(expectedCHash, result.CodeHash);
            Assert.Equal(expectedCHash, jwtToken.Payload.CHash);
            Assert.Equal(expectedAtHash, result.AccessTokenHash);
            Assert.Equal(expectedAtHash, jwtToken.Payload.Claims.FirstOrDefault(c => c.Type == "at_hash")?.Value);
        }