0

I want to use Bearer header in Retrofit with Dagger Hilt. But I don't know How. I found a solution in Stackoverflow but I couldn't solve my problem with that:

how to add Authorization token to retrofit header using hilt

Retrofit2 Authorization - Global Interceptor for access token

These are my code:

Dependency Module:

@Provides
@Singleton
fun provideOkHttpClient(token:String) = OkHttpClient.Builder()
    .addInterceptor(Interceptor(){
        var newRequest = it.request().newBuilder()
            .addHeader("Authorization","Bearer $token")
            .build()
        it.proceed(newRequest)
    })

@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient):ApiService = Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create())
    .baseUrl(BASE_URL)
    .client(okHttpClient)
    .build()
    .create(ApiService::class.java)

And in the next class I get token and call the method of viewmodel

@AndroidEntryPoint
class VerifyCodeFragment:Fragment() {

private val verifyViewModel:VerifyCodeViewModel by viewModels()

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val binding:FragmentVerifyCodeBinding = DataBindingUtil.inflate(inflater,R.layout.fragment_verify_code,
        container, false)

    val mobile = requireArguments().getString("mobile","0")
    val nationalCode = requireArguments().getString("national_code","-1")
    val token = requireArguments().getString("token","-2")
    var verifyCode = 0
    verifyViewModel.getVerifyCode(mobile, token)
    verifyViewModel.code.observe(viewLifecycleOwner){
        if(it.data != null){
            verifyCode = it.data.data
            verifyViewModel.sendVerifyCode(mobile,verifyCode,token)
        }

    }

    verifyViewModel.res.observe(viewLifecycleOwner){
        when(it.status){
            Status.SUCCESS ->{
                val token:String = it.data?.data?.access_token!!
                Toast.makeText(requireContext(),token,Toast.LENGTH_SHORT).show()
            }
            Status.ERROR -> {
                Toast.makeText(requireContext(),it.message,Toast.LENGTH_SHORT).show()
            }
            Status.LOADING -> {

            }
        }
    }

    Toast.makeText(requireContext(),"$mobile $nationalCode",Toast.LENGTH_SHORT).show()
    Toast.makeText(requireContext(),token,Toast.LENGTH_SHORT).show()

    return binding.root
}


}

And this is my viewmodel

@HiltViewModel
class VerifyCodeViewModel @Inject constructor(
    private val repository: MainRepository

):ViewModel() {
    private val _res = MutableLiveData<Resource<Result>>()
    private val _code = MutableLiveData<Resource<GetCode>>()

    val res:LiveData<Resource<Result>>
get() = _res

val code:LiveData<Resource<GetCode>>
get() = _code

fun getVerifyCode(mobile:String,token:String) = viewModelScope.launch {
    _code.postValue(Resource.loading(null))
    repository.getCode(mobile,token).let {
        if(it.isSuccessful){
            _code.postValue(Resource.success(it.body()))
        }else{
            _code.postValue(Resource.error(it.errorBody().toString(),null))
        }
    }
}

fun sendVerifyCode(mobile:String,code:Int,token:String) = viewModelScope.launch {
    _res.postValue(Resource.loading(null))
    repository.getToken(mobile,code,token).let {
        if(it.isSuccessful){
            _res.postValue(Resource.success(it.body()))
        }else{
            _res.postValue(Resource.error(it.errorBody().toString(),null))
        }
    }
}
}

If it's right and Ok, so my question is: How can I pass token to the method?

  • You can store the token in shared preferences and you have to create instance of preferences in AppModule and then use it as prefs.getToken() – Dev007 Nov 24 '22 at 05:27
  • @Dev007 Ok, but How? Can you write the code? If it's possible please use data set instead of shared preferences. Thanks – Hooman Hooshyar Nov 24 '22 at 05:32

1 Answers1

1

You have to write the token into the SharedPrefrence where you get that from the server, and read the token from SharedPrefrece in your interceptor

@Module
@InstallIn(SingletonComponent::class)
class SharedPreferencesModule {

    @Singleton
    @Provides
    fun provideSharedPreference(@ApplicationContext context: Context): SharedPreferences {
        return context.getSharedPreferences(context.packageName + "_preferences", Context.MODE_PRIVATE)
    }
}

In your ViewModel

@HiltViewModel
class VerifyCodeViewModel @Inject constructor(
    private val repository: MainRepository
    private val sharedPrefrence: SharedPreferences
):ViewModel()

In your method where get the token from the server in the ViewModel. class:

with (sharedPrefrence.edit()) {
   putString("token", your_token_which_get_from_server)
   apply()
}

And finally in your DependencyModule:

@Provides
@Singleton
fun provideOkHttpClient(sharedPrefrence: SharedPreferences) = OkHttpClient.Builder()
    .addInterceptor(Interceptor(){
        val token = sharedPrefrence.getString("token", "")

        var newRequest = it.request().newBuilder()
            .addHeader("Authorization","Bearer $token")
            .build()

     it.proceed(newRequest)
})

NOTE:

  • NEVER use SharedPreferences for sensitive data like tokens, passwords etc!
  • You can cache the token in a String field instead of reading in every request, But don't forget to delete it when you get the new key.
Abolfazl Abbasi
  • 309
  • 2
  • 12