diff --git a/ApiDto/Common/OAuthAction.cs b/ApiDto/Common/OAuthAction.cs
new file mode 100644
index 0000000..1cc0908
--- /dev/null
+++ b/ApiDto/Common/OAuthAction.cs
@@ -0,0 +1,17 @@
+namespace Mirea.Api.Dto.Common;
+
+///
+/// Defines the actions that can be performed with an OAuth token.
+///
+public enum OAuthAction
+{
+ ///
+ /// The action to log in the user using the provided OAuth token.
+ ///
+ Login,
+
+ ///
+ /// The action to bind an OAuth provider to the user's account.
+ ///
+ Bind
+}
\ No newline at end of file
diff --git a/Endpoint/Controllers/V1/AuthController.cs b/Endpoint/Controllers/V1/AuthController.cs
index 640c80c..544533d 100644
--- a/Endpoint/Controllers/V1/AuthController.cs
+++ b/Endpoint/Controllers/V1/AuthController.cs
@@ -11,12 +11,13 @@ using Mirea.Api.Endpoint.Common.Exceptions;
using Mirea.Api.Endpoint.Common.MapperDto;
using Mirea.Api.Endpoint.Common.Services;
using Mirea.Api.Endpoint.Configuration.Model;
-using Mirea.Api.Security.Common.Model;
using Mirea.Api.Security.Services;
using System;
using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
+using System.Security.Claims;
using System.Threading.Tasks;
using CookieOptions = Mirea.Api.Security.Common.Model.CookieOptions;
using OAuthProvider = Mirea.Api.Security.Common.Domain.OAuthProvider;
@@ -164,6 +165,67 @@ public class AuthController(IOptionsSnapshot user, IOptionsSnapshot
+ /// Processes the OAuth token
+ ///
+ /// The OAuth token used for authentication or binding.
+ /// The action to be performed: Login or Bind.
+ /// If return Ok. If return
+ [HttpGet("HandleToken")]
+ [MaintenanceModeIgnore]
+ [BadRequestResponse]
+ public async Task HandleToken([FromQuery][MinLength(2)] string token, [FromQuery] OAuthAction action)
+ {
+ var (oAuthUser, error, isSuccess, provider) = await oAuthService.GetOAuthUser(GetCookieParams(), HttpContext, token);
+
+ if (!isSuccess || oAuthUser == null || provider == null)
+ throw new ControllerArgumentException(error ?? "Token processing error.");
+
+ switch (action)
+ {
+ case OAuthAction.Login:
+ return Ok(await auth.LoginOAuthAsync(GetCookieParams(), HttpContext, user.Value.ConvertToSecurity(), oAuthUser, provider.Value));
+
+ case OAuthAction.Bind:
+ var userId = HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
+ var admin = user.Value;
+
+ if (string.IsNullOrEmpty(userId) || !int.TryParse(userId, out var result) || result != 1)
+ return Unauthorized(new ProblemDetails
+ {
+ Type = "https://tools.ietf.org/html/rfc9110#section-15.5.2",
+ Title = "Unauthorized",
+ Status = StatusCodes.Status401Unauthorized,
+ Detail = "The user is not logged in to link accounts.",
+ Extensions = new Dictionary()
+ {
+ { "traceId", HttpContext.TraceIdentifier }
+ }
+ });
+
+ if (admin.OAuthProviders != null && admin.OAuthProviders.ContainsKey(provider.Value))
+ return Conflict(new ProblemDetails
+ {
+ Type = "https://tools.ietf.org/html/rfc9110#section-15.5.10",
+ Title = "Conflict",
+ Status = StatusCodes.Status409Conflict,
+ Detail = "This OAuth provider is already associated with the account.",
+ Extensions = new Dictionary()
+ {
+ { "traceId", HttpContext.TraceIdentifier }
+ }
+ });
+
+ admin.OAuthProviders ??= [];
+ admin.OAuthProviders.Add(provider.Value, oAuthUser);
+ admin.SaveSetting();
+
+ return Ok();
+ default:
+ throw new ControllerArgumentException("The action cannot be processed.");
+ }
+ }
+
///
/// Logs in a user using their username or email and password.
///