Add Header to Retrofit Requests - java

I have a token which i save to sharedPreferences and then i get that token and pass it as an authorization to a Retrofit requests. This is my codes below which i used to add a header to my retrofit requests.
I need to add the header below:
"Authorization" "Bearer" + token
public static Retrofit getClient(String token) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okClient = new OkHttpClient();
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
okClient.interceptors().add(chain -> {
Response response = chain.proceed(chain.request());
return response;
});
okClient.interceptors().add(chain -> {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", token)
.method(original.method(), original.body())
.build();
return chain.proceed(request);
});
okClient.interceptors().add(logging);
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(Config.BASE_URL1)
.client(okClient)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
This how i send my token to the retrofit client
Retrofit retrofit = RetrofitClient.getClient("Bearer" + " " + authUser.getToken());
APIService mAPIService = retrofit.create(APIService.class);
But unfortunately the server responds with the message no authorization

You can send header to server without using an interceptor. Just add a field in your method declaration in your service interface like this:
#GET("my/orders/{id}")
Call<Order> getOrder(#Header("Authorization") String token,
#Path("id") int order_id);
Then create a Call object to send request as below:
APIService apiService= retrofit.create(APIService.class);
Call<Order> call = apiService.getOrder(token, id);
call.enqueue(/*callback*/);

Add a method in the BaseCaller Class for your headers like below:
public HashMap<String, String> getHeaders() {
HashMap<String, String> headerHashMap = new HashMap<>();
headerHashMap.put("Content-Type", "application/x-www-form-urlencoded");
headerHashMap.put("time_zone_name", DateTimeHelper.getTimeZoneName());
headerHashMap.put("gmt_offset", DateTimeHelper.getGMTOffset());
return headerHashMap;
}
Now create a method in your service class for url like :
#FormUrlEncoded
#POST("switch_user")
Call<JsonObject> switchUser(#HeaderMap Map<String, String> headers, #FieldMap Map<String, String> fields);
Finally in your class caller class call the methods as follows :
call = loginService.switchUser(getHeaders(), apiParams.mHashMap);
This will do the needful :)

Try this for same:
String credentials = "put your token here";
final String basic = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization",basic);

Related

Retrofit2 FromUrlEncoded not handling Japanese characters

When sending POST requests to an API endpoint using #FormUrlEncoded from RetroFit2, the record looked scrambled when it was Japanese but ok when English.
The charset was set to null when using to send POST request.
Content-Type:application/x-www-form-urlencoded was the header instead of Content-Type:application/x-www-form-urlencoded; charset=utf-8
#FormUrlEncoded
#POST("/api/items")
Call<ApiResponse> post(#FieldMap Map<String, Object> fields);
2 Solutions:
add the headers manually for each endpoint, not very scaleable solution
#FormUrlEncoded
#POST("/api/items")
#Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
Call<ApiResponse> post(#FieldMap Map<String, Object> fields);
add an interceptor to add it for endpoints having POST, a bit more verbose:
#Bean
public ApiService apiService(final ObjectMapper objectMapper) {
final OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(chain -> {
final Request original = chain.request();
if (original.method().equals("POST")) {
final Buffer buffer = new Buffer();
original.body().writeTo(buffer);
final String content = buffer.readString(StandardCharsets.UTF_8);
final RequestBody body = RequestBody.create(MediaType.parse(""application/x-www-form-urlencoded"), content);
final Request request = original.newBuilder().method(original.method(), body).build();
return chain.proceed(request);
} else {
return chain.proceed(original);
}
}).build();
final Retrofit retrofit = new Retrofit.Builder()
.client(httpClient)
.baseUrl(apiBaseUrl)
.build();
return retrofit.create(ApiService.class);
}

Retrofit unable to set new Token to Header of Requests

I have a retrofit Client that helps me set a header for any requests i make to my REST APIs. On user login i get the token from the server and set this token to the header of the requests. I save this token to SharedPreferences so that i can get it anytime i need to make requests to my REST APIs. The problem is that anytime i set a new token to my SharedPreferences file when a new user signs in, it still gets the old token instead of saving this new token to use for future requests.
This is my Retrofit Client below:
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String token) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okClient = new OkHttpClient();
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
okClient.interceptors().add(chain -> chain.proceed(chain.request()));
okClient.interceptors().add(chain -> {
Request original = chain.request();
Request request = original.newBuilder()
.header(Config.X_AUTH_TOKEN, "Bearer" + " " + token)
.method(original.method(), original.body())
.build();
Log.d("Authorization", token);
return chain.proceed(request);
});
okClient.interceptors().add(logging);
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(Config.BASE_URL1)
.client(okClient)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
}
this is my codes for setting and getting the token
public String getToken() {
return prefs.getString(AuthUser.USER_TOKEN, "");
}
public void setToken(String token) {
SharedPreferences.Editor editor = prefs.edit();
editor.putString(AuthUser.USER_TOKEN, token);
editor.apply();
}
this is where i call my set token method to save the new token to SharedPreference
authUser.setToken(token);
I completely don't see how this is surprising. Your RetrofitClient is a confusingly (and arguably badly written) singleton. Let's go through a typical situation where this will fail.
You launch your app with a previously saved token. At first everything works fine. At some point you call RetrofitClient.getClient(token) and all requests succeed. After some time the server invalidates the token. You probably get a 403 response from your server, lauch the login screen again and update your token in your SharedPreferences. Here is where your problems begin. Although you saved your new token correctly, your RetrofitClient will do what singletons do and continue to return the first instantiation of itself stored in the private static Retrofit retrofit filed.
A quick workaround would be to add an invalidate method to your RetrofitClient. Something like.
public static void invalidate() {
this.retrofit = null;
}
Call it when you get your 403 response, or when you logout.
PS: Please move the following line if (retrofit==null) { at the beginning of your getClient method. Creating a new okHttp client, for nothing, every time someone calls getClient is just wasteful.
You can write intercepter to execute each time before network request happen.Create new file as HeaderIntercepter
public class HeaderIntercepter implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String token = context.getSharedPreferences(FILENAME, MODE_PRIVATE).getString("TOKEN","");
Request tokenRequest = request.newBuilder()
.addHeader("Authorization", "Bearer " + token)
.addHeader("Content-Type", "application/json")
.build();
return chain
.proceed(tokenRequest);
}
}
Add intercepter to okHttpclient
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.addInterceptor(new HeaderIntercepter());

Basic authorization in retrofit

Interface:
#GET("burrowedbooks/")
Call<JsonArray> getCategoryList(#Header("Authorization") String token);
Usage:
private LibraryAPi service;
Retrofit retrofit = new Retrofit.Builder()
//.client(client)
.baseUrl(String.valueOf(R.string.base_url))
.addConverterFactory(GsonConverterFactory.create())
.build();
service = retrofit.create(LibraryAPi.class);
// Extract token from Shared Preferences.
SharedPreferences prefs = getActivity().getSharedPreferences(getString(R.string.login_data), MODE_PRIVATE);
String token = "Bearer "+prefs.getString("token","");
Call<JsonArray> categoryListResponseCall = service.getCategoryList(token);
categoryListResponseCall.enqueue(new Callback<JsonArray>() {
#Override
public void onResponse(Call<JsonArray> call, Response<JsonArray> response) {
int statusCode = response.code();
Toast.makeText(getContext(), ""+statusCode, Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<JsonArray> call, Throwable t) {
}
});
I'm trying to send authentication token stored in shared preferences. The code above is not working. It returns 403 forbidden status code. What is the correct way to send authentication header?
You are wrong at .baseUrl(String.valueOf(R.string.base_url))
You should get string from resource using .baseUrl(getActivity().getString(R.string.base_url))
But your code will not send data to the server and onFailure would be called.
If you get the string properly and still are getting 403, you may want to verify your back end implementation using postman.
Also you can create a custom interceptor to add your header automatically on new requests.
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", token)
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
}
OkHttpClient client = httpClient.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
Also, check if token is received good from SharedPreferences. Looks odd how you read it.

Retrofit add header with token and id

I have a problem with getting authenticated user. Before it I got token and user id. Now i need to get user from server using access token and id.
I have header format
Now I'am trying to add header with user token and id using interceptor.
My code:
Interceptor interceptor = new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Accept", "application/json")
.addHeader("authorization", token) <-??
.addHeader("driver_id", id) <-??
.build();
return chain.proceed(newRequest);
}
};
OkHttpClient.Builder okHttpBuilder = new OkHttpClient.Builder();
okHttpBuilder.addInterceptor(interceptor);
OkHttpClient okHttpClient = okHttpBuilder.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
Interface:
#GET("driver/v1/driver")
Call<Driver> getAuthorizedDriver();
Different variants throws 401 error, don't know what to do
Log:
I/Response code: 401
I/Response message: Unauthorized`
I got it.
It's must look like:
#GET("driver/v1/driver")
Call<Driver> getAuthorizedDriver(#Header("authorization") String auth);
And auth:
Call<Driver> call = apiInterface.getAuthorizedDriver("Token token=" + token + ", driver_id=" + id);
Try to pass the header values via the method call:
#GET("driver/v1/driver")
Call<Driver> getAuthorizedDriver(#Header("authorization") String token,
#Header("driver_id") Integer id);
You also wouldn't have to deal with this huge chunk of Interceptor code

How to define a Header to all request using Retrofit?

I'm looking for a solution to define a unique Header to use in all requests. Today I use #Header to each request did pass like parameter but I want define only header that works in all requests without to need pass like a parameter, for example fixing this Header on my requests #GET and #POST
Today I use this. Note that each request #GET I need define Header as parameter.
//interface
#GET("/json.php")
void getUsuarioLogin(
#Header("Authorization") String token,
#QueryMap Map<String, String> params,
Callback<JsonElement> response
);
//interface
#GET("/json.php")
void addUsuario(
#Header("Authorization") String token,
#QueryMap Map<String, String> params,
Callback<JsonElement> response
);
//using
public void getUsuarioLogin(){
Map<String, String> params = new HashMap<String, String>();
params.put("email", "me#mydomain.com");
params.put("senha", ConvertStringToMD5.getMD5("mypassword"));
RestAdapter adapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(WebServiceURL.getBaseWebServiceURL())
.build();
UsuarioListener listener = adapter.create(UsuarioListener.class);
listener.getUsuarioLogin(
//header
"Basic " + BasicAuthenticationRest.getBasicAuthentication(),
params,
new Callback<JsonElement>() {
#Override
public void success(JsonElement arg0, Response arg1) {
Log.i("Usuario:", arg0.toString() + "");
}
#Override
public void failure(RetrofitError arg0) {
Log.e("ERROR:", arg0.getLocalizedMessage());
}
});
}
//using
public void addUsuario(){
Map<String, String> params = new HashMap<String, String>();
params.put("name", "Fernando");
params.put("lastName", "Paiva");
RestAdapter adapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(WebServiceURL.getBaseWebServiceURL())
.build();
UsuarioListener listener = adapter.create(UsuarioListener.class);
listener.addUsuario(
//header
"Basic " + BasicAuthenticationRest.getBasicAuthentication(),
params,
new Callback<JsonElement>() {
#Override
public void success(JsonElement arg0, Response arg1) {
Log.i("Usuario:", arg0.toString() + "");
}
#Override
public void failure(RetrofitError arg0) {
Log.e("ERROR:", arg0.getLocalizedMessage());
}
});
}
Official document:
Headers that need to be added to every request can be specified using a RequestInterceptor. The following code creates a RequestInterceptor that will add a User-Agent header to every request.
RequestInterceptor requestInterceptor = new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("User-Agent", "Retrofit-Sample-App");
}
};
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.setRequestInterceptor(requestInterceptor)
.build();
In Retrofit 2, you need to intercept the request on the network layer provided by OkHttp
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("User-Agent", "Your-App-Name")
.header("Accept", "application/vnd.yourapi.v1.full+json")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
}
OkHttpClient client = httpClient.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
Check this, it explains the differences very well.
Depending on your OkHttp lib:
OkHttpClient httpClient = new OkHttpClient();
httpClient.networkInterceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder().addHeader("User-Agent", System.getProperty("http.agent")).build();
return chain.proceed(request);
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient)
.build();
As the other answers have described, you need a RequestInterceptor. Luckily, this interface has a single method, so Java 8 and above will treat it as a functional interface and let you implement it with a lambda. Simple!
For example, if you're wrapping a specific API and need a header for each endpoint, you might do this when you build your adapter:
RestAdapter whatever = new RestAdapter.Builder().setEndpoint(endpoint)
.setRequestInterceptor(r -> r.addHeader("X-Special-Vendor-Header", "2.0.0"))
.build()
Here's the solution for adding header using retrofit 2.1. We need to add interceptor
public OkHttpClient getHeader(final String authorizationValue ) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.addNetworkInterceptor(
new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = null;
if (authorizationValue != null) {
Log.d("--Authorization-- ", authorizationValue);
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.addHeader("Authorization", authorizationValue);
request = requestBuilder.build();
}
return chain.proceed(request);
}
})
.build();
return okClient;
}
Now in your retrofit object add this header in the client
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.client(getHeader(authorizationValue))
.addConverterFactory(GsonConverterFactory.create())
.build();

Categories