I am implementing authentication in my Ktor app, using an Oauth provider who issues JWT tokens as response. I get the callback, and receive the access token, then manually go and fetch the refresh & id token from the provider.
This all works well and I can validate the JWT against the provider’s public key manually.
I’d now like to attach JWT authentication onto my app as the user will have their session. However I’m not sure if this is the correct solution.
Is it best practice to set login + callback as oauth, and the rest of the app’s protected resources as JWT authenticated?
If not, how can i combine my oauth authentication settings with the JWT validation on the client’s cookie?
Note, the returned JWT has multiple claims. Im thinking I may need to set the JWT as a cookie but that seems wrong. Should I just set the state in the cookie and keep a local cache of the user’s id and refresh token?
install (Authentication) {
jwt("jwt-cookie") {
verifier(
issuer = "my-issuer-url",
audience = "my-audience",
algorithm = RSA256(myKeyProvider)
)
validate { credential ->
if (credential.payload.getClaim("sub").asString() != "")
JWTPrincipal(credential.payload)
else
null
}
challenge {
call.respond(Unauthorized)
}
}
oauth("cookie-provider") {
urlProvider = { "https://myUrlProvider:port/callback" }
providerLookup = {
OauthServerSettings.Oauth2ServerSettings(
name = "cookie-provider",
authorizeUrl = "myAuthorizeUrl",
accessTokenUrl = "myAccessTokenUrl",
requestMethod = Post,
clientId = "myClientId",
passParamsInURL = true
)
}
}
routing {
authenticate("cookie-provider") {
get("/login") { }
get("/callback") {
val accessCode = call.request.queryParameters["code"]
val state = call.request.queryParameters["state"]
if (accessCode != null && state != null) {
val token = myProviderCient.fetchToken(accessCode)
call.sessions.set(UserSession(state, token.refresh))
call.respondRedirect("/welcome")
}
}
}
authenticate("jwt-cookie") {
get("/welcome") {
val principal = call.principal<JWTPrincipal>()
val userID = principal?.payload?.getClaim("UserId")
call.responseText("Hello, $userID!")
}
}
}