suspend fun refreshToken(): String? = withContext(Dispatchers.IO) { val callback = CompletableDeferred() val server = embeddedServer(CIO, port = 0) { val port = async { engine.resolvedConnectors().first().port } authentication { oauth("oauth") { @OptIn(ExperimentalCoroutinesApi::class) urlProvider = { "http://localhost:${port.getCompleted()}/callback" } providerLookup = { OAuthServerSettings.OAuth2ServerSettings( name = "google", authorizeUrl = "https://accounts.google.com/o/oauth2/auth", accessTokenUrl = "https://oauth2.googleapis.com/token", requestMethod = HttpMethod.Post, clientId = config.googleClientId, clientSecret = config.clientSecret, defaultScopes = listOf("email"), ) } client = httpClient } } routing { authenticate("oauth") { get("/login") {} get("/callback") { val principal: OAuth2? = call.authentication.principal() if (principal == null) { callback.completeExceptionally(IllegalStateException("No OAuth2 principal")) call.respondText(createErrorResponseHtml(), ContentType.Text.Html) } else { callback.complete(principal) call.respondText(createSuccessResponseHtml(), ContentType.Text.Html) } } } } } try { server.startSuspend(wait = false) val port = server.engine.resolvedConnectors().first().port val response = httpClient.config { followRedirects = false }.get("http://localhost:$port/login") require(response.status == HttpStatusCode.Found) { "Server returned ${response.status} status code. Expected 302 Found for OAuth redirect." } val url = response.headers["Location"]!! Desktop.getDesktop().browse(URI(url)) val oauth = callback.await() token = oauth oauth.extraParameters["id_token"] } finally { withContext(NonCancellable) { server.stopSuspend(1000, 5000) } } }