Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Basic Authentication with Retrofit

I am trying to build a client for a REST API using Retrofit. The API uses basic auth and I have been unable to authenticate using Retrofit.

I tested the API using the curl below and it works as expected

curl  -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{some_json}' -u api_key: https://apitest.com/api/v1/customers

Below is the Retrofit client

public interface UserService {

String HOST = "https://apitest.com";

public static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
public static Retrofit.Builder builder =
        new Retrofit.Builder()
                .baseUrl(HOST)
                .addConverterFactory(GsonConverterFactory.create());
/*
 * CREATE/UPDATE User
 */
@POST("api/v1/customers")
Call<UserAPIResponse> userUpdate(@Body UserUpdateRequest userUpdateRequest);



static UserService newInstance(String userAPIKey) {
    String credentials = userAPIKey + ":";

    final String basic = "Basic "+ Base64.encodeBase64(credentials.getBytes());

    httpClient.addInterceptor(new Interceptor() {
        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            Request original = chain.request();

            Request.Builder requestBuilder = original.newBuilder()
                    .header("Authorization", basic);
            requestBuilder.header("Accept", "application/json");
            requestBuilder.method(original.method(),original.body());


            Request request = requestBuilder.build();
            return chain.proceed(request);
        }
    });

OkHttpClient client = httpClient.build();
Retrofit retrofit = builder.client(client).build();

return retrofit.create(BlueshiftUserService.class);
}

When I call updateUser on the UserService

Response<UserAPIResponse> response = UserService.userUpdate(userUpdateRequest).execute();

The response.code is 401 (unauthorized/authentication failed)

The curl command with -u and the same credentials works as expected.

like image 701
nipunb Avatar asked Jun 15 '16 08:06

nipunb


2 Answers

The issue was with the credentials encoding. I wasnt sending it as string.

byte[] encodedAuth= Base64.encodeBase64(credentials.getBytes());
final String basic = "Basic " + new String(encodedAuth);
like image 82
nipunb Avatar answered Sep 22 '22 15:09

nipunb


use these libraries in Gradle file

compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.squareup.okhttp:okhttp:2.3.0'
compile 'com.cookpad.android.rxt4a:rxt4a:0.9.0'
compile 'io.reactivex:rxjava:1.0.12'

and put this classes in your project

 public class ServiceGenerator { 
  private static final String TAG = erviceGenerator.class.getSimpleName();
  public static final int READ_TIMEOUT = 10000;
  public static final int CONNECT_TIMEOUT = 100000;   
     // No need to instantiate this class. 
  private ServiceGenerator(){}   
     public static <S> S createService(Class<S> serviceClass, String
   endpoint) {
       // Call basic auth generator method without user and pass
       return createService(serviceClass, endpoint, null, null);   }

     public static <S> S createService(Class<S> serviceClass, String
   endpoint, String username, String password) {
       OkHttpClient okHttpClient = new OkHttpClient();
       okHttpClient.setReadTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
       okHttpClient.setConnectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);

       // Set endpoint url and use OkHTTP as HTTP client
       RestAdapter.Builder builder = new RestAdapter.Builder()
           .setEndpoint(endpoint)
           .setConverter(new GsonConverter(new Gson()))
           .setClient(new OkClient(okHttpClient));

       if (username != null && password != null) {
         // Concatenate username and password with colon for authentication
         final String credentials = username + ":" + password;

         builder.setRequestInterceptor(new RequestInterceptor() {
           @Override
           public void intercept(RequestFacade request) {
             // Create Base64 encoded string
             String string = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
             request.addHeader("Authorization", string);
             request.addHeader("Accept", "application/json");
           }
         });
       }

       RestAdapter adapter = builder.build();

       return adapter.create(serviceClass);   } }

and this interface

public class TodolyClient {

  private static final String TAG = TodolyClient.class.getSimpleName();

  public static final String ENDPOINT = "your base URL";

  public interface TodolyService {

    @GET("/wp-json/wc/v2/products")(your remaining url)
    Observable<Object> isAuthenticated();


  }
}

and call the below method in your main activity

private void createProject() {
 final TodolyClient.TodolyService service =ServiceGenerator.createService(
                TodolyClient.TodolyService.class, TodolyClient.ENDPOINT, "your user name",
                "your password");

        Observable<Object> observable = service.isAuthenticated();
         AndroidCompositeSubscription compositeSubscription = new AndroidCompositeSubscription();
        observable
                .lift(new OperatorAddToCompositeSubscription<Object>(compositeSubscription))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Object>() {

                    @Override
                    public void onNext(Object project) {
                        android.util.Log.d(TAG, "onNext: "+project.toString());
                    }

                    @Override
                    public void onCompleted() {
                        android.util.Log.d(TAG, "onNext:commm " );
                    }

                    @Override
                    public void onError(Throwable e) {
                        android.util.Log.d(TAG, "onNext: eeeeeeeee"+e.getMessage());

                    }
                });
    }
like image 41
Gujjula Ramesh Reddy Avatar answered Sep 22 '22 15:09

Gujjula Ramesh Reddy