Begin work on user confirmation workflow

This commit is contained in:
Aaron Po
2026-02-21 20:44:49 -05:00
parent 17eb04e20c
commit 0ab2eaaec9
15 changed files with 233 additions and 41 deletions

View File

@@ -0,0 +1,21 @@
using System.Runtime.InteropServices.JavaScript;
using Infrastructure.Repository.Auth;
namespace Service.Auth;
public record ConfirmationServiceReturn(DateTime confirmedAt, Guid userId);
public interface IConfirmationService
{
Task<ConfirmationServiceReturn> ConfirmUserAsync(string confirmationToken);
}
public class ConfirmationService(IAuthRepository authRepository) : IConfirmationService
{
public async Task<ConfirmationServiceReturn> ConfirmUserAsync(string confirmationToken)
{
return new ConfirmationServiceReturn(DateTime.Now, Guid.NewGuid());
}
}

View File

@@ -2,6 +2,11 @@ using Domain.Entities;
namespace Service.Auth;
public record LoginServiceReturn(
UserAccount UserAccount,
string RefreshToken,
string AccessToken
);
public interface ILoginService
{
Task<LoginServiceReturn> LoginAsync(string username, string password);

View File

@@ -36,4 +36,4 @@ public interface IRegisterService
UserAccount userAccount,
string password
);
}
}

View File

@@ -7,28 +7,73 @@ public interface ITokenService
{
public string GenerateAccessToken(UserAccount user);
public string GenerateRefreshToken(UserAccount user);
public string GenerateConfirmationToken(UserAccount user);
}
public static class TokenServiceExpirationHours
{
public const double AccessTokenHours = 1;
public const double RefreshTokenHours = 504; // 21 days
public const double ConfirmationTokenHours = 0.5; // 30 minutes
}
public class TokenService(ITokenInfrastructure tokenInfrastructure)
: ITokenService
{
private readonly string _accessTokenSecret =
Environment.GetEnvironmentVariable("ACCESS_TOKEN_SECRET")
?? throw new InvalidOperationException(
"ACCESS_TOKEN_SECRET environment variable is not set"
);
private readonly string _refreshTokenSecret =
Environment.GetEnvironmentVariable("REFRESH_TOKEN_SECRET")
?? throw new InvalidOperationException(
"REFRESH_TOKEN_SECRET environment variable is not set"
);
private readonly string _confirmationTokenSecret =
Environment.GetEnvironmentVariable("CONFIRMATION_TOKEN_SECRET")
?? throw new InvalidOperationException(
"CONFIRMATION_TOKEN_SECRET environment variable is not set"
);
public string GenerateAccessToken(UserAccount userAccount)
{
var jwtExpiresAt = DateTime.UtcNow.AddHours(1);
var jwtExpiresAt = DateTime.UtcNow.AddHours(
TokenServiceExpirationHours.AccessTokenHours
);
return tokenInfrastructure.GenerateJwt(
userAccount.UserAccountId,
userAccount.Username,
jwtExpiresAt
jwtExpiresAt,
_accessTokenSecret
);
}
public string GenerateRefreshToken(UserAccount userAccount)
{
var jwtExpiresAt = DateTime.UtcNow.AddDays(21);
var jwtExpiresAt = DateTime.UtcNow.AddHours(
TokenServiceExpirationHours.RefreshTokenHours
);
return tokenInfrastructure.GenerateJwt(
userAccount.UserAccountId,
userAccount.Username,
jwtExpiresAt
jwtExpiresAt,
_refreshTokenSecret
);
}
public string GenerateConfirmationToken(UserAccount userAccount)
{
var jwtExpiresAt = DateTime.UtcNow.AddHours(
TokenServiceExpirationHours.ConfirmationTokenHours
);
return tokenInfrastructure.GenerateJwt(
userAccount.UserAccountId,
userAccount.Username,
jwtExpiresAt,
_confirmationTokenSecret
);
}
}

View File

@@ -5,11 +5,6 @@ using Infrastructure.Repository.Auth;
namespace Service.Auth;
public record LoginServiceReturn(
UserAccount UserAccount,
string RefreshToken,
string AccessToken
);
public class LoginService(
IAuthRepository authRepo,

View File

@@ -53,6 +53,7 @@ public class RegisterService(
var accessToken = tokenService.GenerateAccessToken(createdUser);
var refreshToken = tokenService.GenerateRefreshToken(createdUser);
var confirmationToken = tokenService.GenerateConfirmationToken(createdUser);
if (
string.IsNullOrEmpty(accessToken)
@@ -67,14 +68,15 @@ public class RegisterService(
{
// send confirmation email
await emailService.SendRegistrationEmailAsync(
createdUser,
"some-confirmation-token"
createdUser, confirmationToken
);
emailSent = true;
}
catch
catch (Exception ex)
{
await Console.Error.WriteLineAsync(ex.Message);
Console.WriteLine("Could not send email.");
// ignored
}
@@ -85,4 +87,4 @@ public class RegisterService(
emailSent
);
}
}
}