I am working on an ASP.NET Core Web API project where I want to allow users to log in using user/password, and also Google, Facebook, and Apple. When using external services to log in, a user should be created which will be used to track their activity in the application: assign points, let them redeem for gifts and other features.
Currently, the solution I have involves:
- Validating the tokens received from external services
- Manually generating JWT Bearer tokens
But this approach has a lot of disadvantages and doesn’t use much of what the Identity Framework offers. Example of the controller getting the user from the authorization code in Google:
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] GoogleLoginRequest request)
{
try
{
var user = await _googleAuthService.GetUserDetails(request.IdToken);
if (user == null)
return BadRequest("Invalid user information received from Google services");
user = await _createUser.ExecuteAsync(user);
if (user == null)
return Problem("Unable to create user");
var tokenResponse = await _userTokenService.GenerateAccessToken(user);
return Ok(tokenResponse);
}
catch (Exception ex)
{
return Problem("Internal server error");
}
}
As you can see, the generation of the bearer is manual using the UserTokenService
:
public async Task<AccessTokenResponse> GenerateAccessToken(IdentityUser user)
{
var userRoles = await _context.UserRoles
.Where(ur => ur.UserId == user.Id)
.Join(_context.Roles, ur => ur.RoleId, r => r.Id, (ur, r) => r.Name)
.ToListAsync();
var roleClaims = userRoles.Select(role => new Claim(ClaimTypes.Role, role)).ToList();
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Name, user.NormalizedUserName!),
new Claim(ClaimTypes.Email, user.Email!)
}
.Union(roleClaims);
var key = new SymmetricSecurityKey(Convert.FromBase64String(_configuration["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var expiration = DateTime.UtcNow.AddHours(int.Parse(_configuration["Jwt:ExpirationInHours"]!));
var token = new JwtSecurityToken(
issuer: _configuration["Jwt:Issuer"],
audience: _configuration["Jwt:Audience"],
claims: claims,
expires: expiration,
signingCredentials: creds);
var jwt = new JwtSecurityTokenHandler().WriteToken(token);
var refreshToken = await GenerateRefreshTokenAsync(user);
return new AccessTokenResponse
{
AccessToken = jwt,
ExpiresIn = (int)(expiration - DateTime.UtcNow).TotalSeconds,
RefreshToken = refreshToken.Token
};
}
I would like to know how to properly do this flow using SignInManager
, UserManager
etc., so that the user can receive their new bearer token managed by Identity Framework. Any guidance, tutorials or docs are really appreciated.