quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.63k stars 2.64k forks source link

Loop on authentification page when authenticated - OIDC Auth0 #13023

Closed majonga88 closed 3 years ago

majonga88 commented 3 years ago

Describe the bug

Regarding to test the fix of this bug : https://github.com/quarkusio/quarkus/issues/8396, when i trying to connect to my application via Auth0 and i'm experiencing a new issue.

2020-10-26 17:28:19,825 FINE  [io.ver.ext.aut.oau.imp.OAuth2UserImpl] (vert.x-eventloop-thread-7) Expired token:: java.lang.RuntimeException: Invalid JWT token: iat > now
    at io.vertx.ext.jwt.JWT.isExpired(JWT.java:341)
    at io.vertx.ext.auth.oauth2.impl.OAuth2UserImpl.expired(OAuth2UserImpl.java:259)
    at io.vertx.ext.auth.oauth2.impl.OAuth2AuthProviderImpl.authenticate(OAuth2AuthProviderImpl.java:304)
    at io.vertx.ext.auth.oauth2.impl.OAuth2AuthProviderImpl.decodeToken(OAuth2AuthProviderImpl.java:338)
    at io.quarkus.oidc.runtime.OidcIdentityProvider$2.accept(OidcIdentityProvider.java:99)
    at io.quarkus.oidc.runtime.OidcIdentityProvider$2.accept(OidcIdentityProvider.java:95)
    at io.smallrye.mutiny.operators.UniCreateWithEmitter.subscribing(UniCreateWithEmitter.java:22)
    at io.smallrye.mutiny.operators.UniSerializedSubscriber.subscribe(UniSerializedSubscriber.java:54)
    at io.smallrye.mutiny.operators.UniSerializedSubscriber.subscribe(UniSerializedSubscriber.java:49)
    at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:30)
    at io.smallrye.mutiny.operators.UniCreateFromDeferredSupplier.subscribing(UniCreateFromDeferredSupplier.java:35)
    at io.smallrye.mutiny.operators.UniSerializedSubscriber.subscribe(UniSerializedSubscriber.java:54)
    at io.smallrye.mutiny.operators.UniSerializedSubscriber.subscribe(UniSerializedSubscriber.java:49)
    at io.smallrye.mutiny.groups.UniSubscribe.withSubscriber(UniSubscribe.java:50)
    at io.smallrye.mutiny.groups.UniSubscribe.with(UniSubscribe.java:70)
    at io.quarkus.oidc.runtime.CodeAuthenticationMechanism$4.lambda$accept$0(CodeAuthenticationMechanism.java:320)
    at io.vertx.ext.auth.oauth2.impl.OAuth2AuthProviderImpl.lambda$authenticate$5(OAuth2AuthProviderImpl.java:318)
    at io.vertx.ext.auth.oauth2.impl.flow.AuthCodeImpl.lambda$getToken$0(AuthCodeImpl.java:93)
    at io.vertx.ext.auth.oauth2.impl.flow.AbstractOAuth2Flow.lambda$getToken$0(AbstractOAuth2Flow.java:148)
    at io.vertx.ext.auth.oauth2.impl.OAuth2API.lambda$null$1(OAuth2API.java:129)
    at io.vertx.core.http.impl.HttpClientResponseImpl$BodyHandler.notifyHandler(HttpClientResponseImpl.java:292)
    at io.vertx.core.http.impl.HttpClientResponseImpl.lambda$bodyHandler$0(HttpClientResponseImpl.java:193)
    at io.vertx.core.http.impl.HttpClientResponseImpl.handleEnd(HttpClientResponseImpl.java:248)
    at io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.lambda$beginResponse$0(Http1xClientConnection.java:483)
    at io.vertx.core.streams.impl.InboundBuffer.handleEvent(InboundBuffer.java:237)
    at io.vertx.core.streams.impl.InboundBuffer.write(InboundBuffer.java:127)
    at io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.endResponse(Http1xClientConnection.java:502)
    at io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.access$000(Http1xClientConnection.java:241)
    at io.vertx.core.http.impl.Http1xClientConnection.handleResponseEnd(Http1xClientConnection.java:641)
    at io.vertx.core.http.impl.Http1xClientConnection.handleHttpMessage(Http1xClientConnection.java:601)
    at io.vertx.core.http.impl.Http1xClientConnection.handleMessage(Http1xClientConnection.java:575)
    at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:366)
    at io.vertx.core.impl.EventLoopContext.execute(EventLoopContext.java:43)
    at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:229)
    at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:163)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1518)
    at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1267)
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1314)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:440)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:829)

I inspect the code on vertx-jwt-3.9.3 dependency, JWT.class inside io.vertx.ext.jwt package, line 337 to 343 and i've seen my timestamp iat more recent than the timestamp now.

image

Here is the difference between the two dates, more interpretable read here :

image

Thank you for your help.

Expected behavior

The present token should not expired in this case.

Actual behavior

The token is expired.

To Reproduce

Here is the target project : https://github.com/majonga88/security-quarkus

Environment (please complete the following information):

sberyozkin commented 3 years ago

@majonga88 I think this issue is invalid, in such cases you need to use quarkus.oidc.token.lifespan-grace to deal with some clock skews etc

majonga88 commented 3 years ago

It's much better thanks, i have no longer the issue, but i experienced now a strange redirection when i'm trying to connect to my application. It redirect to the auth0 login page after every login. The actual Auth0 configuration work on a personal SpringBoot application that i use.


2020-10-29 22:59:42,607 DEBUG [io.net.han.cod.com.ZlibCodecFactory] (vert.x-eventloop-thread-34) -Dio.netty.noJdkZlibDecoder: false
2020-10-29 22:59:42,607 DEBUG [io.net.han.cod.com.ZlibCodecFactory] (vert.x-eventloop-thread-34) -Dio.netty.noJdkZlibEncoder: false
2020-10-29 22:59:42,632 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-34) Authentication request redirect_uri parameter: http://localhost:8080/
2020-10-29 22:59:42,632 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-34) q_auth cookie 'max-age' parameter is set to 1800
2020-10-29 22:59:46,486 DEBUG [io.net.han.ssl.SslHandler] (vert.x-eventloop-thread-2) [id: 0x7432ccf7, L:/192.168.1.10:64298 - R:dev-0-77r6yl.auth0.com/104.16.184.248:443] HANDSHAKEN: protocol:TLSv1.2 cipher suite:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
2020-10-29 22:59:47,553 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-34) Token request redirect_uri parameter: http://localhost:8080/
2020-10-29 22:59:47,617 DEBUG [io.net.han.ssl.SslHandler] (vert.x-eventloop-thread-34) [id: 0xc971cdef, L:/192.168.1.10:64301 - R:dev-0-77r6yl.auth0.com/104.16.184.248:443] HANDSHAKEN: protocol:TLSv1.2 cipher suite:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
2020-10-29 22:59:47,877 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-34) Authentication request redirect_uri parameter: http://localhost:8080/
2020-10-29 22:59:47,877 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-34) q_auth cookie 'max-age' parameter is set to 1800
2020-10-29 22:59:54,138 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-34) Token request redirect_uri parameter: http://localhost:8080/
2020-10-29 22:59:54,168 DEBUG [io.net.han.ssl.SslHandler] (vert.x-eventloop-thread-34) [id: 0x05f79dab, L:/192.168.1.10:64307 - R:dev-0-77r6yl.auth0.com/104.16.184.248:443] HANDSHAKEN: protocol:TLSv1.2 cipher suite:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
2020-10-29 22:59:54,411 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-34) Authentication request redirect_uri parameter: http://localhost:8080/
2020-10-29 22:59:54,411 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-34) q_auth cookie 'max-age' parameter is set to 1800
2020-10-29 23:00:01,751 DEBUG [io.net.han.ssl.SslHandler] (vert.x-eventloop-thread-2) [id: 0x191346c8, L:/192.168.1.10:64315 - R:dev-0-77r6yl.auth0.com/104.16.184.248:443] HANDSHAKEN: protocol:TLSv1.2 cipher suite:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
2020-10-29 23:00:17,389 DEBUG [io.net.han.ssl.SslHandler] (vert.x-eventloop-thread-2) [id: 0x3f484c24, L:/192.168.1.10:64349 - R:dev-0-77r6yl.auth0.com/104.16.185.248:443] HANDSHAKEN: protocol:TLSv1.2 cipher suite:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256```
sberyozkin commented 3 years ago

@majonga88 can you try quarkus.oidc.authentication.cookie-path=/ ?

majonga88 commented 3 years ago

@sberyozkin I have the same behaviour, if you want i can share with you in private message my Auth0 credentials to check, here is the logs :

2020-10-30 13:30:38,873 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-15) Authentication request redirect_uri parameter: http://localhost:8080/
2020-10-30 13:30:38,873 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-15) q_auth cookie 'max-age' parameter is set to 1800
2020-10-30 13:30:47,881 DEBUG [io.net.han.ssl.SslHandler] (vert.x-eventloop-thread-2) [id: 0xa092f812, L:/192.168.1.10:49894 - R:dev-0-77r6yl.auth0.com/104.16.185.248:443] HANDSHAKEN: protocol:TLSv1.2 cipher suite:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
2020-10-30 13:31:03,069 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-15) Token request redirect_uri parameter: http://localhost:8080/
2020-10-30 13:31:03,101 DEBUG [io.net.han.ssl.SslHandler] (vert.x-eventloop-thread-15) [id: 0x39721a57, L:/192.168.1.10:49919 - R:dev-0-77r6yl.auth0.com/104.16.184.248:443] HANDSHAKEN: protocol:TLSv1.2 cipher suite:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
2020-10-30 13:31:03,146 DEBUG [io.net.han.ssl.SslHandler] (vert.x-eventloop-thread-2) [id: 0xf6430673, L:/192.168.1.10:49921 - R:dev-0-77r6yl.auth0.com/104.16.184.248:443] HANDSHAKEN: protocol:TLSv1.2 cipher suite:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
2020-10-30 13:31:03,369 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-15) Authentication request redirect_uri parameter: http://localhost:8080/
2020-10-30 13:31:03,369 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-15) q_auth cookie 'max-age' parameter is set to 1800
2020-10-30 13:31:07,262 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-15) Token request redirect_uri parameter: http://localhost:8080/
2020-10-30 13:31:07,320 DEBUG [io.net.han.ssl.SslHandler] (vert.x-eventloop-thread-15) [id: 0x91eb085b, L:/192.168.1.10:49935 - R:dev-0-77r6yl.auth0.com/104.16.184.248:443] HANDSHAKEN: protocol:TLSv1.2 cipher suite:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
2020-10-30 13:31:07,566 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-15) Authentication request redirect_uri parameter: http://localhost:8080/
2020-10-30 13:31:07,566 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-15) q_auth cookie 'max-age' parameter is set to 1800
2020-10-30 13:31:12,778 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-15) Token request redirect_uri parameter: http://localhost:8080/
2020-10-30 13:31:12,803 DEBUG [io.net.han.ssl.SslHandler] (vert.x-eventloop-thread-15) [id: 0xec7376fa, L:/192.168.1.10:49942 - R:dev-0-77r6yl.auth0.com/104.16.184.248:443] HANDSHAKEN: protocol:TLSv1.2 cipher suite:TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
2020-10-30 13:31:13,061 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-15) Authentication request redirect_uri parameter: http://localhost:8080/
2020-10-30 13:31:13,061 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-15) q_auth cookie 'max-age' parameter is set to 1800
sberyozkin commented 3 years ago

@majonga88 Can you please fork this project, https://github.com/quarkusio/quarkus-quickstarts/tree/1.9.1.Final/security-openid-connect-web-authentication-quickstart, update these properties with Auth0 connection url, and see if you can reproduce it ? I'm assuming you are on the latest Quarkus. Or create a reproducer project in your githib account and ping me privately at https://quarkusio.zulipchat.com/

majonga88 commented 3 years ago

@sberyozkin Ok so i fork your project security-openid-connect-web-authentication-quickstart, the authentification works without :

quarkus.oidc.roles.source=userinfo or quarkus.oidc.roles.source=accesstoken parameters.

I go to this url : http://localhost:8080/tokens. I have an error like we saw on #8396 which is normal without quarkus.oidc.roles.source. See the error log below :

2020-10-31 17:36:25,926 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-1) HTTP Request to /tokens failed, error id: 0c347fc3-72a8-43df-a8ca-9b1d476b3947-1: org.jboss.resteasy.spi.UnhandledException: io.quarkus.oidc.OIDCException: Opaque access token can not be converted to JsonWebToken
    at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:106)
    at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:372)
    at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:218)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:519)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
    at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
    at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:131)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.access$000(VertxRequestHandler.java:37)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:94)
    at io.quarkus.runtime.CleanableExecutor$CleaningRunnable.run(CleanableExecutor.java:231)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2046)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1578)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
    at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
    at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
    at java.base/java.lang.Thread.run(Thread.java:829)
    at org.jboss.threads.JBossThread.run(JBossThread.java:479)

When i tried with quarkus.oidc.roles.source=userinfo it loop on authentification page of Auth0 and quarkus.oidc.roles.source=accesstoken send me a 403 forbidden with this kind of url : http://localhost:8080/?code=57VpewRDgvBCLIAs&state=457304d5-9917-484a-853c-e0d6ee393b50.

The branch is here : https://github.com/majonga88/security-quarkus/tree/fork

Can you help me, if you want please ping me zulipchat i'm on.

sberyozkin commented 3 years ago

@majonga88 I think I understand now why you are seeing a loop. I believe it happens due to the wrong exception beng reported in case of the user-info request failure, I'm pretty sure I saw it but did not fix yet, so I'll take care of it as part of this issue. The reason the userinfo request fails is because the access token does not have enough permissions for it. Also, since the access token is binary, you get a scope returned in the introspection response and whatever value is returned there does not match what you set in RolesAllowed. You can inspect what is really returned there by setting a breakpoint in a custom SecurityIdentityAugmentor, see https://quarkus.io/guides/security-customization#security-identity-customization and https://github.com/quarkusio/quarkus-security/blob/master/src/main/java/io/quarkus/security/identity/SecurityIdentity.java#L53

majonga88 commented 3 years ago

@sberyozkin Ok i deep looking the documentation of Auth0 about access token here and openid scopes here

When i do it manually :

We need to get an authorization code from the authorization server for generate the access token :

https://dev-0-77r6yl.auth0.com/authorize?audience=https://quickstarts/api&scope=openid&response_type=code&client_id=hSbuxfeTI25DHp0F9OPW1XbQe42ONiD6&redirect_uri=http://localhost:8080/&state=xbc

After that, we are redirect and we get a code and a state on this url : http://localhost:8080/?code=XK2RfoAaUPwlKmal&state=xbc

We keep this code and we put it on this query for getting access token :

curl --location --request POST 'https://dev-0-77r6yl.auth0.com/oauth/token' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_id=hSbuxfeTI25DHp0F9OPW1XbQe42ONiD6' \
--data-urlencode 'client_secret=XXXXX' \
--data-urlencode 'code=XK2RfoAaUPwlKmal' \
--data-urlencode 'redirect_uri=http://localhost:8080/'

After executed the request, i have my access token generated and when i put this one on header of https://dev-0-77r6yl.auth0.com/userinfo, i get this result :

{
    "sub": "google-oauth2|116720606290557643328"
}

So i compare this manual authentification flow with Quarkus one, when we loop i have this group of request executed :

image

My application.properties is like this :

quarkus.oidc.auth-server-url=https://dev-0-77r6yl.auth0.com
quarkus.oidc.client-id=hSbuxfeTI25DHp0F9OPW1XbQe42ONiD6
quarkus.oidc.credentials.secret=XXXXXX
quarkus.oidc.token.lifespan-grace=10
quarkus.oidc.roles.source=accesstoken
quarkus.oidc.application-type=web-app
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
quarkus.log.level=ALL

Something it's blocked here with this request on Quarkus :

image

The error in console log, it's about decoding an opaque token i suppose, but i don't really know why.

2020-11-02 01:02:09,319 FINEST [io.ver.ext.aut.oau.imp.OAuth2UserImpl] (vert.x-eventloop-thread-20) Cannot decode token:: java.lang.RuntimeException: Not enough or too many segments
    at io.vertx.ext.jwt.JWT.decode(JWT.java:261)
    at io.vertx.ext.auth.oauth2.impl.OAuth2UserImpl.decodeToken(OAuth2UserImpl.java:182)
    at io.vertx.ext.auth.oauth2.impl.OAuth2UserImpl.decodeToken(OAuth2UserImpl.java:156)
    at io.vertx.ext.auth.oauth2.impl.OAuth2UserImpl.init(OAuth2UserImpl.java:73)
    at io.vertx.ext.auth.oauth2.impl.OAuth2UserImpl.setAuthProvider(OAuth2UserImpl.java:100)
    at io.vertx.ext.auth.oauth2.impl.OAuth2UserImpl.<init>(OAuth2UserImpl.java:49)
    at io.vertx.ext.auth.oauth2.impl.OAuth2TokenImpl.<init>(OAuth2TokenImpl.java:55)
    at io.vertx.ext.auth.oauth2.impl.flow.AuthCodeImpl.lambda$getToken$0(AuthCodeImpl.java:87)
    at io.vertx.ext.auth.oauth2.impl.flow.AbstractOAuth2Flow.lambda$getToken$0(AbstractOAuth2Flow.java:148)
    at io.vertx.ext.auth.oauth2.impl.OAuth2API.lambda$null$1(OAuth2API.java:129)
    at io.vertx.core.http.impl.HttpClientResponseImpl$BodyHandler.notifyHandler(HttpClientResponseImpl.java:292)
    at io.vertx.core.http.impl.HttpClientResponseImpl.lambda$bodyHandler$0(HttpClientResponseImpl.java:193)
    at io.vertx.core.http.impl.HttpClientResponseImpl.handleEnd(HttpClientResponseImpl.java:248)
    at io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.lambda$beginResponse$0(Http1xClientConnection.java:483)
    at io.vertx.core.streams.impl.InboundBuffer.handleEvent(InboundBuffer.java:237)
    at io.vertx.core.streams.impl.InboundBuffer.write(InboundBuffer.java:127)
    at io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.endResponse(Http1xClientConnection.java:502)
    at io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.access$000(Http1xClientConnection.java:241)
    at io.vertx.core.http.impl.Http1xClientConnection.handleResponseEnd(Http1xClientConnection.java:641)
    at io.vertx.core.http.impl.Http1xClientConnection.handleHttpMessage(Http1xClientConnection.java:601)
    at io.vertx.core.http.impl.Http1xClientConnection.handleMessage(Http1xClientConnection.java:575)
    at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:366)
    at io.vertx.core.impl.EventLoopContext.execute(EventLoopContext.java:43)
    at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:229)
    at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:163)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1518)
    at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1267)
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1314)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:440)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:829)
sberyozkin commented 3 years ago

@majonga88 I'm getting a bit confused. I think you said that it starts looping if you configure it to request the userinfo, but when you try to set the source of roles to access token it is 404. Can you clarify please ? What happens if you remove quarkus.oidc.roles.source=accesstoken And does Auth0 support the introspection of the tokens ? thanks

majonga88 commented 3 years ago

@sberyozkin If i remove this quarkus.oidc.roles.source=accesstoken it works, i go to Auth0 authentification page and after it redirect to the index.html.

Auth0 doesn't support the introspection of the tokens : https://community.auth0.com/t/oidc-dynamic-client-registration-token-introspection-url/37503

sberyozkin commented 3 years ago

@majonga88 OK, thanks, so all is quite clear now:

So the only way for you to pass the roles is to update Auth0 somehow to include them in the ID token.

As I said I'm going to fix the redirect loop issue which is caused by the userinfo request failure. What remains unclear though is why a user info request fails in your case.

Lets get back to this comment.

Can you type here the curl command which you use to request the userinfo with that access token. Thanks

majonga88 commented 3 years ago

@sberyozkin Thank you for that. The curl :

curl --location --request GET 'https://dev-0-77r6yl.auth0.com/userinfo' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik9UVTRNekE0TjBFM1JETXhNRVkwTTBGQk16RTVSRVEzTVVVeU9EWkNPVEk1TTBFM1JVVkRSQSJ9.eyJpc3MiOiJodHRwczovL2Rldi0wLTc3cjZ5bC5hdXRoMC5jb20vIiwic3ViIjoiZ29vZ2xlLW9hdXRoMnwxMTY3MjA2MDYyOTA1NTc2NDMzMjgiLCJhdWQiOlsiaHR0cHM6Ly9xdWlja3N0YXJ0cy9hcGkiLCJodHRwczovL2Rldi0wLTc3cjZ5bC5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNjA0MjczNDE3LCJleHAiOjE2MDQzNTk4MTcsImF6cCI6ImhTYnV4ZmVUSTI1REhwMEY5T1BXMVhiUWU0Mk9OaUQ2Iiwic2NvcGUiOiJvcGVuaWQiLCJwZXJtaXNzaW9ucyI6WyJyZWFkOmFwcG9pbnRlbWVudHMiLCJyZWFkOm1lc3NhZ2VzIl19.PSdTuujLTToIfOm6-lB1sRdNKqedSZ7OJPOeYPTc4oJVTYi6O6rqehyAbclW8A2OItziNXJNXkimUduwXab1KMqrTjWYqkkGsqKc1xRz3B7A1hPFxis3fsv2dP-qAI44lH7RS-AglD81cDxjzhkh6KVuizzBTkPdwHfHdb9a7Rd71yweM2CtX7ack9FyA0pamBaNayVKJBSA8CJGuFjNFa74204N2mk5fS6lGnzqScRQLo4f1KhcZIQOmJ5uYjjxa4SoLZcA3vTmq6RmjGn9gsXgS2-stIX8AxcAJ_G3gajsSyzvfX2VgyEFUgQzZG31A-q9sUrooDdw_OGQKK-OkA'

I will open a ticket to bring the support of introspection token in Auth0 side.

sberyozkin commented 3 years ago

@majonga88 OK, so this token is a JWT token while we are assuming you are dealing with the binary access token. In that comment where you typed a curl request to the token endpoint, what is returned, can you type it here ?

majonga88 commented 3 years ago

@sberyozkin Here is the curl request for token endpoint :

curl --location --request POST 'https://dev-0-77r6yl.auth0.com/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_id=hSbuxfeTI25DHp0F9OPW1XbQe42ONiD6' \
--data-urlencode 'client_secret=XXXXX' \
--data-urlencode 'code=XK2RfoAaUPwlKmal' \
--data-urlencode 'redirect_uri=http://localhost:8080/'

And result :

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik9UVTRNekE0TjBFM1JETXhNRVkwTTBGQk16RTVSRVEzTVVVeU9EWkNPVEk1TTBFM1JVVkRSQSJ9.eyJpc3MiOiJodHRwczovL2Rldi0wLTc3cjZ5bC5hdXRoMC5jb20vIiwic3ViIjoiZ29vZ2xlLW9hdXRoMnwxMTY3MjA2MDYyOTA1NTc2NDMzMjgiLCJhdWQiOlsiaHR0cHM6Ly9xdWlja3N0YXJ0cy9hcGkiLCJodHRwczovL2Rldi0wLTc3cjZ5bC5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNjA0MjczNDE3LCJleHAiOjE2MDQzNTk4MTcsImF6cCI6ImhTYnV4ZmVUSTI1REhwMEY5T1BXMVhiUWU0Mk9OaUQ2Iiwic2NvcGUiOiJvcGVuaWQiLCJwZXJtaXNzaW9ucyI6WyJyZWFkOmFwcG9pbnRlbWVudHMiLCJyZWFkOm1lc3NhZ2VzIl19.PSdTuujLTToIfOm6-lB1sRdNKqedSZ7OJPOeYPTc4oJVTYi6O6rqehyAbclW8A2OItziNXJNXkimUduwXab1KMqrTjWYqkkGsqKc1xRz3B7A1hPFxis3fsv2dP-qAI44lH7RS-AglD81cDxjzhkh6KVuizzBTkPdwHfHdb9a7Rd71yweM2CtX7ack9FyA0pamBaNayVKJBSA8CJGuFjNFa74204N2mk5fS6lGnzqScRQLo4f1KhcZIQOmJ5uYjjxa4SoLZcA3vTmq6RmjGn9gsXgS2-stIX8AxcAJ_G3gajsSyzvfX2VgyEFUgQzZG31A-q9sUrooDdw_OGQKK-OkA",
    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik9UVTRNekE0TjBFM1JETXhNRVkwTTBGQk16RTVSRVEzTVVVeU9EWkNPVEk1TTBFM1JVVkRSQSJ9.eyJpc3MiOiJodHRwczovL2Rldi0wLTc3cjZ5bC5hdXRoMC5jb20vIiwic3ViIjoiZ29vZ2xlLW9hdXRoMnwxMTY3MjA2MDYyOTA1NTc2NDMzMjgiLCJhdWQiOiJoU2J1eGZlVEkyNURIcDBGOU9QVzFYYlFlNDJPTmlENiIsImlhdCI6MTYwNDI3MzQxNywiZXhwIjoxNjA0MzA5NDE3fQ.sPnmcBlRkXFlwRkd9H1YtKLDNMQAdLhQYMYUY2_SNoFNqClYdG8hxrywbwMYQDPmAWBhuV97kMvuIsPy7lhPCm9jkz2-UpOwtaNvZDff7a_D7yTBqAPSj-tfIiD9JDPOOIzs0y2ri_K_RE-nnKvyuPc91vLWh3aUaJVsiPBoi87Ntb5Xeik9iHvAgdbtVNfl7EbQ7AMJeu2_3pE8s7562DPFCWikvgFnZuoszm8KGHppnbMwUPQOi-IUlLrO-8f3OIBHEOFDi3NwX3j7OM6nMHjeKdvxlBclw1cXbHSUFRDdKWOCSqXDv2RvAFUyN5qSU5GYB13nhyPdsKLKndOz7w",
    "scope": "openid",
    "expires_in": 86400,
    "token_type": "Bearer"
}
sberyozkin commented 3 years ago

@majonga88 OK, thanks, so both ID and access tokens are JWT tokens and indeed it is the access token which contains a custom permissions claims.

Did you say you had 403 when you were setting quarkus.oidc.roles.source=accesstoken with your own demo ? Can you try it again, and make sure you set quarkus.oidc.roles.role-claim-path=permissions and have @RolesAllowed("read:appointements", "read:messages") ?

This access token also has a scope to access a user info endpoint.

In order to verify the JWT access token it is sufficient to have a local JWK set containing a matching kid and no introspection endpoint is needed. So what we need to verify next is whether a local JWK set is populated and if it does contain the matching key. The other thing that needs to be confirmed if whether the discovery document returned from Auth0 contains the userinfo endpoint path, as well as the jwk endpoint path. Can you add a breakpoint, one is here and check the content of the OAuth2AuthProviderImpl auth object ? You will find there the JWK key set, as well as the discovered endpoint paths. Give it a go please and then we will be able to finally figure out what may be going wrong.

majonga88 commented 3 years ago

@sberyozkin

Did you say you had 403 when you were setting quarkus.oidc.roles.source=accesstoken with your own demo ?

No i don't have any 403 appears in my chrome console when i do authentification :

image

Can you try it again, and make sure you set quarkus.oidc.roles.role-claim-path=permissions and have @RolesAllowed("read:appointements", "read:messages") ?

I try it but i have the same behaviour, it loop on authentification with this error : Cannot decode token:: java.lang.RuntimeException: Not enough or too many segments

Can you add a breakpoint, one is here and check the content of the OAuth2AuthProviderImpl auth object ?

Here is the result.

The config part in auth object :

image

The jwk part in auth object :

Capture2

sberyozkin commented 3 years ago

@majonga88 403 is mentioned here: https://github.com/quarkusio/quarkus/issues/13023#issuecomment-719957210

What was that about then ?

OK, thanks for debugging it, all seems to be correct, so where is Not enough or too many segments coming from ? It can only happen if a token is not a signed JWT token. It just looks like what you get with curl does not correspond to what you get with Quarkus. Since you are debugging it, can you please set a breakpoint here - this will show you the token values, and here and see what happens ?

Thanks

majonga88 commented 3 years ago

@sberyozkin The 403 appears when i execute this request (http://localhost:8080/?code=57VpewRDgvBCLIAs&state=457304d5-9917-484a-853c-e0d6ee393b50) directly on browser it's just a check for me to see what's going on, it's not an issue on Quarkus side here.

For debugging :

Since you are debugging it, can you please set a breakpoint here

Before this breakpoint i already have the error : Cannot decode token:: java.lang.RuntimeException: Not enough or too many segments

Then here :

context.put("access_token", opaqueAccessToken);

I have an opaqueAccessToken : wilUz6rDryuB0NOAr30PaDDhGYKU6CDT

and here and see what happens :

On this portion of code :

if (request.getToken() instanceof IdTokenCredential && (resolvedContext.oidcConfig.authentication.verifyAccessToken || resolvedContext.oidcConfig.roles.source.orElse((Object)null) == Source.accesstoken)) {
        vertxContext.put("code_flow_access_token_result", verifyCodeFlowAccessToken(vertxContext, request, resolvedContext));
}

The condition is true and we execute this function verifyCodeFlowAccessToken(vertxContext, request, resolvedContext), an AuthenticationFailedExceptioni've never seen before appears here : io.vertx.core.impl.NoStackTraceThrowable: Invalid path. The reason is we go into OAuth2TokenImpl on authenticate method and we introspect the opaque token but we don't have an intropection path in our configuration (application.properties) because Auth0 doesn't support introspection.

Regarding the documentation of Auth0, about opaque token management they said this :

Opaque access tokens are tokens in a proprietary format that you cannot access and typically contain some identifier to information in a server's persistent storage. To validate an opaque token, the recipient of the token needs to call the server that issued the token. In Auth0's case, opaque tokens can be used with the /userinfo endpoint to return a user's profile. If you receive an opaque Access Token, you don't need to validate it. You can use it with the /userinfo endpoint, and Auth0 takes care of the rest.

Reference : https://auth0.com/docs/tokens/access-tokens

So, for me the opaque token support is possible on Quarkus if we use the /userinfo endpoint.

sberyozkin commented 3 years ago

@majonga88

So if you have an opaqueAccessToken : wilUz6rDryuB0NOAr30PaDDhGYKU6CDT then why are you posting the curl examples where JWT tokens are used :-) ? We are just going in circles while in fact you have an opaque token which is impossible to verify because Auth0 has no introspection endpoint. So setting the access token as the source of roles in your case is just not going to work for now as we can't get anything out of it anyway.

Re the userinfo - we don;t verify the access token if you need to get the userinfo, can you try this opaque access token to get the userinfo from curl ? The docs you have linked to is one thing, but whether this opaque access token is allowed to do it or not needs to be verified. Please type here the curl command, thanks

sberyozkin commented 3 years ago

Or set a breakpoint here

majonga88 commented 3 years ago

@sberyozkin Sorry, I withdraw what I said previously, for the 403. I got this error when i tried to authenticate with userinfo parameter. For this, i change quarkus.oidc.roles.source=accesstoken to quarkus.oidc.roles.source=userinfo, and i changed the signing algorithm RS256 to HS256 on Auth0.

And i got this 403 when the application trying to redirecting on this url : http://localhost:8080/?code=KhcuMPIzqaSfWtbt&state=c308ebc3-367b-4dfe-b572-1993e34c1481

can you try this opaque access token to get the userinfo from curl ?

curl --location --request GET 'https://dev-0-77r6yl.auth0.com/userinfo' \
--header 'Authorization: Bearer wilUz6rDryuB0NOAr30PaDDhGYKU6CDT' 

I got this result :

{
    "sub": "google-oauth2|116720606290557643328"
}

Or set a breakpoint here

I didn't go into. I'm stopped before on this url : http://localhost:8080/?code=KhcuMPIzqaSfWtbt&state=c308ebc3-367b-4dfe-b572-1993e34c1481 with an 403.

sberyozkin commented 3 years ago

@majonga88 np, OK, 403 is logical because as you see, the userinfo response contains no roles information at all. The likely reason you did not get the breakpoint activating is because you may have not set quarkus.oidc.authentication.user-info-required. But I'd not expect anything else but 403 here anyway, so lets not continue investigating it.

But what really remains to figure out in this issue is when exactly you are getting this redirection loop. I thought it was caused by the failure in the userinfo request but I'm not sure now. Can you please reproduce that, show which configuration you used, and then I'll ask you where to set a breakpoint thanks

majonga88 commented 3 years ago

Ok so i retest it, i add quarkus.oidc.authentication.user-info-required=true and i go when i do breakpoint here

I got this token : zlkArY7A_VASvQq5c7aMv-Ut9gPj19fa

I got in there : OAuth2TokenImpl#userInfo and the request is : https://dev-0-77r6yl.auth0.com/userinfo with those headers :

{"Authorization":"Bearer B24Rol6rFLBx-yz1FUG10iUptyqO2Ntl","Accept":"application/json,application/x-www-form-urlencoded;q=0.9"}

And the result was :

{"sub":"google-oauth2|116720606290557643328"}

But i saw here on OAuth2UserImpl#init, we cannot decode the principal on here : this.accessToken = this.decodeToken("access_token");

And when i got through this OAuth2UserImpl#decodeToken, we go here :

if (!trust) {
        return this.provider.getJWT().decode((String)opaque);
}

And we got the exception : java.lang.RuntimeException: Not enough or too many segments

My configuration now is this :

quarkus.oidc.auth-server-url=https://dev-0-77r6yl.auth0.com
quarkus.oidc.client-id=H0rm1TvIAz2Ge3kxX8PObxQusguzAvmw
quarkus.oidc.credentials.secret=Togg_7NLhscHugZc8r6KnQJuzhY4ORgIYr61Dw5r0pyyYG5CqjlNbfdBm5wssRLw
quarkus.oidc.token.lifespan-grace=10
quarkus.oidc.roles.source=userinfo
quarkus.oidc.authentication.user-info-required=true
quarkus.oidc.roles.role-claim-path=permissions
quarkus.oidc.application-type=web-app
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
quarkus.log.level=ALL
sberyozkin commented 3 years ago

@majonga88 Good you've confirmed the user info itself can be retrieved, but lets stay focused now on the issue of the loop. As I've already said quarkus.oidc.roles.source=userinfo does not make sense in your case. I'd really like to close this issue now :-), but I'm still interested to find out under what conditions it starts looping. Try to reproduce it

majonga88 commented 3 years ago

@sberyozkin I'm confused when you said "does not make sense in your case" for userinfo, because Auth0 doesn't bring any introspection path for checking opaque token, and they promote to use userInfo instead, so i go for it.

Anyway, i checked again with this parameter quarkus.oidc.roles.source=accesstoken and i didn't see any break when the redirection is executed on Quarkus side. My idea is Auth0 force to redirect on the login page when something goes wrong.

I will close the issue, but i can't still use your framework with Auth0 at this point when i'm using scopes, while it works on Spring Boot, regading this example : https://auth0.com/docs/quickstart/backend/java-spring-security5/01-authorization?download=true

Thank you to investigate with me :)

sberyozkin commented 3 years ago

@majonga88

I'm confused when you said "does not make sense in your case" for userinfo

You are asking Quakus OIDC to use the content returned from the user info endpoint as the source of roles, and as you have seen yourself, this content has no information about the roles. Likewise, earlier on, where you were asking Quarkus OIDC to use the access token as a source of roles, again you confirmed the token was opaque/binary and Auth0 had no introspection endpoint to return that content.

So I don't know how it can work with SpringBoot if Auth0 does not include the roles in the userinfo response and it can not return the content of the binary access token but good luck with it :-)

gsmet commented 3 years ago

@sberyozkin I think it would be worth investigating what Spring is doing and we are not.

sberyozkin commented 3 years ago

@gsmet, and @majonga88, Hi, I'm sorry but given what @majonga88 has confirmed I don't believe @majonga88's setup can work with SpringBoot. What I can imagine is that @majonga88's setup in the SpringBoot project is entirely different to the Quarkus project setup.

The reason I think it can be the case is that @majonga88 has posted the working example with SpringBoot showing that the access token is in the JWT format - and also confirmed at the same time that the same access token is in fact in a binary format in a Quarkus project, therefore the access token can not be used as the source of the roles as Auth0 does not support the binary token introspection.

The other point which has been discussed is the acquisition of the roles from the user info endpoint. And again, @majonga88 has confirmed that the user info response has no roles in it at all, while also confirmed, that Quarkus OIDC can successfully get the userinfo content on its own.

So, as I said, given that in the Quarkus project 1) the access token is binary and Auth0 can not return the introspection response for the binary tokens and 2) the userinfo response has no roles in it, I don't think SpringBoot or any other OIDC provider implementation can get it working.

It is possible that there has been some confusion. But I've given my best here to help @majonga88 who is welcome to create concrete issues.

majonga88 commented 3 years ago

@sberyozkin @gsmet I think the best way to handle fully Auth0 integration in Quarkus, is to provide an example like you doing for Keycloak. I think many people will asks same questions around Quarkus integration with tiers providers like Okta or Auth0.

@sberyozkin Maybe when i testing it, it appends, if you try on your own, you can see something that i missed (i hope). I send you in zulip all credentials to test if you wanted to try and the project.

I strongly have to say again, i don't know why scopes working on Spring Boot and not in Quarkus with the same Auth0 configuration. I kindly remark, i'm not an expert on this, i'm just a friendly user on OIDC on both Quarkus and SpringBoot and i just trying to understand what append.

sberyozkin commented 3 years ago

@majonga88 We have both Auth0 and Okta users confirming Quarkus OIDC works for them. The idea of having more provider specific integration examples is good and I'd encourage you to work on the Auth0 one. Start from something simple and we can move from there (copy and paste the existing web-app quickstart).

I strongly have to say again, i don't know why scopes working on Spring Boot and not in Quarkus with the same Auth0 configuration

See the problem we have been having in this issue is that we seem to can't understand each other :-). I'm sorry but I don't have time to try to reproduce something that, as per my last feedback, can't even work. Many other concrete issues and enhancements have to be addressed.

Given my previous comment,

The reason I think it can be the case is that @majonga88 has posted the working example with SpringBoot showing that the access token is in the JWT format - and also confirmed at the same time that the same access token is in fact in a binary format in a Quarkus project, therefore the access token can not be used as the source of the roles as Auth0 does not support the binary token introspection.

What can you say about this one ?

The other point which has been discussed is the acquisition of the roles from the user info endpoint. And again, @majonga88 has confirmed that the user info response has no roles in it at all, while also confirmed, that Quarkus OIDC can successfully get the userinfo content on its own.

And this one ?

So, as I said, given that in the Quarkus project 1) the access token is binary and Auth0 can not return the introspection response for the binary tokens and 2) the userinfo response has no roles in it, I don't think SpringBoot or any other OIDC provider implementation can get it working.

And this one ?

In this issue and in the previous issue you have opened we have investigated and confirmed:

So what exactly is not clear as to why Quarkus can't get any roles ?

majonga88 commented 3 years ago

@sberyozkin Nevermind, i found my solution.

cihati commented 3 years ago

@majonga88 would you mind sharing the solution?

majonga88 commented 3 years ago

@cihati I switch to Spring Boot, I was inspired by this example : https://auth0.com/blog/securing-spring-boot-apis-and-spas-with-oauth2/

And the gihub link : https://github.com/auth0-blog/spring-boot-oauth2

And my example based on this project : https://github.com/majonga88/sb-security-oauth2

Mugumo commented 1 year ago

@cihati I switch to Spring Boot, I was inspired by this example : https://auth0.com/blog/securing-spring-boot-apis-and-spas-with-oauth2/

And the gihub link : https://github.com/auth0-blog/spring-boot-oauth2

And my example based on this project : https://github.com/majonga88/sb-security-oauth2

Sadly, quarkus still doesn't work with Auth0 access tokens as a source of roles and permissions, yet it works with Spring projects. So to date, we can authenticate using auth0 but can't do much else without adding information to the idtoken via rules which isn't recommended.