Skip to content

Instantly share code, notes, and snippets.

@stargatex
Last active February 21, 2024 17:58
Show Gist options
  • Save stargatex/7678d15a6e7bef0b3cf1262f38a7a31d to your computer and use it in GitHub Desktop.
Save stargatex/7678d15a6e7bef0b3cf1262f38a7a31d to your computer and use it in GitHub Desktop.
Code snippets of Token refresh implementation with Ktor in Kotlin Multiplatform Mobile - Medium Post - https://medium.com/@lahirujay
actual fun platformNetModule(): Module = module {
single {
OkHttp.create {
preconfigured = getOkHttpClient()
}
}
}
fun getOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.build()
}
val commonMain by getting {
dependencies {
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
implementation("io.ktor:ktor-client-logging:$ktorVersion")
implementation("io.ktor:ktor-client-auth:$ktorVersion")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
implementation("io.insert-koin:koin-core:$koinVersion")
implementation("io.github.aakira:napier:$napierVersion")
}
}
val androidMain by getting {
dependencies {
implementation("io.ktor:ktor-client-okhttp:$ktorVersion")
}
}
val iosMain by creating {
dependsOn(commonMain)
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
iosSimulatorArm64Main.dependsOn(this)
dependencies {
implementation("io.ktor:ktor-client-darwin:$ktorVersion")
}
}
actual fun platformNetModule(): Module = module {
single { Darwin.create() }
}
fun initKoin(
enableLogs: Boolean = false,
baseUrl: String, clientId: String, appDeclaration: KoinAppDeclaration = {}
) = startKoin {
appDeclaration()
modules(
platformNetModule(),
networkModule(enableLogs, baseUrl, clientId),
userManagerModule(),
//...
)
}
//IOS
fun KoinApplication.Companion.start(baseUrl: String,clientId: String): KoinApplication =
initKoin(enableLogs = true, baseUrl = baseUrl, clientId = clientId) { }
expect fun platformNetModule(): Module
fun networkModule(enableLogs: Boolean, baseUrl: String, clientId: String) = module {
single {
HttpClient(get()) {
expectSuccess = true
install(Auth){
bearer {
loadTokens {
val userManager: UserManager = get() // Secure Token Store
val accessToken = userManager.get().accessToken
val refreshToken = userManager.get().refreshToken
BearerTokens(accessToken!!,refreshToken!!)
}
refreshTokens {
val userManager: UserManager = get() // Secure Token Store
val refreshTokenInfo: TokenInfo = client.submitForm(
url = "token",
formParameters = Parameters.build {
append("grant_type", "refresh_token")
append("client_id", clientId)
append("refresh_token", userManager.get().refreshToken ?: "")
}
) { markAsRefreshTokenRequest() }.body()
userManager.connect(
SessionData(
accessToken = refreshTokenInfo
.accessToken,
idToken = refreshTokenInfo.idToken,
refreshToken = refreshTokenInfo.refreshToken
)
)
val accessToken = refreshTokenInfo.accessToken
val refreshToken = userManager.get().refreshToken
BearerTokens(accessToken, refreshToken!!)
}
}
}
defaultRequest {
url {
host = baseUrl
url { protocol = URLProtocol.HTTPS }
}
}
install(Logging) {
logger = object : Logger {
override fun log(message: String) {
Napier.v(message = message, tag = "HTTPS Client")
}
}
level = LogLevel.ALL
}
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
ignoreUnknownKeys = true
})
}
}
}
}
install(Auth){
bearer {
refreshTokens {
val refreshTokenInfo: TokenInfo = client.submitForm(
url = "token", //token endpoint
formParameters = Parameters.build {
append("grant_type", "refresh_token")
append("client_id", "YOUR_CLIENT_ID")
append("refresh_token", "CURRENT_REFRESH_TOKEN")
}
) { markAsRefreshTokenRequest() }.body()
val accessToken = refreshTokenInfo.accessToken
val refreshToken = refreshTokenInfo.refreshToken
BearerTokens(accessToken, refreshToken)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment