120

I'm trying to use Retrofit2, I want to add Token to my Header Like this:

Authorization: Bearer Token but the code below doesn't work:

public interface APIService {
    @Headers({"Authorization", "Bearer "+ token})
    @GET("api/Profiles/GetProfile?id={id}")
    Call<UserProfile> getUser(@Path("id") String id);
}

My server is asp.net webApi. Please help what should I do?

Nicola Gallazzi
  • 7,897
  • 6
  • 45
  • 64
farshad
  • 1,339
  • 2
  • 9
  • 14
  • This way of adding a header only works when 'token' is a compile time constant. Java's annotation rules and such. The documetation gives you another way to include a header though: http://square.github.io/retrofit/ (make it a method paramenter) – zapl Dec 10 '16 at 19:10

6 Answers6

211

You have two choices -- you can add it as a parameter to your call --

@GET("api/Profiles/GetProfile?id={id}")
Call<UserProfile> getUser(@Path("id") String id, @Header("Authorization") String authHeader);

This can be a bit annoying because you will have to pass in the "Bearer" + token on each call. This is suitable if you don't have very many calls that require the token.

If you want to add the header to all requests, you can use an okhttp interceptor --

OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
      @Override
      public Response intercept(Chain chain) throws IOException {
        Request newRequest  = chain.request().newBuilder()
            .addHeader("Authorization", "Bearer " + token)
            .build();
        return chain.proceed(newRequest);
      }
    }).build();

Retrofit retrofit = new Retrofit.Builder()
    .client(client)
    .baseUrl(/** your url **/)
    .addConverterFactory(GsonConverterFactory.create())
    .build();
iagreen
  • 31,470
  • 8
  • 76
  • 90
  • 1
    For me I didn't realise until I had implemented it but the token is only known at runtime - therefore I think this is a better solution: https://stackoverflow.com/questions/43051558/dagger-retrofit-adding-auth-headers-at-runtime/43083639#43083639 – Daniel Wilson Nov 23 '17 at 08:55
  • Thanks its working for bearer token, but how to add FieldMap with dyanamic header. I have tried with FieldMap, but Its not working. Pls help. – Dildarkhan Pathan Nov 28 '19 at 16:03
  • 1
    fist case: "Bearer" + token. "Bearer " + token. Need empty space – cristianego Nov 03 '20 at 23:26
  • The problem with the second. Method is if you use Dependency Injector library. You have to login user, get the token before you instantiate Okhttp for ur calls – Declan Nnadozie Dec 29 '20 at 18:16
  • The best approach is to use the new Authenticator API, https://stackoverflow.com/a/31624433/5093308 – Zhou Hongbo Feb 10 '22 at 02:57
40

If you want to add Bearer Token as a Header you can do those types of process.

This is one way to work with Bearer Token

In your Interface

@Headers({ "Content-Type: application/json;charset=UTF-8"})
@GET("api/Profiles/GetProfile")
Call<UserProfile> getUser(@Query("id") String id, @Header("Authorization") String auth);

After that you will call the Retrofit object in this way

Retrofit retrofit  = new Retrofit.Builder()
                    .baseUrl("your Base URL")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();

APIService client = retrofit.create(APIService.class);
Call<UserProfile> calltargetResponse = client.getUser("0034", "Bearer "+token);
calltargetResponse.enqueue(new Callback<UserProfile>() {
       @Override
       public void onResponse(Call<UserProfile> call, retrofit2.Response<UserProfile> response) {
           UserProfile UserResponse = response.body();
           Toast.makeText(this, " "+response.body(), Toast.LENGTH_SHORT).show();
                }
        @Override
        public void onFailure(Call<UserProfile> call, Throwable t) {
            //Toast.makeText(this, "Failed ", Toast.LENGTH_SHORT).show();
        }
});

Another Way is using intercept, which is similar the previous Answer. But, that time you just need to modify interface little bit like.

@Headers({ "Content-Type: application/json;charset=UTF-8"})
@GET("api/Profiles/GetProfile")
Call<UserProfile> getUser(@Query("id") String id); 

Hope this will work for you.

Morgan Koh
  • 2,297
  • 24
  • 24
Hamza Rahman
  • 664
  • 7
  • 19
18

Based on @iagreen solution kotlin version with different classes and structure suggested by @Daniel Wilson

Make Retrofit instance like this

object RetrofitClientInstance {
   private var retrofit: Retrofit? = null
   private val BASE_URL = "http://yoururl"


    val retrofitInstance: Retrofit?
        get() {
            if (retrofit == null) {
                var client = OkHttpClient.Builder()
                      .addInterceptor(ServiceInterceptor())
                      //.readTimeout(45,TimeUnit.SECONDS)
                      //.writeTimeout(45,TimeUnit.SECONDS)
                        .build()

                retrofit = Retrofit.Builder()
                        .baseUrl(BASE_URL)
                        .client(client)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build()

            }
            return retrofit
      }

}

Add ServiceInterceptor class like below

class ServiceInterceptor : Interceptor{

  var token : String = "";

  fun Token(token: String ) {
     this.token = token;
  }

  override fun intercept(chain: Interceptor.Chain): Response {
    var request = chain.request()

    if(request.header("No-Authentication")==null){
        //val token = getTokenFromSharedPreference();
        //or use Token Function
        if(!token.isNullOrEmpty())
        {
            val finalToken =  "Bearer "+token
            request = request.newBuilder()
                    .addHeader("Authorization",finalToken)
                    .build()
        }

    }

    return chain.proceed(request)
  }

}

Login Interface and data class implementation

interface Login {
  @POST("Login")
  @Headers("No-Authentication: true")
  fun login(@Body value: LoginModel): Call<LoginResponseModel>



  @POST("refreshToken")
  fun refreshToken(refreshToken: String): 
      Call<APIResponse<LoginResponseModel>>
}

data class LoginModel(val Email:String,val Password:String)
data class LoginResponseModel (val token:String,val 
         refreshToken:String)

call this in any activity like this

val service = RetrofitClientInstance.retrofitInstance?.create(Login::class.java)
val refreshToken = "yourRefreshToken"
val call = service?.refreshToken(refreshToken)
        call?.enqueue(object: Callback<LoginResponseModel>{
            override fun onFailure(call: Call<LoginResponseModel>, t: Throwable) {
                print("throw Message"+t.message)
                Toast.makeText(applicationContext,"Error reading JSON",Toast.LENGTH_LONG).show()
            }

            override fun onResponse(call: Call<LoginResponseModel>, response: Response<LoginResponseModel>) {
                val body = response?.body()
                if(body!=null){
                    //do your work
                }
            }

        })

for detail this video will be helpful.

Faraz Ahmed
  • 1,467
  • 2
  • 18
  • 33
13

This adds your token to the builder and you can change it at any time in case of login/logout.

object ApiService {
    var YOUR_TOKEN = ""

    private var retrofit: Retrofit = Retrofit.Builder()
        .baseUrl("YOUR_URL")
        .addConverterFactory(GsonConverterFactory.create())
        .client(OkHttpClient.Builder().addInterceptor { chain ->
            val request = chain.request().newBuilder().addHeader("Authorization", "Bearer ${YOUR_TOKEN}").build()
            chain.proceed(request)
        }.build())
        .build()

    var service: AppAPI = retrofit.create(AppAPI::class.java)
        private set

}
cibernato
  • 131
  • 1
  • 4
  • Does it mean I have to call Retrofit.Builder() everytime the token changes? I thought I build Retrofit once, then login and after login I use the token until it expires. I don't get it yet. :) – The incredible Jan Aug 31 '20 at 11:23
  • You got it working without rebuilding retrofit every time? – Jasper B Dec 05 '22 at 14:54
6

You will need to add an Interceptor into the OkHttpClient.

Add a class called OAuthInterceptor.

class OAuthInterceptor(private val tokenType: String, private val accessToken: String) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
        var request = chain.request()
        request = request.newBuilder().header("Authorization", "$tokenType $accessToken").build()

        return chain.proceed(request)
    }
}

Following that, when you initialise your RetrofitApiService interface, you will need this.

interface RetrofitApiService {
    companion object {
        private const val BASE_URL = "https://api.coursera.org/api/businesses.v1/"
        fun create(accessToken: String): RetrofitApiService {
            val client = OkHttpClient.Builder()
                    .addInterceptor(OAuthInterceptor("Bearer", accessToken))
                    .build()

            val retrofit = Retrofit.Builder()
                    .addConverterFactory(GsonConverterFactory.create())
                    .baseUrl(BASE_URL)
                    .client(client)
                    .build()

            return retrofit.create(RetrofitApiService::class.java)
        }
    }
}

Shout out to Java Code Monk, and visit the reference link for more details. https://www.javacodemonk.com/retrofit-oauth2-authentication-okhttp-android-3b702350

Morgan Koh
  • 2,297
  • 24
  • 24
4

The best approach is to use the new Authenticator API.

class TokenAuthenticator : Authenticator {
    override fun authenticate(route: Route?, response: Response): Request? {
        if (response.request.header("Authorization") != null) {
            return null
        }
        return response.request.newBuilder().header("Authorization", "Bearer " + token).build()
    }
}
OkHttpClient.Builder().authenticator(TokenAuthenticator()).build()

Reference: https://square.github.io/okhttp/recipes/#handling-authentication-kt-java

Zhou Hongbo
  • 1,297
  • 13
  • 25
  • I see this error "Cannot access 'request': it is package-private in 'Response". how did you overcome that? – CanCoder Feb 16 '23 at 21:16
  • @CanCoder you will need to add okhttp4, implementation("com.squareup.okhttp3:okhttp:4.10.0") https://square.github.io/okhttp/ – mementoGuy Jun 01 '23 at 09:25