refactor(auth): cleanup auth module and streamline the registration flow

This commit is contained in:
2025-06-18 16:50:11 -04:00
parent 25b94d3e02
commit cdcfe8d7e2
24 changed files with 2140 additions and 1387 deletions

View File

@@ -3,11 +3,12 @@ using System.Text.Json.Serialization;
using Hutopy.Infrastructure.Security;
using Hutopy.Modules.Identity.Configuration;
using Hutopy.Modules.Identity.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
namespace Hutopy.Modules.Identity.Handlers;
class GoogleToken
internal class GoogleToken
{
[JsonPropertyName("access_token")] public required string AccessToken { get; init; }
[JsonPropertyName("token_type")] public required string TokenType { get; init; }
@@ -55,11 +56,11 @@ public class LoginWithGoogleHandler(
LoginWithGoogleRequest request,
CancellationToken ct)
{
var googleToken = JsonSerializer.Deserialize<GoogleToken>(request.Token)!;
GoogleToken googleToken = JsonSerializer.Deserialize<GoogleToken>(request.Token)!;
// Verify the token with Google
using var httpClient = httpClientFactory.CreateClient();
using var response = await httpClient.GetAsync(
using HttpClient httpClient = httpClientFactory.CreateClient();
using HttpResponseMessage response = await httpClient.GetAsync(
$"https://www.googleapis.com/oauth2/v1/userinfo?access_token={googleToken.AccessToken}",
ct);
if (!response.IsSuccessStatusCode)
@@ -72,8 +73,8 @@ public class LoginWithGoogleHandler(
}
// Extract the user info (email, name, etc.).
var content = await response.Content.ReadAsStringAsync(ct);
var userInfo = JsonSerializer.Deserialize<GoogleUserInfo>(content);
string content = await response.Content.ReadAsStringAsync(ct);
GoogleUserInfo? userInfo = JsonSerializer.Deserialize<GoogleUserInfo>(content);
if (userInfo is null
|| !userInfo.VerifiedEmail
|| string.IsNullOrEmpty(userInfo.Email))
@@ -85,17 +86,18 @@ public class LoginWithGoogleHandler(
return;
}
// Check if user exists or create a new one
var user = await userManager.FindByEmailAsync(userInfo.Email);
// Check if the user exists or create a new one
User? user = await userManager.FindByEmailAsync(userInfo.Email);
if (user is null)
{
var generatedPassword = PasswordGenerator.Next();
var refreshToken = RefreshTokenGenerator.Next();
var generatedUser = new User
string generatedPassword = PasswordGenerator.Next();
string refreshToken = RefreshTokenGenerator.Next();
User generatedUser = new()
{
UserName = userInfo.Email,
Email = userInfo.Email,
EmailConfirmed = true,
Firstname = userInfo.GivenName,
Lastname = userInfo.FamilyName,
Alias = userInfo.Name,
@@ -105,7 +107,7 @@ public class LoginWithGoogleHandler(
RefreshTokenExpiryTime = DateTime.UtcNow.Add(jwtOptions.Value.RefreshTokenLifetime)
};
var result = await userManager.CreateAsync(
IdentityResult result = await userManager.CreateAsync(
generatedUser,
generatedPassword);
@@ -121,25 +123,25 @@ public class LoginWithGoogleHandler(
user = generatedUser;
}
// Generate new refresh token
// Generate the new refresh token
user.RefreshToken = RefreshTokenGenerator.Next();
user.RefreshTokenExpiryTime = DateTime.UtcNow.Add(jwtOptions.Value.RefreshTokenLifetime);
await userManager.UpdateAsync(user);
var accessToken = JwtTokenHelper.GenerateJwtToken(
expiresIn: jwtOptions.Value.Lifetime,
issuer: jwtOptions.Value.Issuer,
audience: jwtOptions.Value.Audience,
key: jwtOptions.Value.Key,
userId: user.Id.ToString(),
email: user.Email ?? string.Empty,
alias: user.Alias,
firstname: user.Firstname ?? string.Empty,
lastname: user.Lastname ?? string.Empty,
portraitUrl: user.PortraitUrl);
string accessToken = JwtTokenHelper.GenerateJwtToken(
jwtOptions.Value.Lifetime,
jwtOptions.Value.Issuer,
jwtOptions.Value.Audience,
jwtOptions.Value.Key,
user.Id.ToString(),
user.Email ?? string.Empty,
user.Alias,
user.Firstname ?? string.Empty,
user.Lastname ?? string.Empty,
user.PortraitUrl);
await SendOkAsync(
new LoginWithGoogleResponse(accessToken, user.RefreshToken),
cancellation: ct);
ct);
}
}