Rahul Chaurasia
Rahul Chaurasia

Reputation: 1641

How to add authenticate with refresh token with Asynchronous request within okhttp3 authenticator

I'm having a authenticator attached to a Okhttp3 client which is getting called successfully when a 401 response comes. Within the authenticator, I want to authenticate the user with refresh token. I'm using IBM AppId for authentication.

private Authenticator getAuthenticator() {
        return new Authenticator() {

            @Override
            public Request authenticate(Route route, Response response) throws IOException {
                // code to authenticate with refresh token 
                return null;
            }
        };
    }

And I've the following code to authenticate with refresh token:

AppID.getInstance().signinWithRefreshToken(getApplicationContext(), refreshTokenString, new AuthorizationListener() {
    @Override
    public void onAuthorizationFailure(AuthorizationException exception) {
        //Exception occurred
    }

    @Override
    public void onAuthorizationCanceled() {
        //Authentication canceled by the user
    }

    @Override
    public void onAuthorizationSuccess(AccessToken accessToken, IdentityToken identityToken, RefreshToken refreshToken) {
        //User authenticated
    }
});

Now as you can see that it is asynchronous request and I cannot put this code inside the authenticator because the method will return before the calling onAuthorizationSuccess(). Also, AppId doesn't have synchronous type of request which I can use. Can you please point me how do I use this code within the authenticator class. Please help me with this issue.

Upvotes: 3

Views: 1186

Answers (2)

Devangi
Devangi

Reputation: 375

I have a solution for that. Please try below code.

Make class like : TokenAuthenticator.java

import android.content.Context;
import android.support.annotation.Nullable;

import com.dmlllc.insideride.common.Preferences;
import com.dmlllc.insideride.model.AccessToken;
import com.dmlllc.insideride.restModel.RestResponse;
import com.dmlllc.insideride.restModel.requestModel.AccessTokenReq;

import java.io.IOException;

import okhttp3.Authenticator;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;

public class TokenAuthenticator implements Authenticator {

    private Context context;

    public TokenAuthenticator(Context context) {
        this.context = context;
    }

    @Nullable
        @Override
        public Request authenticate(Route route, Response response) throws IOException {
            // Refresh your access_token using a synchronous api request
            AccessTokenReq accessTokenReq = new AccessTokenReq(Preferences.getPreferenceString(context, Preferences.USERNAME_FOR_TOKEN, ""),
                    Preferences.getPreferenceString(context, Preferences.PASSWORD_FOR_TOKEN, ""));
            try {
                retrofit2.Response<RestResponse<AccessToken>> tokenResponse = Global.initRetrofit(context).getAccessToken(accessTokenReq).execute();
                if (tokenResponse.body() != null) {
                    if (tokenResponse.body().getResStatus().equals("success")) {
                        SessionManager sessionManager = new SessionManager(context);
                        sessionManager.storeToken(tokenResponse.body().getResults().getYourAccessToken());
                        Preferences.setPreferenceString(context, Preferences.ACCESS_TOKEN, tokenResponse.body().getResults().getYourAccessToken());
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }

            // Add new header to rejected request and retry it
            return response.request().newBuilder()
                    .header("Authorization", Preferences.getPreferenceString(context, Preferences.ACCESS_TOKEN, ""))
                    .build();
        }
    }

And then use this class in your retrofit method just like :

public static RestApi initRetrofit(Context context) {
        // For logging request & response (Optional)
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

        TokenAuthenticator tokenAuthenticator = new TokenAuthenticator(context);

        OkHttpClient client = new OkHttpClient.Builder()
                .authenticator(tokenAuthenticator)
                .addInterceptor(loggingInterceptor)
                .connectTimeout(1, TimeUnit.MINUTES)
                .writeTimeout(1, TimeUnit.MINUTES)
                .readTimeout(1, TimeUnit.MINUTES)
                .build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(URL.BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .client(client)
                .build();
        return retrofit.create(RestApi.class);
    }

Hope It will help you also. :) Happy Coding...!!!

Upvotes: 2

Flekken
Flekken

Reputation: 61

I have two solution that might interest you:

  1. Calling the API yourself. This might be hard, but you can also browse the AppId SDK for help.
  2. Fork and modify the AppId SDK with a syncronous signinWithRefreshToken() call and use that. Also make sure to create a feature request or pull request about this change in the original repo, so this might be included in the next version.
    Downside of this is that you have to maintain another fork of the AppId SDK and merge new changes overtime if needed.

Upvotes: 0

Related Questions