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 wich 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<String, String> params = new HashMap<String, String>();
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<JSONObject>() {
@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 finnally 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<String, String> params = new HashMap<String, String>();
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<JSONObject>() {
//Some code ....
});
AppController.getInstance().addToRequestQueue(req);
}
get()
method of your secondAsyncTask
indoInBackground()
method of your firstAsyncTask
. Theget()
method ofAsyncTask
is a blocking method which returns a result - it's completely useless to use it on the main/UI thread but if you call it from the firstAsyncTask
'sdoInBackground()
method (which runs on its own thread) then you can simply carry on with the original task once the secondAsyncTask
'sget()
method returns. Just an idea. – Peag