public async Task<bool> AddRefreshTokenAsync(RefreshToken refreshToken) {
            var existingToken = await db.RefreshTokens.SingleOrDefaultAsync(r => r.Subject == refreshToken.Subject && r.Id == refreshToken.Id);
            if(existingToken != null) {
                var result = await RemoveRefreshTokenAsync(existingToken);
            }

            db.RefreshTokens.Add(refreshToken);

            return await db.SaveChangesAsync() > 0; // True if number rows inserted > 0
        }
 public async Task<bool> RemoveRefreshTokenAsync(RefreshToken refreshToken) {
     db.RefreshTokens.Remove(refreshToken);
     return await db.SaveChangesAsync() > 0;
 }
        public async Task<IActionResult> Token([FromBody] LoginViewModel model) {
            ClaimsIdentity identity = null;

            //Clean out expired tokens.
            await authRepo.CleanExiredRefreshTokens();


            if(String.IsNullOrWhiteSpace(model.GrantType)) {
                return new BadRequestObjectResult(new { message = "Request must contain a 'grantType' property." });
            }

            //Check if the user is logging in via password or refresh_token
            if(model.GrantType == "password") {
                //We need to authorize the user.
                identity = await authRepo.LoginUserAsync(model);
                if(identity == null) {
                    return new HttpUnauthorizedResult();
                }
            } else if(model.GrantType == "refreshToken") {
                var existingRefreshToken = await authRepo.FindRefreshTokenAsync(Utility.Util.GetHash(model.RefreshToken));
                if(existingRefreshToken == null) {
                    //No refresh token mean's it's invalid or revoked
                    return new HttpUnauthorizedResult();
                }

                if(existingRefreshToken.ClientId != model.ClientId) {
                    return new HttpUnauthorizedResult();
                }

                identity = await authRepo.GetClaimsIdentityByNameAsync(existingRefreshToken.Subject);
                await authRepo.RemoveRefreshTokenAsync(existingRefreshToken);

            } else {
                return new BadRequestObjectResult(new { message = "The 'grantType' must be either 'password' or 'refreshToken'." });
            }

            var client = await authRepo.FindClientAsync(model.ClientId);
            if(client == null) {
                return new HttpNotFoundObjectResult(new { message = "No such ClientId." });
            }
            
            if(string.IsNullOrWhiteSpace(client.AllowedOrigin) || client.AllowedOrigin == "*") {
                //If origin is blank or *, we need to check client secret to ensure we don't allow just any client to spoof its way in
                if(model.ClientSecret != client.Secret) {
                    //Sent secret doesn't match stored client secret...GTFO
                    return new HttpUnauthorizedResult();
                }
            }
            //TODO: Authorized Origins check, and integrate with CORS

            var newRefreshTokenId = Guid.NewGuid().ToString("n");

            var refreshToken = new RefreshToken {
                ClientId = client.Id,
                Id = Utility.Util.GetHash(newRefreshTokenId),
                IssuedUtc = DateTime.UtcNow,
                ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(5)),
                Subject = identity.Name
            };

            await authRepo.AddRefreshTokenAsync(refreshToken);

            string token = GenerateAccessToken(identity);
            return new JsonResult(new TokenDTO {
                AccessToken = token,
                RefreshToken = newRefreshTokenId,
                ClientId = refreshToken.ClientId,
                ExpiresIn = Convert.ToInt32(refreshToken.ExpiresUtc.Subtract(DateTime.UtcNow).TotalMinutes),
                Expires = refreshToken.ExpiresUtc.ToString(),
                Issued = refreshToken.IssuedUtc.ToString(),
                TokenType = "bearer",
                UserName = refreshToken.Subject
            });
        }