Skip to content

Commit

Permalink
Merge pull request #57 from KNPhilip/RefreshTokens
Browse files Browse the repository at this point in the history
Fix Refresh Token bug
  • Loading branch information
KNPhilip authored Sep 9, 2023
2 parents 39322e7 + 90db3ab commit 04c71f5
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 565 deletions.
58 changes: 56 additions & 2 deletions API/Controllers/AuthController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Security.Claims;
using System.Security.Cryptography;
using API.Dtos;
using API.Services.AuthService;
using Application.Core;
Expand All @@ -22,8 +23,19 @@ public AuthController(IAuthService authService, UserManager<User> userManager)
[HttpPost("login"), AllowAnonymous]
public async Task<ActionResult<ServiceResponse<UserDto>>> Login(LoginDto request)
{
User? user = await _userManager.Users
.FirstOrDefaultAsync(u => u.Email == request.Email);

if (user is null) return Unauthorized();

var response = await _authService.Login(request);
return response.Success ? Ok(response.Data) : Unauthorized(response.Error ?? "You are not authorized.");

if (response.Success)
{
await SetRefreshToken(user);
return Ok(response.Data);
}
else return Unauthorized(response.Error ?? "You are not authorized.");
}

[HttpPost("register"), AllowAnonymous]
Expand All @@ -32,7 +44,15 @@ public async Task<ActionResult<ServiceResponse<UserDto>>> Register(RegisterDto r
var response = await _authService.Register(request);

if (response.Success)
{
User? user = await _userManager.Users
.FirstOrDefaultAsync(u => u.UserName == response.Data!.Username);

if (user is null) return Unauthorized();

await SetRefreshToken(user);
return Ok(response.Data);
}
else
{
ModelState.AddModelError("user", "Email or username already taken.");
Expand All @@ -43,8 +63,18 @@ public async Task<ActionResult<ServiceResponse<UserDto>>> Register(RegisterDto r
[HttpGet, Authorize]
public async Task<ActionResult<UserDto>> GetCurrentUser()
{
User? user = await _userManager.Users
.FirstOrDefaultAsync(u => u.Email == User.FindFirstValue(ClaimTypes.Email));

if (user is null) return Unauthorized();

var response = await _authService.GetCurrentUser();
return response.Success ? Ok(response.Data) : NotFound(response.Error);
if (response.Success)
{
await SetRefreshToken(user!);
return Ok(response.Data);
}
else return NotFound(response.Error);
}

[HttpPost("fbLogin"), AllowAnonymous]
Expand All @@ -63,5 +93,29 @@ public async Task<ActionResult<UserDto>> RefreshToken()
var response = await _authService.RefreshJWT();
return response.Success ? Ok(response.Data) : Unauthorized(response.Error);
}

private async Task SetRefreshToken(User user)
{
RefreshToken refreshToken = GenerateRefreshToken();

user.RefreshTokens.Add(refreshToken);
await _userManager.UpdateAsync(user);

var cookieOptions = new CookieOptions
{
HttpOnly = true,
Expires = DateTime.UtcNow.AddDays(7)
};

Response.Cookies.Append("refreshToken", refreshToken.Token, cookieOptions);
}

private static RefreshToken GenerateRefreshToken()
{
var randomNumber = new byte[32];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return new RefreshToken{Token = Convert.ToBase64String(randomNumber)};
}
}
}
37 changes: 5 additions & 32 deletions API/Services/AuthService/AuthService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,16 @@ public string CreateJWT(User user)

public async Task<ServiceResponse<UserDto?>> Login(LoginDto request)
{
User? user = await _userManager.FindByEmailAsync(request.Email);
User? user = await _userManager.Users
.Include(u => u.Photos)
.FirstOrDefaultAsync(u => u.Email == request.Email);

if (user is null)
return new ServiceResponse<UserDto?> { Error = "Incorrect email or password." };

bool result = await _userManager.CheckPasswordAsync(user, request.Password);
if (result)
{
await SetRefreshToken(user);
UserDto returningUser = CreateUserObject(user);
return ServiceResponse<UserDto?>.SuccessResponse(returningUser);
}
Expand All @@ -87,7 +89,6 @@ public string CreateJWT(User user)

if (result.Succeeded)
{
await SetRefreshToken(user);
UserDto returningUser = CreateUserObject(user);
ServiceResponse<UserDto>.SuccessResponse(returningUser);
}
Expand All @@ -105,10 +106,7 @@ public string CreateJWT(User user)
if (userDto is null)
return new ServiceResponse<UserDto?> { Error = "User not found." };
else
{
await SetRefreshToken(user!);
return ServiceResponse<UserDto?>.SuccessResponse(userDto);
}
}

public async Task<bool> VerifyFacebookToken(string accessToken)
Expand Down Expand Up @@ -152,7 +150,6 @@ public async Task<bool> VerifyFacebookToken(string accessToken)
if (!result.Succeeded)
return new ServiceResponse<UserDto?> { Error = "Problem creating user account" };

await SetRefreshToken(user);
return ServiceResponse<UserDto?>.SuccessResponse(CreateUserObject(user));
}

Expand All @@ -172,7 +169,7 @@ public async Task<ServiceResponse<UserDto>> RefreshJWT()
return ServiceResponse<UserDto>.SuccessResponse(returning);
}

private UserDto CreateUserObject(User user)
public UserDto CreateUserObject(User user)
{
return new()
{
Expand All @@ -182,29 +179,5 @@ private UserDto CreateUserObject(User user)
Username = user.UserName
};
}

private static RefreshToken GenerateRefreshToken()
{
var randomNumber = new byte[32];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return new RefreshToken{Token = Convert.ToBase64String(randomNumber)};
}

private async Task SetRefreshToken(User user)
{
RefreshToken refreshToken = GenerateRefreshToken();

user.RefreshTokens.Add(refreshToken);
await _userManager.UpdateAsync(user);

var cookieOptions = new CookieOptions
{
HttpOnly = true,
Expires = DateTime.UtcNow.AddDays(7)
};

_httpContextAccessor.HttpContext!.Response.Cookies.Append("refreshToken", refreshToken.Token, cookieOptions);
}
}
}
1 change: 1 addition & 0 deletions API/Services/AuthService/IAuthService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public interface IAuthService
Task<bool> VerifyFacebookToken(string accessToken);
Task<ServiceResponse<UserDto?>> FacebookLogin(string accessToken);
Task<ServiceResponse<UserDto>> RefreshJWT();
UserDto CreateUserObject(User user);
}
}
Loading

0 comments on commit 04c71f5

Please sign in to comment.