free geoip
26

Handle API 403/401 Unauthorized Error in Kotlin

Handling API 403 and 401 Unauthorized errors is essential when building secure Kotlin Android applications that rely on web services.…

Handling API 403 and 401 Unauthorized errors is essential when building secure Kotlin Android applications that rely on web services. These HTTP status codes indicate that the user is either unauthorized (401) or forbidden (403) to access a resource, usually due to invalid credentials or missing access tokens.

In Kotlin-based Android development using Retrofit, the best practice is to intercept these responses, notify the user, and redirect them to login or token refresh logic.

Here is a complete working example to handle 401/403 API errors using Retrofit and OkHttp interceptor in Kotlin.

Step 1: Add Retrofit & OkHttp dependencies (in build.gradle):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"
implementation "com.squareup.retrofit2:retrofit:2.9.0" implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"

Step 2: Create an AuthInterceptor.kt

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class AuthInterceptor(private val tokenProvider: () -> String?) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val token = tokenProvider()
val request = chain.request().newBuilder()
.apply {
if (!token.isNullOrEmpty()) {
header("Authorization", "Bearer $token")
}
}
.build()
val response = chain.proceed(request)
if (response.code == 401 || response.code == 403) {
// You can log out the user or refresh token here
println("Unauthorized or Forbidden. Code: ${response.code}")
}
return response
}
}
class AuthInterceptor(private val tokenProvider: () -> String?) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val token = tokenProvider() val request = chain.request().newBuilder() .apply { if (!token.isNullOrEmpty()) { header("Authorization", "Bearer $token") } } .build() val response = chain.proceed(request) if (response.code == 401 || response.code == 403) { // You can log out the user or refresh token here println("Unauthorized or Forbidden. Code: ${response.code}") } return response } }
class AuthInterceptor(private val tokenProvider: () -> String?) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val token = tokenProvider()
        val request = chain.request().newBuilder()
            .apply {
                if (!token.isNullOrEmpty()) {
                    header("Authorization", "Bearer $token")
                }
            }
            .build()

        val response = chain.proceed(request)

        if (response.code == 401 || response.code == 403) {
            // You can log out the user or refresh token here
            println("Unauthorized or Forbidden. Code: ${response.code}")
        }

        return response
    }
}

Step 3: Create Retrofit Instance (ApiClient.kt)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
object ApiClient {
private val retrofit: Retrofit
init {
val client = OkHttpClient.Builder()
.addInterceptor(AuthInterceptor { getTokenFromPrefs() })
.build()
retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
fun <T> create(service: Class<T>): T = retrofit.create(service)
private fun getTokenFromPrefs(): String? {
// Replace this with real SharedPreferences or DataStore logic
return "your_token_here"
}
}
object ApiClient { private val retrofit: Retrofit init { val client = OkHttpClient.Builder() .addInterceptor(AuthInterceptor { getTokenFromPrefs() }) .build() retrofit = Retrofit.Builder() .baseUrl("https://api.example.com/") .client(client) .addConverterFactory(GsonConverterFactory.create()) .build() } fun <T> create(service: Class<T>): T = retrofit.create(service) private fun getTokenFromPrefs(): String? { // Replace this with real SharedPreferences or DataStore logic return "your_token_here" } }
object ApiClient {

    private val retrofit: Retrofit

    init {
        val client = OkHttpClient.Builder()
            .addInterceptor(AuthInterceptor { getTokenFromPrefs() })
            .build()

        retrofit = Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    fun <T> create(service: Class<T>): T = retrofit.create(service)

    private fun getTokenFromPrefs(): String? {
        // Replace this with real SharedPreferences or DataStore logic
        return "your_token_here"
    }
}

Step 4: Define Your API Interface (ApiService.kt)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
interface ApiService {
@GET("user/profile")
suspend fun getUserProfile(): Response<UserProfile>
}
interface ApiService { @GET("user/profile") suspend fun getUserProfile(): Response<UserProfile> }
interface ApiService {
    @GET("user/profile")
    suspend fun getUserProfile(): Response<UserProfile>
}

Step 5: Use the API in Your ViewModel or Repository

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
val api = ApiClient.create(ApiService::class.java)
viewModelScope.launch {
val response = api.getUserProfile()
if (response.isSuccessful) {
val user = response.body()
// Handle success
} else {
// Handle other error codes
Log.e("API_ERROR", "Error: ${response.code()}")
}
}
val api = ApiClient.create(ApiService::class.java) viewModelScope.launch { val response = api.getUserProfile() if (response.isSuccessful) { val user = response.body() // Handle success } else { // Handle other error codes Log.e("API_ERROR", "Error: ${response.code()}") } }
val api = ApiClient.create(ApiService::class.java)

viewModelScope.launch {
    val response = api.getUserProfile()
    if (response.isSuccessful) {
        val user = response.body()
        // Handle success
    } else {
        // Handle other error codes
        Log.e("API_ERROR", "Error: ${response.code()}")
    }
}

This setup ensures you handle 401/403 errors in a centralized manner using interceptors. It also prepares your codebase for further enhancements like token refresh workflows or user logout.

For more best practices on secure API integration, check out Retrofit’s official documentation.

rysasahrial

Leave a Reply

Your email address will not be published. Required fields are marked *