auth0.net icon indicating copy to clipboard operation
auth0.net copied to clipboard

Newtonsoft can't deserialize user response

Open BrandonBoone opened this issue 1 year ago • 0 comments

Checklist

  • [X] I have looked into the Readme and have not found a suitable solution or answer.
  • [X] I have looked into the API documentation and have not found a suitable solution or answer.
  • [X] I have searched the issues and have not found a suitable solution or answer.
  • [X] I have searched the Auth0 Community forums and have not found a suitable solution or answer.
  • [X] I agree to the terms within the Auth0 Code of Conduct.

Description

The Auth0 SDK cannot desterilize the JSON response from the following API call:

API Call: https://dev-nextech.us.auth0.com/api/v2/users?q=identities.connection%3A%22Username-Password-Authentication%22%20AND%20email%3A%22b.boone%40mailinator.com%22&search_engine=v3

Response:

[
  {
    "email": "[email protected]",
    "email_verified": true,
    "blocked": false,
    "created_at": "2023-06-20T16:24:03.232Z",
    "updated_at": "2024-05-31T18:56:09.778Z",
    "identities": [
      {
        "connection": "Username-Password-Authentication",
        "provider": "auth0",
        "user_id": "6491d2d0088e46b72de20b35",
        "isSocial": false
      }
    ],
    "user_id": "auth0|6491d2d0088e46b72de20b35",
    "name": "[email protected]",
    "picture": "https://secure.gravatar.com/avatar/ef417adb54a7e4db7773f3d434919711?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fb.png",
    "nickname": "b.boone",
    "last_password_reset": "2024-01-22T17:17:35.911Z",
    "user_metadata": {

    },
    "multifactor": [
      "guardian",
      [
        "otp",
        "sms",
        "email",
        "push"
      ]
    ],
    "multifactor_last_modified": "2024-05-31T18:50:13.044Z",
    "last_login": "2024-05-31T18:48:57.480Z",
    "last_ip": "47.206.147.48",
    "logins_count": 118,
    "app_metadata": {

    }
  }
]

Specifically, Newtonsoft Json cannot deserialize the following portion:

"multifactor": [
      "guardian",
      [
        "otp",
        "sms",
        "email",
        "push"
      ]
    ],

Example usage

public async Task<IPagedList<User>> GetUsersByEmailAddressAsync(string emailAddress)
=> await (
    await _managementApiClientFactory.CreateAsync()
).Users.GetAllAsync(new GetUsersRequest()
{
    Query = $"identities.connection:\"{CONNECTION_ID}\" AND email:\"{emailAddress}\"",
    SearchEngine = "v3"
});

Stack Trace:

Newtonsoft.Json.JsonReaderException: Error reading string. Unexpected token: StartArray. Path '[0].multifactor[1]', line 1, position 711.
   at Newtonsoft.Json.JsonReader.ReadAsString()
   at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType)
   at Newtonsoft.Json.Linq.JToken.ToObject[T]()
   at Auth0.ManagementApi.Paging.PagedListConverter`1.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Auth0.ManagementApi.HttpClientManagementConnection.SendRequest[T](HttpRequestMessage request, JsonConverter[] converters, CancellationToken cancellationToken)
   at Auth0.ManagementApi.HttpClientManagementConnection.GetAsyncInternal[T](Uri uri, IDictionary`2 headers, JsonConverter[] converters, CancellationToken cancellationToken)
   at Auth0.ManagementApi.HttpClientManagementConnection.<>c__DisplayClass13_0`1.<<GetAsync>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at Auth0.ManagementApi.HttpClientManagementConnection.Retry[TResult](Func`1 retryable)
   at Auth0.ManagementApi.HttpClientManagementConnection.GetAsync[T](Uri uri, IDictionary`2 headers, JsonConverter[] converters, CancellationToken cancellationToken)
   at nextech_auth0_shared.Services.Auth0ManagementService.GetUsersByEmailAddressAsync(String emailAddress) in C:\....\UserController.cs:line 125
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Nextech.Api.ResponseCache.ApiResponseCacheMiddleware.InvokeAsync(HttpContext context, IApiResponseCacheClient cache)
   at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

According to the Managemen API documentation, multifactor should be a list of string: [] and should not contain a nested array.

image

Reproduction

We traced the cause to our implementation of MFA in a onExecutePostLogin flow.

The call to enable MFA temporarily had the incorrect values:

api.multifactor.enable([
"otp",
"sms",
"email",
"push"
], {
      allowRememberBrowser: false,
});

And was changed to:

api.multifactor.enable('any', {
      allowRememberBrowser: false,
});

It seems the api.multifactor.enable method is not validating the parameters sent to it.

Additional context

No response

auth0.net version

7.26.2

.NET version

6

BrandonBoone avatar Jun 01 '24 14:06 BrandonBoone