using System.Net; using System.Security.Authentication; using FitConnect.Services.Interfaces; using FitConnect.Services.Models; using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace FitConnect.Services; internal class OAuthService : RestCallService, IOAuthService { private readonly string _clientId; private readonly string _clientSecret; private readonly ILogger? _logger; private readonly string _tokenUrl; private OAuthAccessToken? _token; public OAuthService(string tokenUrl, string version, string clientId, string clientSecret, ILogger? logger) : base($"{tokenUrl}/{version}", logger) { _tokenUrl = tokenUrl; _clientId = clientId; _clientSecret = clientSecret; _logger = logger; } public OAuthAccessToken? Token { get => _token; private set { _token = value; AccessToken = value?.AccessToken; } } /// <summary> /// Requesting an OAuth token from the FitConnect API. /// <para> /// You can get the Client ID and Client Secret from the FitConnect Self Service portal /// under <br /> /// https://portal.auth-testing.fit-connect.fitko.dev /// </para> /// </summary> /// <param name="scope">Scope if needed</param> /// <returns>The received token or null</returns> public async Task AuthenticateAsync( string? scope = null) { var client = CreateClient(); var requestContent = new Dictionary<string, string> { { "grant_type", "client_credentials" }, { "client_id", _clientId }, { "client_secret", _clientSecret } }; if (scope != null) requestContent["scope"] = scope; var content = new FormUrlEncodedContent(requestContent); var request = new HttpRequestMessage(HttpMethod.Post, _tokenUrl) { Content = content, Method = HttpMethod.Post }; var response = await client.SendAsync(request); if (response.IsSuccessStatusCode) { var result = JsonConvert.DeserializeObject<OAuthAccessToken>( await response.Content.ReadAsStringAsync()); if (result == null) throw new AuthenticationException("Failed to authenticate"); Token = result; } if (response.StatusCode == HttpStatusCode.Unauthorized) throw new InvalidCredentialException(await response.Content.ReadAsStringAsync()); } public bool IsAuthenticated => Token != null; public void EnsureAuthenticated() { if (!IsAuthenticated) AuthenticateAsync().Wait(); } }