Skip to content

Instantly share code, notes, and snippets.

@shibbirweb
Last active February 4, 2024 09:58
Show Gist options
  • Select an option

  • Save shibbirweb/5cea9781b062da6bb972503628cc9f59 to your computer and use it in GitHub Desktop.

Select an option

Save shibbirweb/5cea9781b062da6bb972503628cc9f59 to your computer and use it in GitHub Desktop.
Android - Kotlin - Retrofit Authorization Token Interceptor
package com.***.data.apis
import android.content.Context
import com.****.data.apis.interceptor.ApiAcceptInterceptor
import com.****.data.apis.interceptor.AuthorizationTokenInterceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
object Api {
const val BASE_URL = "https://api.***.com/api/v1/"
private fun retrofit(context: Context?): Retrofit {
return Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client(context))
.addConverterFactory(GsonConverterFactory.create())
.build()
}
private fun client(context: Context?): OkHttpClient {
return OkHttpClient.Builder().apply {
connectTimeout(5, TimeUnit.MINUTES)
readTimeout(5, TimeUnit.MINUTES)
writeTimeout(5, TimeUnit.MINUTES)
addInterceptor(ApiAcceptInterceptor())
if (context != null)
addInterceptor(AuthorizationTokenInterceptor(context))
}.build()
}
fun <T> service(context: Context, clazz: Class<T>): T {
return retrofit(context).create(clazz)
}
fun <T> serviceWithoutAuthorization(clazz: Class<T>): T {
return retrofit(null).create(clazz)
}
}
package com.***.utilities.constants
object ApplicationConstants {
// authorization
const val TOKEN = "user_token"
}
package com.***.data.apis.endpoints.authentication
import com.***.data.models.project.authentication.*
import com.***.data.models.response.GeneralResponse
import com.***.data.models.response.authentication.IsAlreadyUserExists
import com.***.data.models.response.authentication.LoginResponse
import com.***.data.models.response.authentication.VerifyResponse
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.Header
import retrofit2.http.POST
interface AuthenticationApi {
@POST("auth/login")
suspend fun login(
@Body credential: Login
): Response<LoginResponse>
@POST("auth/register")
suspend fun register(
@Body registration: Registration
): Response<LoginResponse>
@POST("exists/user-exists-by-credential")
suspend fun isAlreadyUserExists(@Body registration: Registration): Response<IsAlreadyUserExists>
@POST("auth/verify/email")
suspend fun verifyEmail(@Body verify: Verify): Response<VerifyResponse>
@POST("auth/verify/email")
suspend fun verifyEmail(
@Body verify: Verify,
@Header("authorization") authorization: String
): Response<VerifyResponse>
@POST("auth/verify/phone")
suspend fun verifyPhone(@Body verify: Verify): Response<VerifyResponse>
@POST("auth/verify/phone")
suspend fun verifyPhone(
@Body verify: Verify,
@Header("authorization") authorization: String
): Response<VerifyResponse>
@POST("auth/resend/verification/email")
suspend fun resendVerificationCodeToEmail(@Header("Authorization") token: String): Response<GeneralResponse>
@POST("auth/resend/verification/phone")
suspend fun resendVerificationCodeToPhone(@Header("Authorization") token: String): Response<GeneralResponse>
@POST("auth/logout")
suspend fun logout(@Body logoutRequest: LogoutRequest): Response<GeneralResponse>
@POST("auth/recovery/email")
suspend fun sendVerificationCodeToEmail(@Body sendRecoveryCodeToEmailRequest: SendRecoveryCodeToEmailRequest): Response<String>
@POST("auth/recovery/phone")
suspend fun sendVerificationCodeToPhone(@Body sendRecoveryCodeToPhoneRequest: SendRecoveryCodeToPhoneRequest): Response<String>
@POST("auth/recovery/password-reset/email")
suspend fun resetPasswordByEmail(@Body resetPasswordByEmailRequest: ResetPasswordByEmailRequest): Response<GeneralResponse>
@POST("auth/recovery/password-reset/phone")
suspend fun resetPasswordByPhone(@Body resetPasswordByPhoneRequest: ResetPasswordByPhoneRequest): Response<GeneralResponse>
}
package com.***.data.repository.authentication
import android.content.Context
import com.***.data.apis.Api
import com.***.data.apis.endpoints.authentication.AuthenticationApi
import com.***.data.models.project.authentication.*
import com.***.data.models.response.authentication.IsAlreadyUserExists
import com.***.data.models.response.authentication.LoginResponse
import com.***.data.models.response.authentication.VerifyResponse
import retrofit2.Response
class AuthenticationRepository(private val context: Context) {
private val apiService by lazy {
Api.service(context, AuthenticationApi::class.java)
}
private val apiServiceWithOutAuthorizationTokenInterceptor by lazy {
Api.serviceWithoutAuthorization(AuthenticationApi::class.java)
}
suspend fun login(credential: Login): Response<LoginResponse> {
return apiServiceWithOutAuthorizationTokenInterceptor.login(credential)
}
suspend fun register(registration: Registration): Response<LoginResponse> {
return apiServiceWithOutAuthorizationTokenInterceptor.register(registration)
}
suspend fun isAlreadyUserExists(registration: Registration): Response<IsAlreadyUserExists> {
return apiServiceWithOutAuthorizationTokenInterceptor.isAlreadyUserExists(registration);
}
suspend fun verifyEmail(verify: Verify): Response<VerifyResponse> {
return apiService.verifyEmail(verify)
}
suspend fun verifyEmail(verify: Verify, token: String): Response<VerifyResponse> {
return apiServiceWithOutAuthorizationTokenInterceptor.verifyEmail(verify, "Bearer $token")
}
suspend fun verifyPhone(verify: Verify): Response<VerifyResponse> {
return apiService.verifyPhone(verify)
}
suspend fun verifyPhone(verify: Verify, token: String): Response<VerifyResponse> {
return apiServiceWithOutAuthorizationTokenInterceptor.verifyPhone(verify, "Bearer $token")
}
// resend verification code to email
suspend fun resendVerificationCodeToEmail(token: String) =
apiServiceWithOutAuthorizationTokenInterceptor.resendVerificationCodeToEmail(token)
// resend verification code to phone
suspend fun resendVerificationCodeToPhone(token: String) =
apiServiceWithOutAuthorizationTokenInterceptor.resendVerificationCodeToPhone(token)
// logout
suspend fun logout(logoutRequest: LogoutRequest) = apiService.logout(logoutRequest)
// send verification code to email
suspend fun sendVerificationCodeToEmail(sendRecoveryCodeToEmailRequest: SendRecoveryCodeToEmailRequest) =
apiService.sendVerificationCodeToEmail(sendRecoveryCodeToEmailRequest)
// send verification code to phone
suspend fun sendVerificationCodeToPhone(sendRecoveryCodeToPhoneRequest: SendRecoveryCodeToPhoneRequest) =
apiService.sendVerificationCodeToPhone(sendRecoveryCodeToPhoneRequest)
// reset password by email
suspend fun resetPasswordByEmail(resetPasswordByEmailRequest: ResetPasswordByEmailRequest) =
apiService.resetPasswordByEmail(resetPasswordByEmailRequest)
// reset password by phone
suspend fun resetPasswordByPhone(resetPasswordByPhoneRequest: ResetPasswordByPhoneRequest) =
apiService.resetPasswordByPhone(resetPasswordByPhoneRequest)
}
package com.***.data.apis.interceptor
import android.content.Context
import com.***.data.dataStoreManager.DataStoreManager
import com.***.utilities.constants.ApplicationConstants
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.Response
class AuthorizationTokenInterceptor(private val context: Context) : Interceptor {
private val TAG = this::class.simpleName
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
.newBuilder()
.addHeader("authorization", "Bearer ${getAuthorizationToken(context)}")
.build()
return chain.proceed(request)
}
private fun getAuthorizationToken(context: Context): String {
return runBlocking { DataStoreManager.getStringValue(context, ApplicationConstants.TOKEN) }
}
}
package com.***.data.dataStoreManager
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.*
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
// At the top level of your kotlin file:
val Context.userSettingsDataStore: DataStore<Preferences> by preferencesDataStore(name = "user_settings")
object DataStoreManager {
suspend fun saveValue(context: Context, key: String, value: String) {
val wrappedKey = stringPreferencesKey(key)
context.userSettingsDataStore.edit {
it[wrappedKey] = value
}
}
suspend fun saveValue(context: Context, key: String, value: Int) {
val wrappedKey = intPreferencesKey(key)
context.userSettingsDataStore.edit {
it[wrappedKey] = value
}
}
suspend fun saveValue(context: Context, key: String, value: Double) {
val wrappedKey = doublePreferencesKey(key)
context.userSettingsDataStore.edit {
it[wrappedKey] = value
}
}
suspend fun saveValue(context: Context, key: String, value: Long) {
val wrappedKey = longPreferencesKey(key)
context.userSettingsDataStore.edit {
it[wrappedKey] = value
}
}
suspend fun saveValue(context: Context, key: String, value: Boolean) {
val wrappedKey = booleanPreferencesKey(key)
context.userSettingsDataStore.edit {
it[wrappedKey] = value
}
}
suspend fun getStringValue(context: Context, key: String, default: String = ""): String {
val wrappedKey = stringPreferencesKey(key)
val valueFlow: Flow<String> = context.userSettingsDataStore.data.map {
it[wrappedKey] ?: default
}
return valueFlow.first()
}
suspend fun getIntValue(context: Context, key: String, default: Int = 0): Int {
val wrappedKey = intPreferencesKey(key)
val valueFlow: Flow<Int> = context.userSettingsDataStore.data.map {
it[wrappedKey] ?: default
}
return valueFlow.first()
}
suspend fun getDoubleValue(context: Context, key: String, default: Double = 0.0): Double {
val wrappedKey = doublePreferencesKey(key)
val valueFlow: Flow<Double> = context.userSettingsDataStore.data.map {
it[wrappedKey] ?: default
}
return valueFlow.first()
}
suspend fun getLongValue(context: Context, key: String, default: Long = 0L): Long {
val wrappedKey = longPreferencesKey(key)
val valueFlow: Flow<Long> = context.userSettingsDataStore.data.map {
it[wrappedKey] ?: default
}
return valueFlow.first()
}
suspend fun getBooleanValue(context: Context, key: String, default: Boolean = false): Boolean {
val wrappedKey = booleanPreferencesKey(key)
val valueFlow: Flow<Boolean> = context.userSettingsDataStore.data.map {
it[wrappedKey] ?: default
}
return valueFlow.first()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment