using Campaign_Tracker.Server.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Campaign_Tracker.Server.Controllers; [ApiController] [AllowAnonymous] [Route("api/auth/token")] public sealed class AuthTokenController : ControllerBase { private readonly IHostEnvironment _environment; private readonly IKeycloakTokenClient _tokenClient; public AuthTokenController( IKeycloakTokenClient tokenClient, IHostEnvironment environment) { _environment = environment; _tokenClient = tokenClient; } [HttpPost("exchange")] public async Task> Exchange( [FromBody] AuthorizationCodeExchangeRequest request, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(request.Code) || string.IsNullOrWhiteSpace(request.RedirectUri)) { return BadRequest(); } try { return Ok(await _tokenClient.ExchangeAuthorizationCodeAsync( request.Code, request.RedirectUri, cancellationToken)); } catch (KeycloakTokenRequestException exception) { return Unauthorized(CreateTokenExchangeProblem(exception)); } } [HttpPost("refresh")] public async Task> Refresh( [FromBody] RefreshTokenRequest request, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(request.RefreshToken)) { return BadRequest(); } try { return Ok(await _tokenClient.RefreshAccessTokenAsync( request.RefreshToken, cancellationToken)); } catch (KeycloakTokenRequestException exception) { return Unauthorized(CreateTokenExchangeProblem(exception)); } } private object CreateTokenExchangeProblem(KeycloakTokenRequestException exception) { if (!_environment.IsDevelopment()) { return new { error = "Keycloak token request failed." }; } return new { error = "Keycloak token request failed.", statusCode = (int)exception.StatusCode, keycloakResponse = exception.ResponseBody, }; } } public sealed record AuthorizationCodeExchangeRequest(string Code, string RedirectUri); public sealed record RefreshTokenRequest(string RefreshToken);