I\'m using the OkHttp library for a new project and am impressed with its ease of use. I now have a need to use Basic Authentication. Unfortunately, there is a dearth of w
All answers are good but no one said, that for some requests content-type is required, you should add a content-type to your request like this:
Request request = new Request.Builder()
.url(url)
.addHeader("content-type", "application/json")
.post(body)
.build();
If you don't add it, you will get Unauthorized message and you will waste a lot of time to fix it.
As pointed out by @agamov:
The aforementioned solution has one drawback: httpClient adds authorization headers only after receiving 401 response
@agamov proposed then to "manually" add authentication headers to each request, but there is a better solution: use an Interceptor:
import java.io.IOException;
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class BasicAuthInterceptor implements Interceptor {
private String credentials;
public BasicAuthInterceptor(String user, String password) {
this.credentials = Credentials.basic(user, password);
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request authenticatedRequest = request.newBuilder()
.header("Authorization", credentials).build();
return chain.proceed(authenticatedRequest);
}
}
Then, simply add the interceptor to an OkHttp client that you will be using to make all your authenticated requests:
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new BasicAuthInterceptor(username, password))
.build();
Someone asked for a Kotlin version of the interceptor. Here is what I came up with and it works great:
val client = OkHttpClient().newBuilder().addInterceptor { chain ->
val originalRequest = chain.request()
val builder = originalRequest.newBuilder()
.header("Authorization", Credentials.basic("ausername", "apassword"))
val newRequest = builder.build()
chain.proceed(newRequest)
}.build()
The aforementioned solution has one drawback: httpClient adds authorization headers only after receiving 401 response. Here's how my communication with api-server looked like:
If you need to use basic-auth for every request, better add your auth-headers to each request or use a wrapper method like this:
private Request addBasicAuthHeaders(Request request) {
final String login = "your_login";
final String password = "p@s$w0rd";
String credential = Credentials.basic(login, password);
return request.newBuilder().header("Authorization", credential).build();
}
Here's the updated code:
client.setAuthenticator(new Authenticator() {
@Override
public Request authenticate(Proxy proxy, Response response) throws IOException {
String credential = Credentials.basic("scott", "tiger");
return response.request().newBuilder().header("Authorization", credential).build();
}
@Override
public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
return null;
}
})
In my case it only worked when I integrated authorization into the header (OkHttp Version 4.0.1):
Request request = new Request.Builder()
.url("www.url.com/api")
.addHeader("Authorization", Credentials.basic("username", "password"))
.build();
Request response = client.newCall(request).execute();