Token authentication with Volley
Asked Answered
N

5

17

If I have a server where I authenticate with username/password and get auth token for subsequent requests, what would be the best approach addressing this problem?

The flow should be like this: - Start request - If we don't have auth token - get it with username and password - Make request with auth token - If request failed because token expired, get new auth token with user name and password - Retry request with new auth token - Finish

I've noticed that Volley already might have something that might solve this issue - Authenticator https://android.googlesource.com/platform/frameworks/support/+/4474bc11f64b2b274ca6db5a1e23e8c1d143d5fa/volley/src/com/android/volley/toolbox/Authenticator.java It contains getAuthToken() and invalidateAuthToken() methods which would be exactly what I want. But it seems that it's never used in the library at all.

Nigrify answered 1/7, 2013 at 8:42 Comment(3)
I've just checked the sources, and it looks like you are - Authenticator is not used in the code. So probably you will have to do it manually.Pisolite
Yeah. In the meantime I've copied BasicNetwork class and made adjustments there to do authentication for me.Nigrify
can you post how you did it as answer, pleasePenguin
S
12

I used volley for an authentication system using longlive (LLT) and shortlive (SLT) tokens.

I did it manually but it really wasn't much work once you get it all laid out.

Have all secure requests subclass a baseSecureRequest that can handle this token mechanism common to all secure request in its onResponse() and onErrorResponse().

It becomes a little node.js style, where requests send other requests and await callbacks.


An app may have a dozen screens, with only half requiring auth access - so each screen should be ignorant as to the requirements of its request.

Scenario A

  • We attempt to send a secure request. We notice we don't have a SLT in memory, so make a TokenRequest.
  • TokenRequest's onResponse() saves that token to memory (let a singleton session manager hold onto it or similar omni-present class)
  • Now callback to the original concrete-class request object to continue with the newly updated token.

Scenario B

  • We send a secure request but our SLT is stale (expired)

  • The server returns an error code or msg that you can catch in the general onErrorResponse() of your baseSecureRequest.

  • In this onError(), you send a refreshTokenRequest() object that attempts to refresh the SLT in memory by requesting a new SLT from the server using the LLT.

  • the onResponse() of the refreshTokenRequest can now callback to the original request to resend.

  • however the onErrorResponse() should probably abandon the entire thing because chances are anything that isn't a connectivity error - is an error caused by invalid LLT. If you keep trying to refresh with a bad LLT you will never get out.
Saucier answered 24/8, 2013 at 3:58 Comment(3)
I disagree. onErrorResponse is too late for refreshing the token, because the request will be considered as failed no matter what you do. The correct place for requesting a new token will be in a custom RetryPolicy class. The retry policy will be asked to prepare for retry in 2 cases: 1. Timeout 2. AuthFailureError - which is what you want.Gomphosis
This is not a valid solution. By the time volley returns error it has already retried your request. The correct place to do this is to write a custom retry policy. Let's assume you have 3 threads for your API request. That means from your network queue you can theoretically have 3 requests in parallel. Now if the SLT expired, you will get 3 failures at different times. That means you will retry bunch of your refreshTokenRequest with either old SLT or keep retrying with new tokens with even if you have valid token.Dunagan
@Dunagan Could you explain in detail how to handle refresh token in case of multi-thread where request are processed in parallel. It would be great if you can share a code snippet.Firkin
U
1
  1. You might want to use the AccountManager API in Android for authentication and authorization. You may follow the blog here.
  2. For OAuth 2.0 server side implementation you may read the IETF draft V2-31 here.
  3. For better understanding of OAuth 2.0 you may read the blog by Nitesh Kumar here.
  4. For Server side implementation of OAuth 2.0 you can fork Apis Autherization Server repo at Github.
  5. More implementation option can be found at the website of OAuth 2.0 here.
Upsetting answered 10/7, 2013 at 19:30 Comment(2)
Thanks for response, but my questions is specifically about Volley. It's not about how to do authorization, but how to integrate it with VolleyNigrify
AndroidAuthenticator seems to use accountManager, but I am not sure how we are supposed to use AndroidAuthenticator.Predatory
D
1

Did you see this blog post? https://smaspe.github.io/2013/06/06/volley-part2.html

Demonstrates a simple way of overriding request object to use twitter tokens.

@Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = new HashMap<String, String>();
        String auth = "Basic "
                + Base64.encodeToString((TwitterValues.CONSUMER_KEY 
                + ":" + TwitterValues.CONSUMER_SECRET).getBytes(),
                        Base64.NO_WRAP);
        headers.put("Authorization", auth);
        return headers;
    }
Dishonest answered 4/1, 2015 at 13:22 Comment(2)
Link down. Do you have another post like this ?Demetra
@Demetra the linked blog was recently moved (and renamed) I updated the link.Merchant
H
0

In my case, I changed a "Basic" authentication to a Token authentication as follows:

@Override
public Map<String, String> getHeaders() throws AuthFailureError {
    Map<String,String> headers = new HashMap<>();
    //todo Esta es una authenticación basica (usuario y contraseña)
    /*String credentials = USER+":"+PASSWORD;
    String auth = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
    headers.put("Authorization", auth);*/
    //todo Esta es una authenticación con token (por tiempos)
    headers.put("Authorization", "Bearer" + " " + "tokenString");//App.getToken()
    return  headers;
}

What I did was to save the Login in a global static variable and then be able to use it.

Hatteras answered 17/9, 2019 at 14:9 Comment(0)
F
-2

getToken() failed. Status BAD_AUTHENTICATION error

I also faced the same problem.

Solution: check whether the device is sign-in with your Google account.

Fabianfabianism answered 14/2, 2018 at 14:57 Comment(1)
Is this supposed to be an answer or a new question?Nonbelligerent

© 2022 - 2024 — McMap. All rights reserved.