OAuth клиент для Kotlin: интеграция с провайдерами через ktor-client и kotlinx-serialization
OAuth 2.0 — это стандартный протокол авторизации, который позволяет приложениям получать ограниченный доступ к ресурсам пользователя без передачи его учётных данных. В экосистеме Kotlin, благодаря совместимости с JVM и мультиплатформенности, можно эффективно реализовать OAuth-клиент с использованием современных библиотек. В этой статье мы рассмотрим создание OAuth-клиента на Kotlin с применением ktor-client для HTTP-запросов и kotlinx-serialization для обработки JSON.
Основные компоненты OAuth-клиента
- HTTP-клиент —
ktor-clientдля отправки запросов к серверам авторизации и ресурсов. - Сериализация —
kotlinx-serializationдля парсинга ответов в data-классы. - Хранилище токенов — in-memory или постоянное (SharedPreferences, файлы).
- Менеджер состояний — обработка authorization code, refresh token, CSRF-защита.
Подключение зависимостей
Для работы с OAuth в Kotlin добавьте в build.gradle.kts (или build.gradle) следующие зависимости:
// build.gradle.kts
dependencies {
implementation("io.ktor:ktor-client-core:2.3.12")
implementation("io.ktor:ktor-client-cio:2.3.12") // движок
implementation("io.ktor:ktor-client-content-negotiation:2.3.12")
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.12")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
}
Базовая архитектура OAuth-клиента
Разделим логику на три слоя:
- Модели (DTO) — data-классы для запросов/ответов.
- Сервис — класс, управляющий потоками авторизации.
- Клиент — обёртка над ktor-client с методами для разных грантов.
Модели данных
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class TokenResponse(
@SerialName("access_token") val accessToken: String,
@SerialName("token_type") val tokenType: String = "Bearer",
@SerialName("expires_in") val expiresIn: Long? = null,
@SerialName("refresh_token") val refreshToken: String? = null,
@SerialName("scope") val scope: String? = null,
@SerialName("id_token") val idToken: String? = null // для OpenID Connect
)
@Serializable
data class OAuthError(
val error: String,
@SerialName("error_description") val errorDescription: String? = null
)
Клиент OAuth2
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
class OAuth2Client(
private val clientId: String,
private val clientSecret: String,
private val redirectUri: String,
private val tokenEndpoint: String,
private val authEndpoint: String
) {
private val httpClient = HttpClient(CIO) {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
isLenient = true
})
}
}
// Генерация URL для редиректа на страницу авторизации
fun getAuthorizationUrl(state: String, scope: String = "openid profile email"): String {
return "$authEndpoint?response_type=code" +
"&client_id=$clientId" +
"&redirect_uri=${java.net.URLEncoder.encode(redirectUri, "UTF-8")}" +
"&scope=${java.net.URLEncoder.encode(scope, "UTF-8")}" +
"&state=$state"
}
// Обмен authorization code на токены
suspend fun exchangeCodeForToken(code: String): Result<TokenResponse> {
return try {
val response: HttpResponse = httpClient.post(tokenEndpoint) {
contentType(ContentType.Application.FormUrlEncoded)
setBody(buildMap {
put("grant_type", "authorization_code")
put("code", code)
put("redirect_uri", redirectUri)
put("client_id", clientId)
put("client_secret", clientSecret)
})
}
if (response.status.isSuccess()) {
Result.success(response.body<TokenResponse>())
} else {
val error = response.body<OAuthError>()
Result Также в библиотеке
Криптография в C# (.NET): шифрование и хеширование данных
Очереди задач в Swift: GCD, OperationQueue и Swift Concurrency
Интернационализация (i18n) в Java: полное руководство с примерами
Отправка email на Go: полное руководство по библиотекам и инструментам