fullstackhero/dotnet-starter-kit · warning · UnauthorizedException
Unauthorized
Error message
Unauthorized
What it means
VerifyEnrollTwoFactorCommandHandler throws UnauthorizedException when ICurrentUser.IsAuthenticated() is false. Verification completes 2FA enrollment and enables it, so it must only run for a properly authenticated principal.
Solutions
- Sign in again (the enroll step too, if the key rotated) and retry with a valid token
- Keep the enroll→verify flow within one authenticated session; refresh the token if it is near expiry
- Confirm the endpoint enforces authentication and middleware order is correct
- In tests, stub ICurrentUser.IsAuthenticated() to true
Example fix
// before if (Date.now() > tokenExpiry) verifyCode(code); // after if (Date.now() > tokenExpiry) await reauthenticate(); await verifyCode(code);
Defensive patterns
Strategy: try-catch
Validate before calling
function canVerifyEnroll() {
return Boolean(accessToken) && !isTokenExpired(accessToken);
}
if (!canVerifyEnroll()) await reauthenticate(); Try / catch
try {
await api.verifyEnrollTwoFactor({ code });
} catch (e) {
if (e.status === 401) { await reauthenticate(); return retry(); }
throw e;
} Prevention
- Verify promptly after enrolling so the token doesn't expire mid-flow
- Centralize auth header handling
- Refresh tokens before starting the verification step
When it happens
Trigger: Posting the authenticator code without a bearer token, with an expired JWT, or calling the handler directly in tests without an authenticated ICurrentUser.
Common situations: Token expired while the user was reading the code from their authenticator app; frontend lost the auth header between enroll and verify-enroll calls; middleware misordering; unauthenticated test invocation.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of fullstackhero/dotnet-starter-kit@3f2959e683 (2026-09-15).
Data as JSON: /api/errors/a4003eef2eb434f3.
Report an issue: GitHub.
Appendix: source
Thrown at src/Modules/Identity/Modules.Identity/Features/v1/TwoFactor/VerifyEnroll/VerifyEnrollTwoFactorCommandHandler.cs:29
: ICommandHandler<VerifyEnrollTwoFactorCommand, bool>
{
private readonly UserManager<FshUser> _userManager;
private readonly ICurrentUser _currentUser;
public VerifyEnrollTwoFactorCommandHandler(UserManager<FshUser> userManager, ICurrentUser currentUser)
{
_userManager = userManager;
_currentUser = currentUser;
}
public async ValueTask<bool> Handle(
VerifyEnrollTwoFactorCommand command, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(command);
if (!_currentUser.IsAuthenticated())
{
throw new UnauthorizedException();
}
var userId = _currentUser.GetUserId().ToString();
var user = await _userManager.FindByIdAsync(userId)
?? throw new NotFoundException($"User {userId} not found.");
var sanitized = command.Code.Replace(" ", string.Empty, StringComparison.Ordinal);
var valid = await _userManager.VerifyTwoFactorTokenAsync(
user,
_userManager.Options.Tokens.AuthenticatorTokenProvider,
sanitized);
if (!valid)
{
throw new CustomException(
"The authenticator code is invalid.",
errors: null,
System.Net.HttpStatusCode.BadRequest);View on GitHub (pinned to 3f2959e683)