How does one use Basic Authentication with Volley on Android?
Asked Answered
B

3

28

I'm looking through examples and code but I don't see anything implemented. Is this possible at this stage?

Bacchius answered 29/5, 2013 at 15:26 Comment(1)
I have tested both solutions but still an error 401 #53839622Urdar
M
10

Yes it's possible. You need to override Request.getHeaders(). I'm lazy and I used HttpHeaders and HttpAuthentication from Spring for Android but you can just build the auth header and return it from the method. From getHeaders() you can return the auth header for basic auth. This is a sample request with basic auth.

public class GetUser extends Request<User> {

    private static final String TAG = GetUser.class.getName();

    private Response.Listener<User> mListener;
    private ObjectMapper mMapper = new ObjectMapper();

    public GetUser(Response.ErrorListener errorListener, Response.Listener<User> listener){
        super(Method.GET, PoisUtils.BASE_URL + "/users", errorListener);

        mListener = listener;
    }

    @Override
    protected Response<User> parseNetworkResponse(NetworkResponse response) {
        String jsonString = new String(response.data);
        try {
            User result = mMapper.readValue(jsonString, User.class);
            return Response.success(result, getCacheEntry());
        } catch (IOException e) {
            Log.d(TAG, e.getMessage());
        }
        return null;
    }

    @Override
    protected void deliverResponse(User response) {
        mListener.onResponse(response);
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        return AuthUtils.buildAuthHeaders().toSingleValueMap();
    }
}

And here is how I build the auth headers

public static HttpHeaders buildAuthHeaders(){

    if(UserUtils.isUserLogged()){
        HttpHeaders requestHeaders = new HttpHeaders();
        User user = PoisApplication.get().getUser();

        HttpAuthentication auth = new HttpBasicAuthentication(
                user.getUsername(), user.getPassword());
        requestHeaders.setAuthorization(auth);

        return requestHeaders;
    }
    return null;
}
Mozarab answered 29/5, 2013 at 17:2 Comment(7)
Thank you for the reply. However, this looks like a very common/basic feature, and I think a library like volley should implement this somehow in an easier way. I'm trying out this library, and it looks promising (really excited about a good caching HTTP library), but I'm finding certain parts that don't make much sense: like I would like the parsing part (json, xml...) be part of the Listener and not the Request, that way I could create my own base Request that will add these headers all the time. Maybe it should be the RequestQueue the one having some default options (headers)... Some ideas.Bacchius
I'm not sure it's what you want to do, but you could create something like this gist.github.com/alexmazza/5659606 with the getHeaders() method implemented. I'm using jackson there but you could use Gson or anything else, and then always use that class as a base class for your authenticated requestsMozarab
Yeah, but it if I want to get some JSON data, and later some xml data, I would have to replicate the logic, or create a base class, that has the headers code, and then I would have to create 2 subclasses, and I wouldn't be able to use the default JsonRequest, etc... To me, it looks like response and requests should be in different classes (parsing should belong to the Listener) so that you could mixed them up. Inheritance issues! ;) Thanks for the reply anyway.Bacchius
Hi again, I'm trying to do this manually, so when curling my url, authorization works with something like -H "Authorization: Basic <KEY>" (<KEY> being Base 64 encoded versino of user:passw). However, if I return a map containing a key "Authorization" and a value for that key "Basic <KEY>", volley still returns an error. Is there a specific format I need to follow? Thank you!Bacchius
I found this github.com/njzk2/VolleyTwitter/blob/master/src/com/njzk2/…Mozarab
Awesome, I found the same link a while ago and it is working like a charm! Thanks!Bacchius
Why bother responding if you're lazy? :)Uella
A
93

For those who don't want to use Spring for Android just for that, here's how to do it.

@Override
public Map<String, String> getHeaders() throws AuthFailureError {
    HashMap<String, String> params = new HashMap<String, String>();
    String creds = String.format("%s:%s","USERNAME","PASSWORD");
    String auth = "Basic " + Base64.encodeToString(creds.getBytes(), Base64.DEFAULT);
    params.put("Authorization", auth);
    return params;
}

Note that you may have to use Base64.NO_WRAP instead of Base64.DEFAULT for this to work. As pointed in the comments.

API 8+

Again answered 24/9, 2013 at 11:32 Comment(7)
This is really good as the final size of the APK is very important for small projects.Wholehearted
It's worth noting that I needed to use Base64.NO_WRAP instead of Base64.DEFAULT in order for this to work for me.Anecdotage
@Anecdotage Your comment helped me to fix 400 error on Andrpiod 2.3 devices. What can be a reason of the issue?Lemniscus
Even i had to use use Base64.NO_WRAP instead of Base64.DEFAULT for it to work. I am using Play and it gave exception p.nettyException - Exception caught in Netty java.lang.IllegalArgumentException: Header name cannot contain the following prohibited characters: =,;: \t\r\n\v\f when i used Base64.DEFAULT. Any idea why? Also please edit your post with this change.Pyroxene
Yes, you must use NO_WRAP as otherwise it a line break might split the encoded string into two lines which is not allowed for HTTP headers. A line break always indicates a new header line. The second line of the base64 string is not a valid header line causing this exception.Paz
This worked for me but I had to use NO_WRAP for it to workEvangelist
So where does this fit into Volley? Do I have to extend StringRequest and override it there?Comedienne
M
10

Yes it's possible. You need to override Request.getHeaders(). I'm lazy and I used HttpHeaders and HttpAuthentication from Spring for Android but you can just build the auth header and return it from the method. From getHeaders() you can return the auth header for basic auth. This is a sample request with basic auth.

public class GetUser extends Request<User> {

    private static final String TAG = GetUser.class.getName();

    private Response.Listener<User> mListener;
    private ObjectMapper mMapper = new ObjectMapper();

    public GetUser(Response.ErrorListener errorListener, Response.Listener<User> listener){
        super(Method.GET, PoisUtils.BASE_URL + "/users", errorListener);

        mListener = listener;
    }

    @Override
    protected Response<User> parseNetworkResponse(NetworkResponse response) {
        String jsonString = new String(response.data);
        try {
            User result = mMapper.readValue(jsonString, User.class);
            return Response.success(result, getCacheEntry());
        } catch (IOException e) {
            Log.d(TAG, e.getMessage());
        }
        return null;
    }

    @Override
    protected void deliverResponse(User response) {
        mListener.onResponse(response);
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        return AuthUtils.buildAuthHeaders().toSingleValueMap();
    }
}

And here is how I build the auth headers

public static HttpHeaders buildAuthHeaders(){

    if(UserUtils.isUserLogged()){
        HttpHeaders requestHeaders = new HttpHeaders();
        User user = PoisApplication.get().getUser();

        HttpAuthentication auth = new HttpBasicAuthentication(
                user.getUsername(), user.getPassword());
        requestHeaders.setAuthorization(auth);

        return requestHeaders;
    }
    return null;
}
Mozarab answered 29/5, 2013 at 17:2 Comment(7)
Thank you for the reply. However, this looks like a very common/basic feature, and I think a library like volley should implement this somehow in an easier way. I'm trying out this library, and it looks promising (really excited about a good caching HTTP library), but I'm finding certain parts that don't make much sense: like I would like the parsing part (json, xml...) be part of the Listener and not the Request, that way I could create my own base Request that will add these headers all the time. Maybe it should be the RequestQueue the one having some default options (headers)... Some ideas.Bacchius
I'm not sure it's what you want to do, but you could create something like this gist.github.com/alexmazza/5659606 with the getHeaders() method implemented. I'm using jackson there but you could use Gson or anything else, and then always use that class as a base class for your authenticated requestsMozarab
Yeah, but it if I want to get some JSON data, and later some xml data, I would have to replicate the logic, or create a base class, that has the headers code, and then I would have to create 2 subclasses, and I wouldn't be able to use the default JsonRequest, etc... To me, it looks like response and requests should be in different classes (parsing should belong to the Listener) so that you could mixed them up. Inheritance issues! ;) Thanks for the reply anyway.Bacchius
Hi again, I'm trying to do this manually, so when curling my url, authorization works with something like -H "Authorization: Basic <KEY>" (<KEY> being Base 64 encoded versino of user:passw). However, if I return a map containing a key "Authorization" and a value for that key "Basic <KEY>", volley still returns an error. Is there a specific format I need to follow? Thank you!Bacchius
I found this github.com/njzk2/VolleyTwitter/blob/master/src/com/njzk2/…Mozarab
Awesome, I found the same link a while ago and it is working like a charm! Thanks!Bacchius
Why bother responding if you're lazy? :)Uella
H
0

For a proxy authorization (like squid) use this header :

String credentials = proxyUsername + ":" + proxyPassword;
String auth = "Basic "  + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);                
headers.put("Proxy-Authorization", auth);
Hillaryhillbilly answered 15/2, 2017 at 10:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.