I tried to set up a working Oauth2 authorization via Keycloak in a Ktor web server. The expected flow would be sending a request from the web server to keycloak and logging in on the given UI, then Keycloak sends back a code that can be used to receive a token. Like here
First I did it based on the examples in Ktor's documentation. Oauth It worked fine until it got to the point where I had to receive the token, then it just gave me HTTP status 401. Even though the curl command works properly. Then I tried an example project I found on GitHub , I managed to make it work by building my own HTTP request and sending it to the Keycloak server to receive the token, but is it supposed to work like this?
I have multiple questions regarding this.
Is this function supposed to handle both authorization and getting the token?
authenticate(keycloakOAuth) { get("/oauth") { val principal = call.authentication.principal<OAuthAccessTokenResponse.OAuth2>() call.respondText("Access Token = ${principal?.accessToken}") } }I think my configuration is correct, since I can receive the authorization, just not the token.
const val KEYCLOAK_ADDRESS = "**" val keycloakProvider = OAuthServerSettings.OAuth2ServerSettings( name = "keycloak", authorizeUrl = "$KEYCLOAK_ADDRESS/auth/realms/production/protocol/openid-connect/auth", accessTokenUrl = "$KEYCLOAK_ADDRESS/auth/realms/production/protocol/openid-connect/token", clientId = "**", clientSecret = "**", accessTokenRequiresBasicAuth = false, requestMethod = HttpMethod.Post, // must POST to token endpoint defaultScopes = listOf("roles") ) const val keycloakOAuth = "keycloakOAuth" install(Authentication) { oauth(keycloakOAuth) { client = HttpClient(Apache) providerLookup = { keycloakProvider } urlProvider = { "http://localhost:8080/token" } } }There is this /token route I made with a built HTTP request, this one manages to get the token, but it feels like a hack.
get("/token"){ var grantType = "authorization_code" val code = call.request.queryParameters["code"] val requestBody = "grant_type=${grantType}&" + "client_id=${keycloakProvider.clientId}&" + "client_secret=${keycloakProvider.clientSecret}&" + "code=${code.toString()}&" + "redirect_uri=http://localhost:8080/token" val tokenResponse = httpClient.post<HttpResponse>(keycloakProvider.accessTokenUrl) { headers { append("Content-Type","application/x-www-form-urlencoded") } body = requestBody } call.respondText("Access Token = ${tokenResponse.readText()}") }
TL;DR: I can log in via Keycloak fine, but trying to get an access_token gives me 401. Is the authenticate function in ktor supposed to handle that too?