Ad

Get Access Token From Refresh Token In Volley

I am using Android Volley to send an HTTP request to the blogger API website to get the user's blog:

https://www.googleapis.com/blogger/v3/users/self/blogs

I sent a Volley request to this website with an HTTP Authorization header with bearer Access token as said in the documentation:

GET https://www.googleapis.com/blogger/v3/users/self/blogs
Authorization: /* OAuth 2.0 token here */

I sent the request like this:

RequestQueue queue = Volley.newRequestQueue(this);
String url = "https://www.googleapis.com/blogger/v3/users/self/blogs";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
        new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                // handle response
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Toasty.warning(SelectBlog.this, error.getMessage(), Toast.LENGTH_LONG).show();
        }
    }){
        @Override
        public Map<String, String> getHeaders() {
            HashMap<String, String> params = new HashMap<>();

            params.put("Authorization", "Bearer ACCESS TOKEN");

            return params;
        }
    };

    queue.add(stringRequest);

Now everything seems fine but I see that the access token changes every 3599 seconds. I want to know to update the access token programmatically using refresh token provided by the OAuth Playground website.

Ad

Answer

You probably got your refresh token when you were issued with your access token.

{
  "access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in":3920,
  "token_type":"Bearer",
  "refresh_token":"1/xEoDL4iW3cxlI7yDbSRFYNG01kVKM2C-259HOF2aQbI"
}

Above is a sample response for the token request. You should store this refresh token somewhere safe so that you can refresh your access token without another authentication process via google login.

Don't try to refresh your access token periodically. Your logic should not depend on its expiration time because the policy might change later.

Just try to refresh it when you actually get 401 error from any API response. Therefore what I would do is try to refresh access token when you encounter 401 http status code (which usually means the token has expired) in the onErrorResponse method of your volley request.

https://developers.google.com/identity/protocols/OAuth2InstalledApp

In the above link, you can find information on how to refresh your access token. In the Refreshing an access token section, it shows a sample request.

POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

client_id=<your_client_id>&
client_secret=<your_client_secret>&
refresh_token=<refresh_token>&
grant_type=refresh_token

Fill in the required information and send a post request with Volley. Then in the success block, parse your response to get access token, which you can use to retry calling blog API.

EDIT: See code snippet below. It is a rather mediocre code but it will be enough for the concept. The point is that you refresh your access token with 401 error on blog API and then retry that API with the new access token from the response

RequestQueue queue;
String tokenUrl = "https://www.googleapis.com/oauth2/v4/token";
String blogUrl = "https://www.googleapis.com/blogger/v3/users/self/blogs";

public void onCreate() {
    queue = Volley.newRequestQueue(getApplicationContext());
    fetchBlogs("${your original access token here}");
}

void fetchBlogs(final @NonNull String accessToken) {
    JsonObjectRequest blogRequest = new JsonObjectRequest(Request.Method.GET, blogUrl, null, new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            // successfully got blog response
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            if (error.networkResponse.statusCode == 401) {
                refreshAccessToken();
            } else {
                // irrecoverable errors. show error to user.
            }
        }
    }) {
        @Override
        public Map<String, String> getHeaders() {
            Map<String, String> headers = new HashMap<>();
            headers.put("Authorization", "Bearer " + accessToken);
            return headers;
        }
    };
    queue.add(blogRequest);
}

void refreshAccessToken() {
    JSONObject params = new JSONObject();
    try {
        params.put("client_id", "${your client id here}");
        params.put("client_secret", "${your client secret here}");
        params.put("refresh_token", "${your refresh token here}");
        params.put("grant_type", "refresh_token");
    } catch (JSONException ignored) {
        // never thrown in this case
    }

    JsonObjectRequest refreshTokenRequest = new JsonObjectRequest(Request.Method.POST, tokenUrl, params, new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            try {
                String accessToken = response.getString("access_token");
                fetchBlogs(accessToken);
            } catch (JSONException e) {
                // this will never happen but if so, show error to user.
            }
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            // show error to user. refresh failed.
            Log.e("Error on token refresh", new String(error.networkResponse.data));

        }
    });
    queue.add(refreshTokenRequest);
}
Ad
source: stackoverflow.com
Ad