OKHTTP Interceptor not working It gives me 401 Response(Unauthenticated/UnAuthorized)
Here is my Interceptor Class
InterceptorClass
class NetworkInterceptor(context: Context) : Interceptor {
private val applicationContext = context.applicationContext
private val sharedPreferenceData = SharedPreferenceData(applicationContext)
override fun intercept(chain: Interceptor.Chain): Response {
if (!isConnectionAvailable()) {
throw NoConnectionException("Error! Connecting to the network")
} else {
val requestBuilder = chain.request().newBuilder()
val token = sharedPreferenceData.getString("token", "")
requestBuilder.addHeader("Authorization", "Bearer $token")
Log.e("Token", "intercept: $token")
return chain.proceed(requestBuilder.build())
}
}
#Suppress("DEPRECATION")
fun isConnectionAvailable(): Boolean {
val cm =
applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
cm.activeNetworkInfo.also {
return it != null && it.isConnected
}
}
}
Here is the network instance class
object NetworkInstance {
fun getApi(context: Context): DataApi {
val gsonBuilder = GsonBuilder()
gsonBuilder.setLenient()
val gson = gsonBuilder.create()
val logging = HttpLoggingInterceptor()
logging.setLevel(HttpLoggingInterceptor.Level.BODY)
val client = OkHttpClient
.Builder()
.addInterceptor(logging)
.addInterceptor(NetworkInterceptor(context))
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.addInterceptor(logging)
.build()
val retrofit = Retrofit
.Builder()
.client(client)
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
return retrofit.create(DataApi::class.java)
}
}
The issue was because of my Stupidity. I have added BASE_URL inside build.gradle which generates a Static Final variable inside BuildCondig.java which can't be altered. While Adding header BASE_URL can't be changed.
Related
I'm having the below Okhttp code:
val client = OkHttpClient()
val mediaType = MediaType.parse("application/x-www-form-urlencoded")
val body = RequestBody.create(mediaType, "tenant_id=xxxx&client_id=xxxx&client_secret=xxxx&resource=xxxx&grant_type=client_credentials")
val request = Request.Builder()
.url("https://sxxx.com/axxx/oauth2/token")
.post(body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build()
val response = client.newCall(request).execute()
And want to convert it usint ktor, so I wrote the below:
class Greeting {
private val httpClient = HttpClient {
}
#Throws(Exception::class)
suspend fun greeting(): String {
val response = httpClient.request {
method = HttpMethod.Post
url {
protocol = URLProtocol.HTTPS
host = "sxxx.com"
path("axxx/oauth2/token")
// encodedParameters
trailingQuery = true
parameters.append("tenant_id", "xxxx")
parameters.append("client_id", "xxxx")
parameters.append("client_secret", "xxxx")
parameters.append("resource", "xxxx")
parameters.append("grant_type", "client_credentials")
}
headers {
append(HttpHeaders.ContentType, "application/x-www-form-urlencoded")
}
}
return response.bodyAsText()
}
}
And calling my new code as:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
val scope = rememberCoroutineScope()
var text by remember {
mutableStateOf("Loading")
}
LaunchedEffect(true){
scope.launch {
text = try {
Greeting().greeting()
} catch (e: Exception) {
e.localizedMessage ?: "error"
}
}
}
Greeting(text)
}
}
}
}
}
#Composable
fun Greeting(text: String) {
Text(text = text)
}
But instead of getting the required token, I'm getting the response: Chain validation failed
Make sure that:
Your server certificate is valid.
Your android system datetime is correct.
Iam trying to serialize a response into Session class with Retrofit and Kotlin but i have an error. I am using inheritance here and maybe that is the problem i don't know :
"java.lang.IllegalArgumentException: Unable to create call adapter for retrofit2.Response<com.mobile.myapplication.Session> "
open class BaseUser {
var id:Int=0
var correo:String=""
var nombre:String=""
var apellido:String=""
var direccion:String=""
var telefono:String=""
var imagen:String=""
}
class Permiso {
var id:Int=0
var aplicacionId:Int=0
var aplicacionName:String=""
var lectura:Boolean=false
var escritura:Boolean=false
}
class Session: BaseUser() {
var token:String=""
var permiso:List<Permiso> = emptyList()
}
class LocalViewModel(private val retro:Retro= Retro()):ViewModel(){
private val _result = MutableStateFlow("")
val result:StateFlow<String> = _result
init {
viewModelScope.launch {
val jsonObject= JSONObject()
jsonObject.put("correo", "xxxxxx.com")
jsonObject.put("password", "xxxxx")
Log.d("payload",jsonObject.toString())
retro.token(jsonObject.toString())
}
}
}
#Composable
fun main(vm: LocalViewModel= viewModel()){
Text(text = "Hello world")
}
interface APIService {
#POST("api/Auth/SignIn")
fun requestToken(#Body requestBody: RequestBody): Response<Session>
}
class Retro{
fun getinstance(): APIService? {
var service:APIService?=null
try {
// Create Retrofit
val retrofit = Retrofit.Builder()
.baseUrl("xxxxxxxxx")
.addConverterFactory(GsonConverterFactory.create())
.build()
// Create Service
service = retrofit.create(APIService::class.java)
}catch (err:Error){
Log.e("RETROFIT_ERROR", err.toString())
}
return service
}
fun token(payload:String){
val instance=getinstance()
val requestBody = payload.toRequestBody("application/json".toMediaTypeOrNull())
val response = instance?.requestToken(requestBody)
Log.d("response",response.toString())
}
}
API response is like this :
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJOb21icmUiOiJSaWNoYXJkIiwiQXBlbGxpZG8iOiJWw61xdWV6IiwiQ29ycmVvIjoiUnZpcXVlekBzb2Zub21pYy5jb20iLCJEaXJlY2Npb24iOiJIZXJlZGlhIiwiVGVsZWZvbm8iOiJQw6lyZXoiLCJuYmYiOjE2NTc3MjQzOTksImV4cCI6MTY1Nzc0OTU5OSwiaXNzIjoiaHR0cHM6Ly9zb2Zub21pY2FwaS5henVyZXdlYnNpdGVzLm5ldC8ifQ.HtBEe1XlqyU0YBVyGJ1fs-EUiJn8vbWKqvNci2tOboU",
"id": 26,
"correo": "xxxxx.com",
"nombre": "xx",
"apellido": "xx",
"direccion": "xxx",
"telefono": "xx",
"imagen": null,
"permiso": []
}
What is the problem ???
I don't know why but with Response does not work only with Call instead Response!:
interface APIService {
#POST("api/Auth/SignIn")
fun requestToken(#Body requestBody: RequestBody): Call<Session>
}
fun token(payload:String):Session?{
val instance=getinstance()
val requestBody = payload.toRequestBody("application/json".toMediaTypeOrNull())
var session: Session?=null
val response = instance?.requestToken(requestBody) ?: return null
response.enqueue(object : Callback<Session?> {
override fun onResponse(call: Call<Session?>?, response: Response<Session?>) {
val statusCode = response.code()
if (statusCode!=200){
return
}
session = response.body()
}
override fun onFailure(call: Call<Session?>?, t: Throwable?) {
return
}
})
return session
}
I want to know how can I access my token stored in Shared Preferences and pass it in the url when required.
RetrofitClient.kt file :
class OAuthInterceptor(private val tokenType: String, private val access_token: String):
Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
request = request.newBuilder().header("Authorization", "$tokenType $access_token").build()
return chain.proceed(request)
}
}
val client = OkHttpClient.Builder()
.addInterceptor(OAuthInterceptor("Bearer", access_token))
.build()
val retrofit = Retrofit.Builder()
.baseUrl("___________________")
.client(client)
.build()
object RetrofitClient {
private const val BASE_URL = "_______"
private val okHttpClient = OkHttpClient.Builder()
.addInterceptor { chain ->
val original = chain.request()
val requestBuilder = original.newBuilder()
.method(original.method, original.body)
val request = requestBuilder.build()
chain.proceed(request)
}.build()
val instance: MyApi by lazy{
val retrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
retrofit.create(MyApi::class.java)
}
}
Below is my SharedPrefManager file :
class SharedPrefManager private constructor(private val mCtx: Context) {
val user: User
get() {
val sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE)
return User(
sharedPreferences.getString(user.access_token, ""),
sharedPreferences.getString(user.user_id.toString(), "" ),
sharedPreferences.getString(user.user_name, ""),
sharedPreferences.getString(user.status, ""),
sharedPreferences.getString(user.role_id,""),
sharedPreferences.getString(user.phone, "")
)
}
fun saveUser(user: User) {
val sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putString("access_token", user.access_token)
editor.putString("id", user.user_id)
editor.putString("username", user.user_name)
editor.putString("status", user.status)
editor.putString("role_id", user.role_id)
editor.putString("phone", user.phone)
editor.apply()
}
fun clear() {
val sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.clear()
editor.apply()
}
companion object {
private const val SHARED_PREF = "my_shared_pref"
private var mInstance: SharedPrefManager? = null
#Synchronized
fun getInstance(mCtx: Context): SharedPrefManager {
if (mInstance == null) {
mInstance = SharedPrefManager(mCtx)
}
return mInstance as SharedPrefManager
}
}
}
You should use the name of the save preference when retrieving them.
Try to change your SharedPrefManager get method like this:
get() {
val sharedPreferences = mCtx.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE)
return User(
sharedPreferences.getString("access_token", ""),
sharedPreferences.getString("id", "" ),
sharedPreferences.getString("username", ""),
sharedPreferences.getString("status", ""),
sharedPreferences.getString("role_id",""),
sharedPreferences.getString("phone", "")
)
}
D/OkHttp: {"code":60202,"message":"Token required"}
This is server error problem.
I want solve code in this resultactivity.
I already setting securityToken here, but how can I add securityToken to request()?
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val securityToken = SaveSharedPreference.getUserInfo(this)
val result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
Client.retrofitService.request(result.contents).enqueue(object : Callback<String?> {
override fun onFailure(call: Call<String?>, t: Throwable) {
}
override fun onResponse(
call: Call<String?>?,
response: Response<String?>?
) {
if (response?.isSuccessful == false) {
val er = Gson().fromJson(response.errorBody()?.charStream(), ErrorResponse::class.java)
Log.d(_tag, "${er.code}:${er.message}")
if (er.code == 60201 || er.code== 60202)
{
Toast.makeText(this#Qrcode, "토큰이 유효하지 않습니다.", Toast.LENGTH_SHORT).show()
} else if (securityToken !=null) {
Log.d(_tag, "status: ${response?.code()}. body: ${response?.body()}")
}
}
}
})
}
}```
You can add additional parameter in your request like:
interface RetrofitService {
#GET("/request")
request(#Query("parameter") parameter: String, #Header("Security-Token") securityToken: String): Call<String>
}
Or,
You can build an OkHttpClient for your Retrofit in creating RetrofitService:
RetrofitService :
interface RetrofitService {
#GET("/request")
request(#Query("parameter") parameter): Call<String>
}
Retrofit Builder:
val securityToken = "securityTokenString"
val okHttpClient = OkHttpClient.Builder()
.addInterceptor { chain ->
val request = chain.request()
val newRequestBuilder = request.newBuilder()
.header("Security-Token", securityToken)
chain.proceed(newRequestBuilder.build())
}
val retrofit = Retrofit.Builder()
.addConverterFactory(gsonConverterFactory)
.client(okHttpClient)
.baseUrl(BASE_URL)
.build()
val retrofitService = retrofit.create(RetrofitService::class.java)
I have this service where I want to put the token as an interception in the okhttp instead of passing as a parameter with #Header("MY_API_KEY")
This is my code regarding the service
/**
* Provides the [PHService]
*/
fun provideService(): PHService {
val logger = HttpLoggingInterceptor()
logger.level = HttpLoggingInterceptor.Level.BASIC
val client = OkHttpClient.Builder()
.addInterceptor(logger)
.build()
return Retrofit.Builder()
.baseUrl(BuildConfig.API_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(PHService::class.java)
}
How can I add an interceptor for header authorization in here?
add like this
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", "MY_API_KEY"); // <-- this is the important line
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
httpClient.connectTimeout(30, TimeUnit.SECONDS);
httpClient.readTimeout(30, TimeUnit.SECONDS);
httpClient.addNetworkInterceptor(logging);
OkHttpClient client = httpClient.build();
in kotlin its like
val logging = HttpLoggingInterceptor()
logging.level = HttpLoggingInterceptor.Level.BODY
val httpClient = OkHttpClient.Builder()
httpClient.addInterceptor { chain ->
val original = chain.request()
// Request customization: add request headers
val requestBuilder = original.newBuilder()
.header("Authorization", "MY_API_KEY") // <-- this is the important line
val request = requestBuilder.build()
chain.proceed(request)
}
httpClient.connectTimeout(30, TimeUnit.SECONDS)
httpClient.readTimeout(30, TimeUnit.SECONDS)
httpClient.addNetworkInterceptor(logging)
val okHttpClient=httpClient.build()
In case you wish to add an api_key and an app_id in your requests as a query parameter using retrofit and OkHttp interceptors in kotlin. You can follow the following steps. This is useful so you dont have to pass the keys in every request in each query:
const val E_BASE_URL = "https://api.example.com"
const val API_ID = "YourApiID"
const val API_KEY = "YourApiKey"
//Here you add your url interceptor
//"app_id" and "app_key" might be different, depending on your API
val api_interceptor = Interceptor {
val originalRequest = it.request()
val newHttpUrl = originalRequest.url.newBuilder()
.addQueryParameter("app_id", API_ID)
.addQueryParameter("app_key", API_KEY)
.build()
val newRequest = originalRequest.newBuilder()
.url(newHttpUrl)
.build()
it.proceed(newRequest)
}
//Add the logger interceptor optional:
val logger = HttpLoggingInterceptor().apply { setLevel(HttpLoggingInterceptor.Level.BASIC) }
//Build your OkHttpClient - here you add the api_interceptor and logger
val clientHTTP = OkHttpClient().newBuilder()
.addNetworkInterceptor(logger) //optional
.addNetworkInterceptor(api_interceptor)
.build()
//Build your json converter - in this example MOSHI
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
//FINALLY build your retrofit
val retrofitE = Retrofit.Builder()
.client(clientHTTP)
.baseUrl(E_BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
//You can now declare your interfaces with your REST methods as usual, for example GET which will return your object
interface RecipesService {
#GET("search")
suspend fun getRecipes(
#Query("q") recipe: String,
): RecipeResponse
}
//Finally you create your object (Singleton in Java) which generates your service via lazy delegate
object RecipesAPI {
val retrofitService: RecipesService by lazy {
retrofitE.create(RecipesService::class.java)
}
}
For this example, you need to import following dependencies in the latest version:
com.squareup.retrofit2:retrofit
com.squareup.moshi:moshi-kotlin
com.squareup.retrofit2:converter-moshi
com.squareup.okhttp3:logging-interceptor