#pragma warning disable CA1506 // TODO: Decomplexify
        public async Task <IActionResult> CreateToken(CancellationToken cancellationToken)
        {
            if (ApiHeaders == null)
            {
                Response.Headers.Add(HeaderNames.WWWAuthenticate, new StringValues("basic realm=\"Create TGS4 bearer token\""));
                return(HeadersIssue(false));
            }

            if (ApiHeaders.IsTokenAuthentication)
            {
                return(BadRequest(new ErrorMessage(ErrorCode.TokenWithToken)));
            }

            var oAuthLogin = ApiHeaders.OAuthProvider.HasValue;

            ISystemIdentity systemIdentity = null;

            if (!oAuthLogin)
            {
                try
                {
                    // trust the system over the database because a user's name can change while still having the same SID
                    systemIdentity = await systemIdentityFactory.CreateSystemIdentity(ApiHeaders.Username, ApiHeaders.Password, cancellationToken).ConfigureAwait(false);
                }
                catch (NotImplementedException ex)
                {
                    Logger.LogTrace(ex, "System identities not implemented!");
                }
            }

            using (systemIdentity)
            {
                // Get the user from the database
                IQueryable <Models.User> query = DatabaseContext.Users.AsQueryable();
                if (oAuthLogin)
                {
                    string externalUserId;
                    try
                    {
                        var validator = oAuthProviders
                                        .GetValidator(ApiHeaders.OAuthProvider.Value);

                        if (validator == null)
                        {
                            return(BadRequest(new ErrorMessage(ErrorCode.OAuthProviderDisabled)));
                        }

                        externalUserId = await validator
                                         .ValidateResponseCode(ApiHeaders.Token, cancellationToken)
                                         .ConfigureAwait(false);
                    }
                    catch (RateLimitExceededException ex)
                    {
                        return(RateLimit(ex));
                    }

                    if (externalUserId == null)
                    {
                        return(Unauthorized());
                    }

                    query = query.Where(
                        x => x.OAuthConnections.Any(
                            y => y.Provider == ApiHeaders.OAuthProvider.Value &&
                            y.ExternalUserId == externalUserId));
                }
                else
                {
                    string canonicalName = Models.User.CanonicalizeName(ApiHeaders.Username);
                    if (systemIdentity == null)
                    {
                        query = query.Where(x => x.CanonicalName == canonicalName);
                    }
                    else
                    {
                        query = query.Where(x => x.CanonicalName == canonicalName || x.SystemIdentifier == systemIdentity.Uid);
                    }
                }

                var users = await query.Select(x => new Models.User
                {
                    Id           = x.Id,
                    PasswordHash = x.PasswordHash,
                    Enabled      = x.Enabled,
                    Name         = x.Name
                }).ToListAsync(cancellationToken).ConfigureAwait(false);

                // Pick the DB user first
                var user = users
                           .OrderByDescending(dbUser => dbUser.PasswordHash != null)
                           .FirstOrDefault();

                // No user? You're not allowed
                if (user == null)
                {
                    return(Unauthorized());
                }

                // A system user may have had their name AND password changed to one in our DB...
                // Or a DB user was created that had the same user/pass as a system user
                // Dumb admins...
                // FALLBACK TO THE DB USER HERE, DO NOT REVEAL A SYSTEM LOGIN!!!
                // This of course, allows system users to discover TGS users in this (HIGHLY IMPROBABLE) case but that is not our fault
                var  originalHash        = user.PasswordHash;
                var  isDbUser            = originalHash != null;
                bool usingSystemIdentity = systemIdentity != null && !isDbUser;
                if (!oAuthLogin)
                {
                    if (!usingSystemIdentity)
                    {
                        // DB User password check and update
                        if (!cryptographySuite.CheckUserPassword(user, ApiHeaders.Password))
                        {
                            return(Unauthorized());
                        }
                        if (user.PasswordHash != originalHash)
                        {
                            Logger.LogDebug("User ID {0}'s password hash needs a refresh, updating database.", user.Id);
                            var updatedUser = new Models.User
                            {
                                Id = user.Id
                            };
                            DatabaseContext.Users.Attach(updatedUser);
                            updatedUser.PasswordHash = user.PasswordHash;
                            await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
                        }
                    }
                    else if (systemIdentity.Username != user.Name)
                    {
                        // System identity username change update
                        Logger.LogDebug("User ID {0}'s system identity needs a refresh, updating database.", user.Id);
                        DatabaseContext.Users.Attach(user);
                        user.Name          = systemIdentity.Username;
                        user.CanonicalName = Models.User.CanonicalizeName(user.Name);
                        await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
                    }
                }

                // Now that the bookeeping is done, tell them to f**k off if necessary
                if (!user.Enabled.Value)
                {
                    Logger.LogTrace("Not logging in disabled user {0}.", user.Id);
                    return(Forbid());
                }

                var token = await tokenFactory.CreateToken(user, oAuthLogin, cancellationToken).ConfigureAwait(false);

                if (usingSystemIdentity)
                {
                    // expire the identity slightly after the auth token in case of lag
                    var identExpiry = token.ExpiresAt;
                    identExpiry += tokenFactory.ValidationParameters.ClockSkew;
                    identExpiry += TimeSpan.FromSeconds(15);
                    identityCache.CacheSystemIdentity(user, systemIdentity, identExpiry);
                }

                Logger.LogDebug("Successfully logged in user {0}!", user.Id);

                return(Json(token));
            }
        }
        public async Task <IActionResult> CreateToken(CancellationToken cancellationToken)
        {
            if (ApiHeaders.IsTokenAuthentication)
            {
                return(BadRequest(new Api.Models.ErrorMessage {
                    Message = "Cannot create a token using another token!"
                }));
            }

            ISystemIdentity identity;

            try
            {
                //trust the system over the database because a user's name can change while still having the same SID
                identity = await systemIdentityFactory.CreateSystemIdentity(ApiHeaders.Username, ApiHeaders.Password, cancellationToken).ConfigureAwait(false);
            }
            catch (NotImplementedException)
            {
                identity = null;
            }
            using (identity)
            {
                IQueryable <User> query;
                if (identity == null)
                {
                    query = DatabaseContext.Users.Where(x => x.CanonicalName == ApiHeaders.Username.ToUpperInvariant());
                }
                else
                {
                    query = DatabaseContext.Users.Where(x => x.SystemIdentifier == identity.Uid);
                }
                var user = await query.Select(x => new User
                {
                    Id           = x.Id,
                    PasswordHash = x.PasswordHash,
                    Enabled      = x.Enabled,
                    Name         = x.Name
                }).FirstOrDefaultAsync(cancellationToken).ConfigureAwait(false);

                if (user == null)
                {
                    return(Unauthorized());
                }

                if (identity == null)
                {
                    var originalHash = user.PasswordHash;
                    if (!cryptographySuite.CheckUserPassword(user, ApiHeaders.Password))
                    {
                        return(Unauthorized());
                    }
                    if (user.PasswordHash != originalHash)
                    {
                        var updatedUser = new User
                        {
                            Id = user.Id
                        };
                        DatabaseContext.Users.Attach(updatedUser);
                        updatedUser.PasswordHash = user.PasswordHash;
                        await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
                    }
                }
                //check if the name changed and updoot accordingly
                else if (identity.Username != user.Name)
                {
                    DatabaseContext.Users.Attach(user);
                    user.Name          = identity.Username;
                    user.CanonicalName = user.Name.ToUpperInvariant();
                    await DatabaseContext.Save(cancellationToken).ConfigureAwait(false);
                }

                if (!user.Enabled.Value)
                {
                    return(Forbid());
                }

                var token = tokenFactory.CreateToken(user);
                if (identity != null)
                {
                    identityCache.CacheSystemIdentity(user, identity, token.ExpiresAt.Value.AddMinutes(1));                       //expire the identity slightly after the auth token in case of lag
                }
                Logger.LogDebug("Successfully logged in user {0}!", user.Id);

                return(Json(token));
            }
        }