Cliente OAuth para Kotlin: integración con proveedores a través de ktor-client y kotlinx-serialization
\n\nOAuth 2.0 es un protocolo de autorización estándar que permite a las aplicaciones obtener acceso limitado a los recursos del usuario sin transferir sus credenciales. En el ecosistema de Kotlin, gracias a la compatibilidad con JVM y la multiplataforma, es posible implementar eficazmente un cliente OAuth utilizando bibliotecas modernas. En este artículo, exploraremos la creación de un cliente OAuth en Kotlin usando ktor-client para solicitudes HTTP y kotlinx-serialization para el procesamiento de JSON.
Componentes principales del cliente OAuth
\n- \n
- Cliente HTTP —
ktor-clientpara enviar solicitudes a los servidores de autorización y recursos. \n - Serialización —
kotlinx-serializationpara analizar respuestas en data-classes. \n - Almacenamiento de tokens — en memoria o persistente (SharedPreferences, archivos). \n
- Administrador de estados — manejo de authorization code, refresh token, protección CSRF. \n
Adición de dependencias
\nPara trabajar con OAuth en Kotlin, agregue las siguientes dependencias en build.gradle.kts (o build.gradle):
// build.gradle.kts\ndependencies {\n implementation("io.ktor:ktor-client-core:2.3.12")\n implementation("io.ktor:ktor-client-cio:2.3.12") // motor\n implementation("io.ktor:ktor-client-content-negotiation:2.3.12")\n implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.12")\n implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")\n implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")\n}\n\nArquitectura básica del cliente OAuth
\nDividamos la lógica en tres capas:
\n- \n
- Modelos (DTO) — data-classes para solicitudes/respuestas. \n
- Servicio — clase que gestiona los flujos de autorización. \n
- Cliente — envoltorio sobre ktor-client con métodos para diferentes grants. \n
Modelos de datos
\nimport kotlinx.serialization.SerialName\nimport kotlinx.serialization.Serializable\n\n@Serializable\ndata class TokenResponse(\n @SerialName("access_token") val accessToken: String,\n @SerialName("token_type") val tokenType: String = "Bearer",\n @SerialName("expires_in") val expiresIn: Long? = null,\n @SerialName("refresh_token") val refreshToken: String? = null,\n @SerialName("scope") val scope: String? = null,\n @SerialName("id_token") val idToken: String? = null // para OpenID Connect\n)\n\n@Serializable\ndata class OAuthError(\n val error: String,\n @SerialName("error_description") val errorDescription: String? = null\n)\n\nCliente OAuth2
\nimport io.ktor.client.*\nimport io.ktor.client.call.*\nimport io.ktor.client.plugins.contentnegotiation.*\nimport io.ktor.client.request.*\nimport io.ktor.client.statement.*\nimport io.ktor.http.*\nimport io.ktor.serialization.kotlinx.json.*\nimport kotlinx.serialization.json.Json\n\nclass OAuth2Client(\n private val clientId: String,\n private val clientSecret: String,\n private val redirectUri: String,\n private val tokenEndpoint: String,\n private val authEndpoint: String\n) {\n private val httpClient = HttpClient(CIO) {\n install(ContentNegotiation) {\n json(Json {\n ignoreUnknownKeys = true\n isLenient = true\n })\n }\n }\n\n // Generación de URL para redirigir a la página de autorización\n fun getAuthorizationUrl(state: String, scope: String = "openid profile email"): String {\n return "$authEndpoint?response_type=code" +\n "&client_id=$clientId" +\n "&redirect_uri=${java.net.URLEncoder.encode(redirectUri, "UTF-8")}" +\n "&scope=${java.net.URLEncoder.encode(scope, "UTF-8")} También en la biblioteca
Cliente Elasticsearch para Swift (iOS/macOS): integración y ejemplos
Passport.js para JavaScript (Node.js): guía completa con ejemplos
Helmet para JavaScript (Node.js): guía completa con ejemplos
Internacionalización (i18n) en C# (.NET): guía completa