Created
July 30, 2025 07:51
-
-
Save nomisRev/a76b02442ea9f53e2ac8d83c2d5fd7e8 to your computer and use it in GitHub Desktop.
OpenID Connect example including OAuth2 and JWT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example | |
import com.auth0.jwk.JwkProviderBuilder | |
import io.ktor.client.HttpClient | |
import io.ktor.client.call.body | |
import io.ktor.client.request.get | |
import io.ktor.http.HttpMethod | |
import io.ktor.server.auth.AuthenticationConfig | |
import io.ktor.server.auth.OAuthServerSettings | |
import io.ktor.server.auth.authentication | |
import io.ktor.server.auth.jwt.JWTConfigureFunction | |
import io.ktor.server.auth.jwt.jwt | |
import io.ktor.server.auth.oauth | |
import io.ktor.server.engine.embeddedServer | |
import io.ktor.server.netty.Netty | |
import kotlinx.serialization.SerialName | |
import kotlinx.serialization.Serializable | |
import java.net.URL | |
fun main() { | |
embeddedServer(Netty, port = 8080, host = "0.0.0.0") { | |
val client = HttpClient() | |
val configuration = client.discover("https://accounts.google.com") | |
authentication { | |
configureOpenIdOAuth(configuration, "OPENID_CLIENT_ID", "OPENID_SECRET", client) | |
configureOpenIdJwk(configuration) | |
} | |
}.start(wait = true) | |
} | |
@Serializable | |
data class OpenIdConfiguration( | |
val issuer: String, | |
@SerialName("authorization_endpoint") | |
val authorizationEndpoint: String, | |
@SerialName("token_endpoint") | |
val tokenEndpoint: String, | |
@SerialName("jwks_uri") | |
val jwksUri: String, | |
) | |
/** | |
* Automatically discover OpenID Connect configuration | |
*/ | |
suspend fun HttpClient.discover(issuer: String): OpenIdConfiguration = | |
get("$issuer/.well-known/openid-configuration").body<OpenIdConfiguration>() | |
/** Configure Ktor's OAuth2 using [OpenIdConfiguration], and app-specific secrets. */ | |
fun AuthenticationConfig.configureOpenIdOAuth( | |
configuration: OpenIdConfiguration, | |
clientId: String, | |
clientSecret: String, | |
client: HttpClient, | |
scopes: List<String> = listOf("openid", "profile", "email") | |
) = oauth("openid-connect") { | |
urlProvider = { "http://localhost:8080/callback" } | |
providerLookup = { | |
OAuthServerSettings.OAuth2ServerSettings( | |
name = "openid-connect", | |
authorizeUrl = configuration.authorizationEndpoint, | |
accessTokenUrl = configuration.tokenEndpoint, | |
requestMethod = HttpMethod.Post, | |
clientId = clientId, | |
clientSecret = clientSecret, | |
defaultScopes = scopes | |
) | |
} | |
this.client = client | |
} | |
fun AuthenticationConfig.configureOpenIdJwk( | |
configuration: OpenIdConfiguration, | |
applyJwk: JwkProviderBuilder.() -> Unit = { cached(true).rateLimited(true) }, | |
verify: JWTConfigureFunction = {}, | |
name: String? = null, | |
) = jwt(name) { | |
val jwk = JwkProviderBuilder(URL(configuration.jwksUri)).apply(applyJwk).build() | |
verifier(jwk, configuration.issuer, verify) | |
validate { credential -> credential } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment