6

I am using the Refit library with my Xamarin forms project to send API requests. It works great, but have an issue when the access token expires.

When the access token expires, I get an 401 error from the server, as expected. I then make a call to the Identity Server to issue a new access token, but I am having difficulty in resubmitting the API request. I still get unauthorised error. Appreciate some help.

I have created an AuthenticatedHttpClientHandler class to handle the token.

public class AuthenticatedHttpClientHandler : HttpClientHandler
{
    private readonly string _token;

    public AuthenticatedHttpClientHandler(string token ) 
    {
        _token = token;       
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var auth = request.Headers.Authorization;
        if (auth != null && !string.IsNullOrWhiteSpace(_token))
        {
            request.Headers.Authorization = new AuthenticationHeaderValue(auth.Scheme, _token);
        }
        else
        {
            request.Headers.Remove("Authorization");
        }
        var result = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
        if (result.StatusCode == System.Net.HttpStatusCode.Unauthorized )
        {
            IdSrvApiService idsrvApiService = new IdSrvApiService();
            RefreshTokenService refreshTokneService = new RefreshTokenService(idsrvApiService);

            if( Settings.RefreshToken != ""){
                var newToken = await refreshTokneService.RefreshAccessToken(Priority.Background).ConfigureAwait(false);
                TokenHelper.CacheToken(newToken);
                request.Headers.Authorization = new AuthenticationHeaderValue(auth.Scheme, Settings.AccessToken);
                return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                return result;
            }
        }
        else
        {
            return result;
        }
    }
}
Libin Joseph
  • 7,070
  • 5
  • 29
  • 52
  • I would suggest inspecting the raw request sent to see if the one sent after refresh token has the proper headers sent. – Nkosi Jan 14 '18 at 22:05
  • There is also the chance that you are sending the wrong token on the second try. Confirm that the value in `newToken` is what is being used via `Settings.AccessToken` – Nkosi Jan 14 '18 at 22:16

3 Answers3

3

I would suggest inspecting the raw request sent to see if the one sent after refresh token has the proper headers sent.

There is also the chance that you are sending the wrong token on the second try. Confirm that the value in newToken is what is being used via Settings.AccessToken

Nkosi
  • 235,767
  • 35
  • 427
  • 472
2

Sometimes I get same error. It's more likely happened because time difference between server and client. When I get the this error, I force to user logout.

But I never try to refresh Token. In your code, you want to refresh_token but you sending request with access_token. Maybe it can be your fault.

 var newToken = await refreshTokneService.RefreshAccessToken(Priority.Background).ConfigureAwait(false);

I think, you have a problem in this method.

2

Check if your refresh token service sends the right headers and parameters on the http body post.

Headers:

  • Accept : application/json

Body:

  • grant_type : refresh_token
  • client_id : Your Client Id (if applicable)
  • client_secret : Your Client Secret (if applicable)
  • refresh_token : The refresh token property (refresh_token) returned when you acquired the access token

Make sure your're passing the right Content-Type (application/x-www-form-urlencoded) inside the body header request (https://stackoverflow.com/a/5665663/4738253 or use the FormUrlEncodedContent to create and encoded content).

Douglas Gandini
  • 827
  • 10
  • 24
  • and using **OAuth Token** *authorization client_credentials*: `grant_type=client_credentials &client_id=example_client_id &client_secret=example_client_secret &scope=user.read` ? – Kiquenet May 21 '20 at 10:39