/// <inheritdoc /> public async Task <Outcome <TokenExchangeResponse> > ExchangeAsync( TokenExchangeArgs args, CancellationToken cancellationToken) { using var client = new HttpClient(); if (!(args.Credentials is BasicAuthCredentials basicAuthCredentials)) { return(Outcome <TokenExchangeResponse> .Fail( new InvalidOperationException($"Tetra Pak token exchange expects credentials to be of type {typeof(BasicAuthCredentials)}"))); } client.DefaultRequestHeaders.Authorization = basicAuthCredentials.ToAuthenticationHeaderValue(); try { var discovery = await _authConfig.GetDiscoveryDocumentAsync(); var dictionary = args.ToDictionary(); var content = new FormUrlEncodedContent(dictionary); var response = await client.PostAsync( discovery.TokenEndpoint, content, cancellationToken); if (!response.IsSuccessStatusCode) { #if NET5_0_OR_GREATER var errorContent = await response.Content.ReadAsStringAsync(cancellationToken); #else var errorContent = await response.Content.ReadAsStringAsync(); #endif var statusCode = ((int)response.StatusCode).ToString(); var ex = new Exception($"Call failed with status: {statusCode} {response.ReasonPhrase}. {errorContent}"); Logger?.LogError(ex, "Token exchange failure"); return(Outcome <TokenExchangeResponse> .Fail(ex)); } #if NET5_0_OR_GREATER var stream = await response.Content.ReadAsStreamAsync(cancellationToken); #else var stream = await response.Content.ReadAsStreamAsync(); #endif var responseBody = await JsonSerializer.DeserializeAsync <TokenExchangeResponse>(stream, cancellationToken : cancellationToken); return(Outcome <TokenExchangeResponse> .Success(responseBody)); } catch (Exception ex) { return(Outcome <TokenExchangeResponse> .Fail(ex)); } }
/// <inheritdoc /> public async Task <Outcome <TokenExchangeResponse> > ExchangeAccessTokenAsync(Credentials credentials, string accessToken, CancellationToken cancellationToken) { var args = new TokenExchangeArgs(credentials, accessToken, "urn:ietf:params:oauth:token-type:id_token"); return(await ExchangeAsync(args, cancellationToken)); }