Skip to content

Instantly share code, notes, and snippets.

@nomisRev
Created February 23, 2022 08:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nomisRev/a42110d095e3fd2c82d8137c995569b1 to your computer and use it in GitHub Desktop.
Save nomisRev/a42110d095e3fd2c82d8137c995569b1 to your computer and use it in GitHub Desktop.
Ktor Google OAuth2
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.cio.CIO
import io.ktor.client.request.get
import io.ktor.client.request.headers
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpMethod
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.call
import io.ktor.server.application.Application
import io.ktor.server.application.install
import io.ktor.server.auth.Authentication
import io.ktor.server.auth.OAuthAccessTokenResponse
import io.ktor.server.auth.OAuthServerSettings
import io.ktor.server.auth.authenticate
import io.ktor.server.auth.oauth
import io.ktor.server.auth.principal
import io.ktor.server.html.respondHtml
import io.ktor.server.response.respondRedirect
import io.ktor.server.response.respondText
import io.ktor.server.routing.get
import io.ktor.server.routing.routing
import io.ktor.server.sessions.Sessions
import io.ktor.server.sessions.cookie
import io.ktor.server.sessions.get
import io.ktor.server.sessions.sessions
import io.ktor.server.sessions.set
import kotlinx.html.a
import kotlinx.html.body
import kotlinx.html.p
import kotlinx.serialization.SerialName
fun Application.installAuth() {
val httpClient = HttpClient(CIO) {
install(io.ktor.client.plugins.ContentNegotiation) {
json()
}
}
install(Sessions) {
cookie<UserSession>("user_session")
}
install(Authentication) {
oauth("auth-oauth-google") {
urlProvider = { "http://localhost:8080/callback" }
providerLookup = {
OAuthServerSettings.OAuth2ServerSettings(
name = "google",
authorizeUrl = "https://accounts.google.com/o/oauth2/auth",
accessTokenUrl = "https://accounts.google.com/o/oauth2/token",
requestMethod = HttpMethod.Post,
clientId = System.getenv("GOOGLE_CLIENT_ID"),
clientSecret = System.getenv("GOOGLE_CLIENT_SECRET"),
defaultScopes = listOf("https://www.googleapis.com/auth/userinfo.profile")
)
}
// Closeable
client = httpClient
}
}
routing {
authenticate("auth-oauth-google") {
get("/login") {
// Redirects to 'authorizeUrl' automatically
}
get("/callback") {
val principal: OAuthAccessTokenResponse.OAuth2? = call.principal()
call.sessions.set(UserSession(principal?.accessToken.toString()))
call.respondRedirect("/hello")
}
}
get("/") {
call.respondHtml(HttpStatusCode.OK) {
body {
p {
a("/login") { +"Login with Google" }
}
}
}
}
get("/hello") {
val userSession: UserSession? = call.sessions.get()
if (userSession != null) {
val userInfo: UserInfo = httpClient.get("https://www.googleapis.com/oauth2/v2/userinfo") {
headers {
append(HttpHeaders.Authorization, "Bearer ${userSession.token}")
}
}.body()
call.respondText("Hello, ${userInfo.name}!")
} else {
call.respondRedirect("/")
}
}
}
}
data class UserSession(val token: String)
@kotlinx.serialization.Serializable
data class UserInfo(
val id: String,
val name: String,
@SerialName("given_name") val givenName: String,
@SerialName("family_name") val familyName: String,
val picture: String,
val locale: String
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment