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 Lesson
s. 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.