OAuth2 switching from Authentication Code Flow to Password Credentials / Resource Owner Flow!?

159 views
Skip to first unread message

Johannes Lichtenberger

unread,
Dec 15, 2018, 7:01:01 AM12/15/18
to vert.x
Hello,

would you recommend the authentication code flow or the password credentials flow, when you're writing a RESTful Server-API, which should be processed by a simple HTTPClient in any programming language or even curl? It's for a storage system, so that I assume the resource owner flow is the one to use. I assume for my use case where the resource owner uses my temporal storage system (the RESTful Server-API) it's even safe. The users usually are in control of both my storage system and Keycloak and their programs should just make some API-calls to retrieve the data they need in their applications (via HTTP for now).

Even though I built a simple working Web-Client for the whole authentication code flow with Vert.x, too (just for integration tests for now, and still pretty ugly with the callback hell until I figure out how to start a coroutine in a test-method).

However, I just tried to simply switch the server (which is the client in terms of OAuth2) to the password credentials flow:


    route
().handler(CookieHandler.create())
    route
().handler(BodyHandler.create())
    route
().handler(SessionHandler.create(LocalSessionStore.create(vertx)))

   
val oauth2 = KeycloakAuth.discoverAwait(
       
vertx,
       
OAuth2ClientOptions()
               
.setFlow(OAuth2FlowType.PASSWORD)
               
.setSite("http://localhost:8080/auth/realms/master")
               
.setClientID("sirix")
               
.setClientSecret("c8b9b4ed-67bb-47d9-bd73-a3babc470b2c"))

    route
().handler(UserSessionHandler.create(oauth2))

   
//val oauth2 = KeycloakAuth.create(vertx, OAuth2FlowType.AUTH_CODE, keycloakJson)
    val oauth2Handler = OAuth2AuthHandler.create(oauth2)

    oauth2Handler
.setupCallback(get("/callback"))

   
// Create.
    put("/:database").handler(oauth2Handler).coroutineHandler { Create(location).handle(it) }

And I'm getting the exception (stacktrace):

Could not start application.
java.lang.IllegalArgumentException: OAuth2Auth + Bearer Auth requires OAuth2 AUTH_CODE flow
at io.vertx.ext.web.handler.impl.OAuth2AuthHandlerImpl.verifyProvider(OAuth2AuthHandlerImpl.java:60)
at io.vertx.ext.web.handler.impl.OAuth2AuthHandlerImpl.<init>(OAuth2AuthHandlerImpl.java:77)
at io.vertx.ext.web.handler.OAuth2AuthHandler.create(OAuth2AuthHandler.java:54)
at org.sirix.rest.SirixVerticle.createRouter(SirixVerticle.kt:63)

What would I need to change, and would you change at all?

Johannes Lichtenberger

unread,
Dec 17, 2018, 4:26:09 AM12/17/18
to vert.x
Maybe using the discovery mode from OpenID-Connect is not the right thing in this case!?

Johannes Lichtenberger

unread,
Dec 17, 2018, 1:28:58 PM12/17/18
to vert.x
Okay, seems the OAuthHandler itself is just for the Authorization Code flow.

Now I provide a simple Endpoint to get the token:

val oauth2 = KeycloakAuth.create(vertx, OAuth2FlowType.PASSWORD, keycloakJson)

// To get the access token.
post("/login").produces("application/json").coroutineHandler { rc ->
    val userJson = rc.bodyAsJson
    val user = oauth2.authenticateAwait(userJson)
    rc
.response().end(user.principal().toString())
}

However, at the protected endpoints now the user-Object is not available anymore (obviously). However, can I somehow build the User from the Authorization header, parse the token itself and get an User-instance? 

Johannes Lichtenberger

unread,
Dec 17, 2018, 6:17:05 PM12/17/18
to vert.x
After a lot of debugging and looking into test cases for Vert.x I got it to work:

private suspend fun authenticateUser(ctx: RoutingContext): User {
   
val token = ctx.request().getHeader(HttpHeaders.AUTHORIZATION.toString())

   
val tokenToAuthenticate = json {
        obj("access_token" to token.substring(7),
               
"token_type" to "Bearer")
   
}

    return keycloak.authenticateAwait(tokenToAuthenticate)
}

Whereas keycloak is of type OAuth2Auth.

Paulo Lopes

unread,
Dec 19, 2018, 5:14:22 AM12/19/18
to vert.x
Hi,

The issue here is that when a user is not authenticated (there's no Authorization header) if the flow is not AUTH_CODE, the Oauth2 flow handshake will not work as the redirect is not implemented. I think in order to allow the PASSWORD flow, we need a pull request that would try to inspect of the form parameters contain a username and password fields and then start the PASSWORD flow to get a token.

In that case we would not need that check. Would you like to make such PR?

Kaushal Desai

unread,
May 15, 2019, 12:22:21 PM5/15/19
to vert.x
How do I resolve the following error?




Reply all
Reply to author
Forward
0 new messages