Skip to content

Instantly share code, notes, and snippets.

@alex-shpak
Last active June 14, 2024 02:40
Show Gist options
  • Save alex-shpak/da1e65f52dc916716930 to your computer and use it in GitHub Desktop.
Save alex-shpak/da1e65f52dc916716930 to your computer and use it in GitHub Desktop.
Refreshing OAuth token with okhttp interceptors. All requests will wait until token refresh finished, and then will continue with the new token.
private class HttpInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//Build new request
Request.Builder builder = request.newBuilder();
builder.header("Accept", "application/json"); //if necessary, say to consume JSON
String token = settings.getAccessToken(); //save token of this request for future
setAuthHeader(builder, token); //write current token to request
request = builder.build(); //overwrite old request
Response response = chain.proceed(request); //perform request, here original request will be executed
if (response.code() == 401) { //if unauthorized
synchronized (httpClient) { //perform all 401 in sync blocks, to avoid multiply token updates
String currentToken = settings.getAccessToken(); //get currently stored token
if(currentToken != null && currentToken.equals(token)) { //compare current token with token that was stored before, if it was not updated - do update
int code = refreshToken() / 100; //refresh token
if(code != 2) { //if refresh token failed for some reason
if(code == 4) //only if response is 400, 500 might mean that token was not updated
logout(); //go to login screen
return response; //if token refresh failed - show error to user
}
}
if(settings.getAccessToken() != null) { //retry requires new auth token,
setAuthHeader(builder, settings.getAccessToken()); //set auth token to updated
request = builder.build();
return chain.proceed(request); //repeat request with new token
}
}
}
return response;
}
private void setAuthHeader(Request.Builder builder, String token) {
if (token != null) //Add Auth token to each request if authorized
builder.header("Authorization", String.format("Bearer %s", token));
}
private int refreshToken() {
//Refresh token, synchronously, save it, and return result code
//you might use retrofit here
}
private int logout() {
//logout your user
}
}
@Kolyall
Copy link

Kolyall commented Feb 6, 2018

@jaswanthm how to implement refresh token with Authenticator but avoid multiply token updates from different threads?

@andrconstruction
Copy link

Hi.How do you implement the logout function within the interceptor? is The intercpetor standalone class or a part of an activity?

@alex-shpak
Copy link
Author

@Kolyall
In example synchronized block is used to avoid multiple tokens updates.

@andrconstruction
What kind of logout you need to implement?
Usually it's enough to "forget" api key (and then to not send it to server)

@roni-castro
Copy link

roni-castro commented Dec 5, 2018

@paragones Did you find a way to refresh the token using rxjava?

@maxim-petlyuk
Copy link

@paragones Did you find a way to refresh the token using rxjava?

https://gist.github.com/mpetlyuk/77ac3221c1776d14654374faf2985d5a
look at my implementation. Include my transformer into each request observable via mehtod Observable.compose(/* refresh transformer*/)

@Tgo1014
Copy link

Tgo1014 commented Dec 5, 2019

Very useful. Thanks!

@silwar
Copy link

silwar commented Jan 12, 2021

This is very good. Thanks for sharing this.
Only issue with this implementation is after token gets refreshed, all other requests get executed in serial.
Is there a way to make execution of those requests parallel?

@mecoFarid
Copy link

private int refreshToken() {
		//Refresh token, synchronously, save it, and return result code
		//you might use retrofit here
}

So you are proposing to use retrofit inside Interceptor to refresh token? This is quite ugly workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment