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 }); }