Basic Auth with OkHttp and Retrofit
November 5, 2022
This post contains a basic example of performing an HTTP GET request to an endpoint that requires Basic Authentication in a Kotlin Android project using the following libraries:
OkHttp
Retrofit
Dagger/Hilt
Moshi (or another JSON library, if applicable)
Gradle dependencies
Use the most current versions that work for your project.
Top-level build.gradle
plugins {
...
id 'com.google.dagger.hilt.android' version '2.44' apply false
}
App-level build.gradle
plugins {
...
id 'dagger.hilt.android.plugin'
}
dependencies {
...
implementation 'com.google.dagger:hilt-android:2.44'
kapt 'com.google.dagger:hilt-compiler:2.44'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
implementation 'com.squareup.moshi:moshi-kotlin:1.14.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
kapt 'com.squareup.moshi:moshi-kotlin-codegen:1.14.0'
}
Define your model (if applicable)
We will be loading a list of Lessons. The payload shape is as follows:
[
{
"lesson_id": 1,
"name": "English 101"
},
{
"lesson_id": 2,
"name": "English 102"
}
]
The Moshi annotations used below are only applicable in our API contract.
@JsonClass(generateAdapter = true) data class Lesson( @Json(name = "lesson_id") val id: Int, val name: String )
Set up Retrofit Interface
private const val FETCH_LESSONS_URL = "/api/lessons"
interface LessonsApi {
@Headers("Content-Type: application/json;charset=UTF-8")
@GET("$BASE_URL$FETCH_LESSONS_URL")
suspend fun getLessons(
@Query("date") date: String
): List<Lesson>
}
Configure Dagger Module
Let’s make the outgoing requests go through a custom Interceptor which sets the “Authorization” header using Credentials.basic(username, password)
const val BASE_URL = "https://example.com"
@Module
@InstallIn(SingletonComponent::class)
class AppModule {
private val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
private val okHttpBuilder = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
@Provides
fun provideLessonsApi(): LessonsApi {
okHttpBuilder.addInterceptor(
BasicAuthInterceptor(
BuildConfig.BASIC_AUTH_USERNAME,
BuildConfig.BASIC_AUTH_PASSWORD
)
)
return Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.client(okHttpBuilder.build())
.build()
.create(LessonsApi::class.java)
}
}
class BasicAuthInterceptor(username: String, password: String) : Interceptor {
private val credentials: String = Credentials.basic(username, password)
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request = chain.request()
val authenticatedRequest: Request = request.newBuilder()
.header("Authorization", credentials).build()
return chain.proceed(authenticatedRequest)
}
}
Define Repository
We’ll define a Repository interface and its implementation. We’ll be injecting the interface in a ViewModel.
interface LessonsRepository {
suspend fun getLessons(date: String): Result<List<Lesson>>
}
class LessonsRepositoryImpl @Inject constructor(
val api: LessonsApi
) : LessonsRepository {
override suspend fun getLessons(date: String): Result<List<Lesson>> {
return runCatching {
api.getLessons(date)
}
}
}
Make the LessonsRepository injectable via interface:
@Module
@InstallIn(SingletonComponent::class)
abstract class RepoModule {
@Binds
abstract fun bindsLessonsRepository(repo: LessonsRepositoryImpl): LessonsRepository
}
And use the repository in your ViewModel:
@HiltViewModel class LessonsViewModel @Inject constructor( private val lessonsRepository: LessonsRepository ) : ViewModel()
That’s it. Now your LessonsRepository lookups will be authenticated using Basic Authentication.