I am trying to add basic authentication (username and password) to a Retrofit OkHttp client. This is the code I have so far:
private static Retrofit createMMSATService(String baseUrl, String user, String pass) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
I am using Retrofit 2.2 and this tutorial suggests using AuthenticationInterceptor
, but this class is not available.
Where is the correct place to add the credentials? Do I have to add them to my interceptor, client or Retrofit object? And how do I do that?
Find the Solution
1.Write a Interceptor class
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);
}
}
2.Finally, add the interceptor to an OkHttp client
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new BasicAuthInterceptor(username, password))
.build();
Retrofit 2
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
private static Retrofit retrofit = builder.build();
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null, null);
}
public static <S> S createService(
Class<S> serviceClass, String username, String password) {
if (!TextUtils.isEmpty(username)
&& !TextUtils.isEmpty(password)) {
String authToken = Credentials.basic(username, password);
return createService(serviceClass, authToken);
}
return createService(serviceClass, null);
}
public static <S> S createService(
Class<S> serviceClass, final String authToken) {
if (!TextUtils.isEmpty(authToken)) {
AuthenticationInterceptor interceptor =
new AuthenticationInterceptor(authToken);
if (!httpClient.interceptors().contains(interceptor)) {
httpClient.addInterceptor(interceptor);
builder.client(httpClient.build());
retrofit = builder.build();
}
}
return retrofit.create(serviceClass);
}
}
Retrofit 1.9
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
private static RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(API_BASE_URL)
.setClient(new OkClient(new OkHttpClient()));
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null, null);
}
public static <S> S createService(Class<S> serviceClass, String username, String password) {
if (username != null && password != null) {
// concatenate username and password with colon for authentication
String credentials = username + ":" + password;
// create Base64 encodet string
final String basic =
"Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
builder.setRequestInterceptor(new RequestInterceptor() {
@Override
public void intercept(RequestFacade request) {
request.addHeader("Authorization", basic);
request.addHeader("Accept", "application/json");
}
});
}
RestAdapter adapter = builder.build();
return adapter.create(serviceClass);
}
}
AuthenticationInterceptor.java
public class AuthenticationInterceptor implements Interceptor {
private String authToken;
public AuthenticationInterceptor(String token) {
this.authToken = token;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder builder = original.newBuilder()
.header("Authorization", authToken);
Request request = builder.build();
return chain.proceed(request);
}
}
Usage
Retrofit 2
Interface
public interface LoginService {
@POST("/login")
Call<User> basicLogin();
}
Requester
LoginService loginService =
ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
Call<User> call = loginService.basicLogin();
call.enqueue(new Callback<User >() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
// user object available
} else {
// error response, no access to resource?
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
// something went completely south (like no internet connection)
Log.d("Error", t.getMessage());
}
}
Retrofit 1.9
Interface
public interface LoginService {
@POST("/login")
void basicLogin(Callback<User> cb);
}
Requester
LoginService loginService =
ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
loginService.basicLogin(new Callback<User>() {
@Override
public void success(User user, Response response) {
// user object available
}
@Override
public void failure(RetrofitError error) {
// handle errors, too
}
});
More information see here.
add header interceptor
public class HeaderInterceptor implements Interceptor {
private PreferencesRepository mPrefs;
private String mAuth;
public HeaderInterceptor(PreferencesRepository p) {
mPrefs = p;
}
@Override
public Response intercept(Chain chain) throws IOException {
mAuth = (mPrefs.getAuthToken() != null)?mPrefs.getAuthToken():"";
Request r = chain.request()
.newBuilder()
.addHeader("Accept", "application/json")
// authorization token here
.addHeader("Authorization", "Bearer" + mAuth)
.build();
return chain.proceed(r);
}
}
add cacheinterceptor (optional)
public class CacheInterceptor implements Interceptor {
Context mContext;
public CacheInterceptor(Context context) {
this.mContext = context;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (request.method().equals("GET")) {
if (DeviceUtils.isConnected(mContext)) {
request = request.newBuilder()
.header(Constant.CACHE_CONTROL, "only-if-cached")
.build();
} else {
request = request.newBuilder()
.header(Constant.CACHE_CONTROL, "public, max-stale=2419200")
.build();
}
}
Response originalResponse = chain.proceed(request);
return originalResponse.newBuilder()
.header(Constant.CACHE_CONTROL, "max-age=600")
.build();
}
}
implement it
HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
logger.setLevel(HttpLoggingInterceptor.Level.BODY);
long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(new File(mContext.getCacheDir(), "http"), SIZE_OF_CACHE);
new OkHttpClient.Builder()
.addInterceptor(logger)
.addInterceptor(new HeaderInterceptor(u))
.cache(cache)
.addNetworkInterceptor(new CacheInterceptor(mContext))
.connectTimeout(Constant.CONNECTTIMEOUT, TimeUnit.SECONDS)
.readTimeout(Constant.READTIMEOUT, TimeUnit.SECONDS)
.writeTimeout(Constant.WRITETIMEOUT, TimeUnit.SECONDS)
.build();