IdentityModel / IdentityModel.OidcClient.Old

OpenID Connect Client Library for Native Applications
Other
38 stars 17 forks source link

RefreshTokenHandler throws exception when refresh token expires #29

Closed jrcpereira closed 8 years ago

jrcpereira commented 8 years ago

When using the RefreshTokenHandler to create the HttpClient, it throws an Unhandled Exception when the token and the refresh token aren't valid.

image

This is the code I use to make the call

var handler = new RefeshTokenHandler(Constants.TokenClient, Settings.RefreshToken, Settings.AccessToken);
using (var client = new HttpClient(handler))
{
     var result = await client.GetAsync(Constants.APIClaims).ConfigureAwait(false);
     return await result.Content.ReadAsStringAsync().ConfigureAwait(false);
}

I believe that when it receives the 401 response, it tries to open the authentication page and the exception is thrown because the HttpClient cannot handle it.

My implementation is Xamarin Android and I based it on the sample project AndroidClientChromeCustomTabs.

I believe this isn't exactly a bug, but more an incomplete feature, despite I don't think the library can handle it in a generic way...

Great job you guys doing! Thanks!

leastprivilege commented 8 years ago

Were you able to track down the problem?

jrcpereira commented 8 years ago

Sorry for the delay... I was on vacation.

I didn't had time to review this, but the exception originates on the IdentityModel TokenResponse class. I will dig more into this the next days, but here is the error log.

09-02 17:21:41.351 I/MonoDroid( 2516): UNHANDLED EXCEPTION: 09-02 17:21:41.351 I/MonoDroid( 2516): System.InvalidOperationException: Invalid JSON response ---> Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: <. Path '', line 0, position 0. 09-02 17:21:41.351 I/MonoDroid( 2516): at Newtonsoft.Json.JsonTextReader.ParseValue () [0x002b3] in :0 09-02 17:21:41.351 I/MonoDroid( 2516): at Newtonsoft.Json.JsonTextReader.Read () [0x0004c] in :0 09-02 17:21:41.351 I/MonoDroid( 2516): at Newtonsoft.Json.Linq.JObject.Load (Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Linq.JsonLoadSettings settings) [0x00013] in :0 09-02 17:21:41.351 I/MonoDroid( 2516): at Newtonsoft.Json.Linq.JObject.Parse (System.String json, Newtonsoft.Json.Linq.JsonLoadSettings settings) [0x0000c] in :0 09-02 17:21:41.351 I/MonoDroid( 2516): at Newtonsoft.Json.Linq.JObject.Parse (System.String json) [0x00000] in :0 09-02 17:21:41.351 I/MonoDroid( 2516): at IdentityModel.Client.TokenResponse..ctor (System.String raw) [0x0000d] in c:\local\identity\model\IdentityModel\source\IdentityModel.Shared\Client\TokenResponse.cs:26 09-02 17:21:41.351 I/MonoDroid( 2516): --- End of inner exception stack trace --- 09-02 17:21:41.351 I/MonoDroid( 2516): at IdentityModel.Client.TokenResponse..ctor (System.String raw) [0x0001c] in c:\local\identity\model\IdentityModel\source\IdentityModel.Shared\Client\TokenResponse.cs:30 09-02 17:21:41.351 I/MonoDroid( 2516): at IdentityModel.Client.TokenClient+d1.MoveNext () [0x00160] in c:\local\identity\model\IdentityModel\source\IdentityModel.Shared\Client\TokenClient.cs:86 09-02 17:21:41.351 I/MonoDroid( 2516): --- End of stack trace from previous location where exception was thrown --- 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00047] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter'1[TResult].GetResult () [0x00000] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:357 09-02 17:21:41.351 I/MonoDroid( 2516): at IdentityModel.Client.RefeshTokenHandler+d7.MoveNext () [0x000d5] in c:\local\identity\model\IdentityModel\source\IdentityModel.Shared\Client\RefreshTokenHandler.cs:137 09-02 17:21:41.351 I/MonoDroid( 2516): --- End of stack trace from previous location where exception was thrown --- 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00047] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter'1[TResult].GetResult () [0x00000] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:357 09-02 17:21:41.351 I/MonoDroid( 2516): at IdentityModel.Client.RefeshTokenHandler+d0.MoveNext () [0x0018b] in c:\local\identity\model\IdentityModel\source\IdentityModel.Shared\Client\RefreshTokenHandler.cs:106 09-02 17:21:41.351 I/MonoDroid( 2516): --- End of stack trace from previous location where exception was thrown --- 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00047] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.ConfiguredTaskAwaitable'1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:535 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Net.Http.HttpClient+casync0.MoveNext () [0x000a9] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/mcs/class/System.Net.Http/System.Net.Http/HttpClient.cs:276 09-02 17:21:41.351 I/MonoDroid( 2516): --- End of stack trace from previous location where exception was thrown --- 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00047] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.ConfiguredTaskAwaitable'1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:535 09-02 17:21:41.351 I/MonoDroid( 2516): at ProjXMobile.ServiceAccessLayer.API.ClaimsWrapper+d0.MoveNext () [0x000b6] in C:\Dev\Projects\ProjX\ProjX v2\Main\ProjXMobile\ProjXMobile\ServiceAccessLayer\API\ClaimsWrapper.cs:27 09-02 17:21:41.351 I/MonoDroid( 2516): --- End of stack trace from previous location where exception was thrown --- 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00047] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter'1[TResult].GetResult () [0x00000] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:357 09-02 17:21:41.351 I/MonoDroid( 2516): at ProjXMobile.Helpers.UserLogic+d0.MoveNext () [0x00068] in C:\Dev\Projects\ProjX\ProjX v2\Main\ProjXMobile\ProjXMobile\Helpers\UserLogic.cs:23 09-02 17:21:41.351 I/MonoDroid( 2516): --- End of stack trace from previous location where exception was thrown --- 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00047] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.TaskAwaiter'1[TResult].GetResult () [0x00000] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:357 09-02 17:21:41.351 I/MonoDroid( 2516): at ProjXMobile.Droid.Screens.MainActivity+d2.MoveNext () [0x00044] in C:\Dev\Projects\ProjX\ProjX v2\Main\ProjXMobile\ProjXMobile.Droid\Screens\MainActivity.cs:28 09-02 17:21:41.351 I/MonoDroid( 2516): --- End of stack trace from previous location where exception was thrown --- 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 09-02 17:21:41.351 I/MonoDroid( 2516): at System.Runtime.CompilerServices.AsyncMethodBuilderCore.m0 (System.Object state) [0x00000] in /Users/builder/data/lanes/3415/7db2aac3/source/mono/external/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1018 09-02 17:21:41.351 I/MonoDroid( 2516): at Android.App.SyncContext+cAnonStorey0.<>m0 () [0x00000] in /Users/builder/data/lanes/3415/7db2aac3/source/monodroid/src/Mono.Android/src/Android.App/SyncContext.cs:18 09-02 17:21:41.351 I/MonoDroid( 2516): at Java.Lang.Thread+RunnableImplementor.Run () [0x0000b] in /Users/builder/data/lanes/3415/7db2aac3/source/monodroid/src/Mono.Android/src/Java.Lang/Thread.cs:36 09-02 17:21:41.351 I/MonoDroid( 2516): at Java.Lang.IRunnableInvoker.n_Run (IntPtr jnienv, IntPtr native__this) [0x00009] in /Users/builder/data/lanes/3415/7db2aac3/source/monodroid/src/Mono.Android/platforms/android-23/src/generated/Java.Lang.IRunnable.cs:81 09-02 17:21:41.351 I/MonoDroid( 2516): at (wrapper dynamic-method) System.Object:e9fdb5d8-6800-4701-9768-4fc5aefadc78 (intptr,intptr)

jrcpereira commented 8 years ago

Ok, I've just debugged this error through the IdentityModel source code, and found the root of the problem, but was wondering if it is the expected behavior.

  1. A request is made to an API with an expired AccessToken and RefreshToken.
  2. IdentityModel SendAsync from RefreshTokenHandler class is executed, and gets an 401 response (line 99).
  3. It then calls RequestRefreshTokensAsync extension method from TokenClient to request new AccessToken which always returns a 200 response with the content being a string with the IdentityServer homepage HTML code.
  4. It then tries to create a TokenResponse with the response, which fails throwing an exception in line 26 when it tries to parse the HTML string as JSON.

Is it supposed to return Success when refreshing the token, even when the refresh isn't successful?

Is this some WebAPI configuration that I am missing that should return empty content instead of HTML string?

Thanks!

leastprivilege commented 8 years ago

I don't understand #3 - the request should go to the token endpoint. Why does it return html?

jrcpereira commented 8 years ago

The request is sent to the TokenClient base address which in my case is 'http://10.18.30.26:8090/'.

I configured the IdServer UI to be served on the root of the domain instead on the 'core' path as seen on the samples. Does this make any difference?

leastprivilege commented 8 years ago

Which address do you pass into TokenClient?

jrcpereira commented 8 years ago

Yeah, after my last response, I just come to my senses... slowly... :) I was passing the base address instead of the token endpoint. Duhhh

In the example, the token client is obtained from the LoginAsync result, where the base address is used. Since I was creating a new TokenClient, I was also using the base address...

It now returns

Error: Invalid grant

as expected.

Thank you for your time and support.