I'm working on a Oauth2 Token system to access my REST API for my Android app. I'm having some problems with the token refreshment part on the client side.
Here is the flow: My app makes a request (with an access Token in parameter) to the server thanks some asynctask ( PostCommentAsyncTask(), AddFriendAsyncTask() etc...), so if the accessToken is valid it's ok, but if it has expired I call another AsyncTask (GetRefreshTokenAsyncTask()) from the onPostExecute() method of the precedent AsyncTask to get new accessToken. Here is the tricky part for me. When I get the new access Token I want to re-execute the initial AsyncTask request to the server. I can't figure out how to do it properly.
example1:
request PostCommentAsyncTask() --> (acessToken expired) -->GetRefreshTokenAsyncTask()-->request PostCommentAsyncTask()--> (good token)--> Ok
EDIT:
I finally chose to use the Volley library ( no need to use Asynctask anymore ).
As I use JSON Web Token I can check the expire date which is encoded in the payload of the token.
Here is the isAccessTokenExpired() method to check if the Access Token is not expired before making a request to the server:
public Boolean isAccessTokenExpired(String accessToken){
String[] accessTokenPart = accessToken.split("\\.");
String header =accessTokenPart[0];
String payload =accessTokenPart[1];
String signature =accessTokenPart[2];
try {
byte[] decodedPayload = Base64.decode(payload, Base64.DEFAULT);
payload = new String(decodedPayload,"UTF-8");
} catch(UnsupportedEncodingException e) {
e.printStackTrace();
}
try {
JSONObject obj = new JSONObject(payload);
int expireDate = obj.getInt("exp");
Timestamp timestampExpireDate= new Timestamp( expireDate);
long time = System.currentTimeMillis();
Timestamp timestamp = new Timestamp(time);
return timestamp.after(timestampExpireDate);
} catch (JSONException e) {
e.printStackTrace();
return true;
}
}
And here is the refreshJsonWebToken() method to get a new pair of Access token/Refresh token from my OAUTH2 server:
public void refreshJsonWebToken(){
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
String refreshToken = settings.getString("refreshToken", null);
final HashMap params = new HashMap();
params.put("grant_type","refresh_token");
params.put("client_id","client");
params.put("refresh_token",refreshToken);
JsonObjectRequest req = new JsonObjectRequest(URL_OAUTH2, new JSONObject(params), new Response.Listener() {
@Override
public void onResponse(JSONObject response) {
try {
String newRefreshToken = response.getString("refresh_token");
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putString("accessToken", newAccessToken);
editor.putString("refreshToken", newRefreshToken);
editor.apply();
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("grid", "Error: " + error.getMessage());
}
}
});
AppController.getInstance().addToRequestQueue(req);
}
And finally the getPost() method where I use the precedent methods:
private void getPost(String latitude, String longitude) {
SharedPreferences settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
String accessToken = settings.getString("accessToken", null);
final HashMap params = new HashMap();
params.put("action", "getLocalPosts");
params.put("latitude", latitude);
params.put("longitude", longitude);
if (isAccessTokenExpired(accessToken)){
refreshJsonWebToken();
}
settings = getActivity().getSharedPreferences(PREFS_NAME, 0);
accessToken = settings.getString("accessToken", null);
JsonObjectRequest req = new JsonObjectRequest(URL_APP+accessToken, new JSONObject(params), new Response.Listener() {
//Some code ....
});
AppController.getInstance().addToRequestQueue(req);
}