Client OAuth pour Kotlin : intégration avec les fournisseurs via ktor-client et kotlinx-serialization
\n\nOAuth 2.0 est un protocole d'autorisation standard qui permet aux applications d'obtenir un accès limité aux ressources d'un utilisateur sans transmettre ses identifiants. Dans l'écosystème Kotlin, grâce à la compatibilité JVM et à la multiplateforme, il est possible d'implémenter efficacement un client OAuth en utilisant des bibliothèques modernes. Dans cet article, nous allons créer un client OAuth en Kotlin avec ktor-client pour les requêtes HTTP et kotlinx-serialization pour le traitement JSON.
Composants principaux du client OAuth
\n- \n
- Client HTTP —
ktor-clientpour envoyer des requêtes aux serveurs d'autorisation et de ressources. \n - Sérialisation —
kotlinx-serializationpour analyser les réponses en classes de données. \n - Stockage des jetons — en mémoire ou persistant (SharedPreferences, fichiers). \n
- Gestionnaire d'états — traitement du code d'autorisation, du jeton d'actualisation, protection CSRF. \n
Ajout des dépendances
\nPour travailler avec OAuth en Kotlin, ajoutez les dépendances suivantes dans build.gradle.kts (ou 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") // moteur\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\nArchitecture de base du client OAuth
\nDivisons la logique en trois couches :
\n- \n
- Modèles (DTO) — classes de données pour les requêtes/réponses. \n
- Service — classe gérant les flux d'autorisation. \n
- Client — wrapper autour de ktor-client avec des méthodes pour différents types de subventions. \n
Modèles de données
\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 // pour OpenID Connect\n)\n\n@Serializable\ndata class OAuthError(\n val error: String,\n @SerialName("error_description") val errorDescription: String? = null\n)\n\nClient 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 // Génération de l'URL pour la redirection vers la page d'autorisation\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")}