private async Task UpdateUserAsync(ApplicationUser user,
                                           BuildAssetRegistryContext dbContext,
                                           UserManager <ApplicationUser> userManager,
                                           SignInManager <ApplicationUser> signInManager,
                                           GitHubClaimResolver gitHubClaimResolver)
        {
            using (IDbContextTransaction txn = await dbContext.Database.BeginTransactionAsync())
            {
                string token = await userManager.GetAuthenticationTokenAsync(user, GitHubScheme, "access_token");

                var newClaims = (await gitHubClaimResolver.GetUserInformationClaims(token)).Concat(
                    await gitHubClaimResolver.GetMembershipClaims(token)
                    ).Where(AccountController.ShouldAddClaimToUser);
                var currentClaims = (await userManager.GetClaimsAsync(user)).ToList();

                // remove old claims
                await userManager.RemoveClaimsAsync(user, currentClaims);

                // add new claims
                await userManager.AddClaimsAsync(user, newClaims);

                user.LastUpdated = DateTimeOffset.UtcNow;
                await dbContext.SaveChangesAsync();

                txn.Commit();
            }
        }
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            string protectedToken = null;

            if (Request.Headers.TryGetValue("Authorization", out var authHeader) &&
                AuthenticationHeaderValue.TryParse(authHeader.ToString(), out var auth) &&
                auth.Scheme == "Bearer")
            {
                protectedToken = auth.Parameter;
            }

            if (string.IsNullOrEmpty(protectedToken) &&
                Request.Query.TryGetValue("token", out var tokenQuery))
            {
                protectedToken = tokenQuery;
            }

            if (string.IsNullOrEmpty(protectedToken))
            {
                return(AuthenticateResult.NoResult());
            }

            if (!TryDecodeToken(protectedToken, out GitHubTokenData token))
            {
                return(AuthenticateResult.Fail("Invalid token"));
            }

            if (await _revocation.IsTokenRevokedAsync(token.UserId, token.TokenId))
            {
                Logger.LogWarning("Revoked token used, user {user}, token {token}", token.UserId, token.TokenId);
                return(AuthenticateResult.Fail("Invalid token"));
            }

            (IEnumerable <Claim> userClaims, IEnumerable <Claim> groupClaims) = await Task.WhenAll(
                _resolver.GetUserInformationClaims(token.AccessToken, Context.RequestAborted),
                _resolver.GetMembershipClaims(token.AccessToken, Context.RequestAborted)
                );

            var identity  = new ClaimsIdentity(userClaims.Concat(groupClaims), Scheme.Name);
            var principal = new ClaimsPrincipal(new[] { identity });
            var ticket    = new AuthenticationTicket(principal, Scheme.Name);

            return(AuthenticateResult.Success(ticket));
        }
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            string protectedToken = null;

            if (Request.Headers.TryGetValue("Authorization", out StringValues authHeader) &&
                AuthenticationHeaderValue.TryParse(authHeader.ToString(), out AuthenticationHeaderValue auth) &&
                !string.IsNullOrEmpty(auth.Parameter) &&
                auth.Parameter.Length < 1000)
            {
                switch (auth.Scheme.ToLowerInvariant())
                {
                case "basic":
                    protectedToken = ParseBasicAuth(auth.Parameter);
                    break;

                case "bearer":
                    protectedToken = auth.Parameter;
                    break;
                }
            }

            if (string.IsNullOrEmpty(protectedToken) &&
                Request.Query.TryGetValue("token", out StringValues tokenQuery))
            {
                protectedToken = tokenQuery.ToString();
            }

            if (string.IsNullOrEmpty(protectedToken))
            {
                Logger.LogInformation("No token found in 'Authorization: Bearer <token>', 'Authorization: Basic <base64(ignored:<token>)>', or '?token=<token>'");
                return(AuthenticateResult.NoResult());
            }

            if (!TryDecodeToken(protectedToken, out GitHubTokenData token))
            {
                string reportToken = protectedToken;
                if (reportToken.Length > 10)
                {
                    reportToken = reportToken.Substring(0, 5) + "..." + reportToken.Substring(reportToken.Length - 5);
                }

                Logger.LogWarning("Token failed to decode correctly, token signature... {token}", reportToken);
                return(AuthenticateResult.Fail("Invalid token"));
            }

            if (await _revocation.IsTokenRevokedAsync(token.UserId, token.TokenId))
            {
                Logger.LogWarning("Revoked token used, user {user}, token {token}", token.UserId, token.TokenId);
                return(AuthenticateResult.Fail("Invalid token"));
            }

            (IEnumerable <Claim> userClaims, IEnumerable <Claim> groupClaims) = await Task.WhenAll(
                _resolver.GetUserInformationClaims(token.AccessToken, Context.RequestAborted),
                _resolver.GetMembershipClaims(token.AccessToken, Context.RequestAborted)
                );

            var identity  = new ClaimsIdentity(userClaims.Concat(groupClaims), Scheme.Name);
            var principal = new ClaimsPrincipal(new[] { identity });
            var ticket    = new AuthenticationTicket(principal, Scheme.Name);

            return(AuthenticateResult.Success(ticket));
        }