diff --git a/ApiDto/Requests/TwoFactorAuthRequest.cs b/ApiDto/Requests/TwoFactorAuthRequest.cs
new file mode 100644
index 0000000..29811f1
--- /dev/null
+++ b/ApiDto/Requests/TwoFactorAuthRequest.cs
@@ -0,0 +1,19 @@
+using Mirea.Api.Dto.Common;
+
+namespace Mirea.Api.Dto.Requests;
+
+///
+/// Represents a request for verifying two-factor authentication.
+///
+public class TwoFactorAuthRequest
+{
+ ///
+ /// Gets or sets the two-factor authentication code provided by the user.
+ ///
+ public required string Code { get; set; }
+
+ ///
+ /// Gets or sets the type of the two-factor authentication method used (e.g., TOTP, Email).
+ ///
+ public TwoFactorAuthentication Method { get; set; }
+}
\ No newline at end of file
diff --git a/Endpoint/Controllers/V1/AuthController.cs b/Endpoint/Controllers/V1/AuthController.cs
index 2639165..b1abe5a 100644
--- a/Endpoint/Controllers/V1/AuthController.cs
+++ b/Endpoint/Controllers/V1/AuthController.cs
@@ -54,11 +54,11 @@ public class AuthController(IOptionsSnapshot user, AuthService auth, Pass
return Ok(tokenResult.ConvertToDto());
}
- [HttpGet("Login")]
+ [HttpPost("2FA")]
[BadRequestResponse]
- public async Task> Login([FromQuery] string code)
+ public async Task> TwoFactorAuth([FromBody] TwoFactorAuthRequest request)
{
- var tokenResult = await auth.LoginAsync(GetCookieParams(), HttpContext, code);
+ var tokenResult = await auth.LoginAsync(GetCookieParams(), HttpContext, request.Method.ConvertFromDto(), request.Code);
return Ok(tokenResult ? TwoFactorAuthentication.None : TwoFactorAuthentication.TotpRequired);
}
diff --git a/Security/Services/AuthService.cs b/Security/Services/AuthService.cs
index 6ace1c8..8b542d6 100644
--- a/Security/Services/AuthService.cs
+++ b/Security/Services/AuthService.cs
@@ -93,12 +93,14 @@ public class AuthService(ICacheService cache, IAccessToken accessTokenService, I
authToken.Fingerprint);
}
- public async Task LoginAsync(CookieOptionsParameters cookieOptions, HttpContext context, string code, CancellationToken cancellation = default)
+ public async Task LoginAsync(CookieOptionsParameters cookieOptions, HttpContext context, TwoFactorAuthenticator authenticator, string code, CancellationToken cancellation = default)
{
var requestContext = new RequestContextInfo(context, cookieOptions);
- var firstTokenAuth = await cache.GetAsync(GetFirstAuthCacheKey(requestContext.Fingerprint), cancellationToken: cancellation)
- ?? throw new SecurityException("The session time has expired");
+ var firstTokenAuth = await cache.GetAsync(GetFirstAuthCacheKey(requestContext.Fingerprint), cancellationToken: cancellation);
+
+ if (firstTokenAuth == null || authenticator != firstTokenAuth.TwoFactorAuthenticator)
+ throw new SecurityException("The session time has expired");
switch (firstTokenAuth.TwoFactorAuthenticator)
{