microsoft-identity-web icon indicating copy to clipboard operation
microsoft-identity-web copied to clipboard

downstreamApi does not correctly handle text response

Open karlschriek opened this issue 10 months ago • 2 comments

Microsoft.Identity.Web Library

Microsoft.Identity.Web.DownstreamApi

Microsoft.Identity.Web version

2.17,1

Web app

Not Applicable

Web API

Protected web APIs call downstream web APIs

Token cache serialization

Not Applicable

Description

downstreamApi will attempt to deserialize JSON, even if expected return type is a string.

The only way I have been able to get around this, is by setting up a synchronous custom deserializer as follows:

    options.Deserializer = (content) =>
    {
        var task = Task.Run(() => content.ReadAsStringAsync()); 
        task.Wait();
        return task.Result;
    };

Reproduction steps

Create a downstream API service that return raw text (i.e., not JSON encoded text). Then call that API using:

var result = await _downstreamApi.PostForAppAsync<object, string>( "MyApi", null);

Error message

'r' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
    System.Text.Json.JsonException: 'r' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0.
 ---> System.Text.Json.JsonReaderException: 'r' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0.
   at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
   at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)
   at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first)
   at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
   at System.Text.Json.Utf8JsonReader.Read()
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)

Id Web logs

No response

Relevant code snippets

result = await _downstreamApi.PostForAppAsync<object, string>("MyApi", null);

Regression

No response

Expected behavior

I would expect the downstreamApi to not attempt to parse content if the expected return value is of type string

karlschriek avatar Mar 25 '24 08:03 karlschriek

Hi @karlschriek - there are methods that return an HttpResponseMessage instead, that do not parse the message content. Can't those be used instead?

https://github.com/AzureAD/microsoft-identity-web/blob/master/src/Microsoft.Identity.Web.DownstreamApi/DownstreamApi.cs#L77

bgavrilMS avatar Mar 26 '24 15:03 bgavrilMS

Using the overrides returning an HttpResponseMessage is a work around.

However, we could do better in the other overrides: we should respect the Content-Type header provided by the web API when it's provided. If it contains json we deserialize. If it's text

additionally we should expose a new property "acceptHeader" in the DownstreamApiOptions to specify what the client can process. @jennyf19: it's a good first issue. .NET 9?

jmprieur avatar Mar 28 '24 16:03 jmprieur