I created a class to get refresh token if the token get expired at any time. Always call to this class before do a rest API call.
Here is my class,
import android.content.Context;
import com.epic.ssb.data.TokenModel;
import com.epic.ssb.security.LogoutProcess;
import com.epic.ssb.security.TokenIdentifier;
import com.epic.ssb.util.Constant;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RefreshTokenInterceptor implements Interceptor {
private Lock lock = new ReentrantLock();
Context ctx;
public RefreshTokenInterceptor(Context context){
this.ctx = context;
}
@Override
public Response intercept(Chain chain) throws IOException {
chain.withConnectTimeout( 45, TimeUnit.SECONDS);
chain.withReadTimeout(45,TimeUnit.SECONDS);
chain.withWriteTimeout(45,TimeUnit.SECONDS);
Request request = chain.request();
Response response = chain.proceed(request);
if (response.code() == HttpURLConnection.HTTP_UNAUTHORIZED) {
if (lock.tryLock()) {
try {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Content-Type", "application/json")
.header("X-Requested-With", "XMLHttpRequest")
.header("X-Authorization", "Bearer " + TokenIdentifier.getREFRESHTOKEN())
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constant.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
ApiService apiService = retrofit.create(ApiService.class);
Call<TokenModel> call = apiService.getTokenFromRefreshToken();
retrofit2.Response<TokenModel> response1 = call.execute();
if(response.body()!=null){
TokenModel tokenModel = response1.body();
TokenIdentifier.setTOKEN(tokenModel.getToken());
}
Request newRequest = recreateRequestWithNewAccessToken(chain);
return chain.proceed(newRequest);
} catch (Exception ex) {
LogoutProcess.logout(ctx);
return response;
} finally {
lock.unlock();
}
} else {
lock.lock();
lock.unlock();
Request newRequest = recreateRequestWithNewAccessToken(chain);
return chain.proceed(newRequest);
}
} else {
return response;
}
}
private Request recreateRequestWithNewAccessToken(Chain chain) {
String freshAccessToken = TokenIdentifier.getTOKEN();
return chain.request().newBuilder()
.header("Content-Type", "application/json")
.header("X-Requested-With", "XMLHttpRequest")
.header("X-Authorization", "Bearer " + freshAccessToken)
.method(chain.request().method(), chain.request().body())
.build();
}
}
Note : This class is using to get a new token if the current token is expired.
Then I got below exception randomly for above class is accessed,
W/System.err: java.net.SocketTimeoutException: timeout
W/System.err: at okio.Okio$4.newTimeoutException(Okio.java:232)
at okio.AsyncTimeout.exit(AsyncTimeout.java:285)
W/System.err: at okio.AsyncTimeout$1.write(AsyncTimeout.java:184)
at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:179)
at okio.RealBufferedSink.write(RealBufferedSink.java:42)
at okhttp3.internal.http1.Http1Codec$FixedLengthSink.write(Http1Codec.java:295)
at okio.ForwardingSink.write(ForwardingSink.java:35)
at okhttp3.internal.http.CallServerInterceptor$CountingSink.write(CallServerInterceptor.java:149)
W/System.err: at okio.RealBufferedSink.emitCompleteSegments(RealBufferedSink.java:179)
at okio.RealBufferedSink.write(RealBufferedSink.java:48)
at okhttp3.RequestBody$1.writeTo(RequestBody.java:73)
at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:72)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
W/System.err: at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
W/System.err: at com.epic.ssb.network.RefreshTokenInterceptor.intercept(RefreshTokenInterceptor.java:39)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:147)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
W/System.err: Caused by: java.net.SocketException: Socket closed
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:124)
at java.net.SocketOutputStream.write(SocketOutputStream.java:161)
at okio.Okio$1.write(Okio.java:79)
at okio.AsyncTimeout$1.write(AsyncTimeout.java:180)
W/System.err: ... 30 more
As I mentioned on the top of the post, this is using for secured Rest API calls. Not for unauthorized Rest API calls.
why is this happening randomly ? Should I add more steps ?