Describe the bug
OIDC extension configured to use Okta OIDC is stuck in a redirect loop. The code is never exchanged for a token. The OIDC app configuration works with OIDC Debugger.
application.properties
quarkus.http.root-path=/kafka-client
quarkus.oidc.auth-server-url=https://dev-447850.okta.com
quarkus.oidc.client-id=<<Client ID>>
quarkus.oidc.credentials.secret=<<Client Secret>>
quarkus.oidc.authentication.scopes=openid
quarkus.oidc.application-type=web-app
quarkus.oidc.authentication.redirect-path=/kafka-client
Network redirects:
302 | GET | localhost:8080 | secured | document | plain | 402 B | 0 B
-- | -- | -- | -- | -- | -- | -- | --
302 | GET | dev-447850.okta.com | authorize?redirect_uri=http://localhost:8080/kafka-client&state=27ab84bf-e2b8-4c91-af6a-0b448cd6548c&scope=openid+openid&response_type=code&client_id=0oa25vnmhPszBCA3R4x6 | document | plain | 2.49 KB | 0 B
302 | GET | localhost:8080 | kafka-client?code=jp_7_w68G7w0UmKV61Hd&state=27ab84bf-e2b8-4c91-af6a-0b448cd6548c | document | plain | 181 B | 0 B
302 | GET | localhost:8080 | secured?pathChecked=true&code=jp_7_w68G7w0UmKV61Hd&state=27ab84bf-e2b8-4c91-af6a-0b448cd6548c | document | plain | 402 B | 0 B
302 | GET | dev-447850.okta.com | authorize?redirect_uri=http://localhost:8080/kafka-client&state=1f447861-ef32-4e6a-8d3d-29bc0963625f&scope=openid+openid&response_type=code&client_id=0oa25vnmhPszBCA3R4x6 | document | plain | 2.49 KB | 0 B
302 | GET | localhost:8080 | kafka-client?code=nVqlC135IJMoFhRxR-8C&state=1f447861-ef32-4e6a-8d3d-29bc0963625f | document | plain | 181 B | 0 B
302 | GET | localhost:8080 | secured?pathChecked=true&code=nVqlC135IJMoFhRxR-8C&state=1f447861-ef32-4e6a-8d3d-29bc0963625f | document | plain | 402 B | 0 B
302 | GET | dev-447850.okta.com | authorize?redirect_uri=http://localhost:8080/kafka-client&state=226998f7-305f-47e9-9bf0-58e35f3652d9&scope=openid+openid&response_type=code&client_id=0oa25vnmhPszBCA3R4x6 | document | plain | 2.49 KB | 0 B
302 | GET | localhost:8080 | kafka-client?code=SOe9kOCCfwtnuBcfsOYX&state=226998f7-305f-47e9-9bf0-58e35f3652d9 | document | plain | 181 B | 0 B
Environment (please complete the following information):
uname -a or ver:java -version:Additional context
Project created with this command:
mvn io.quarkus:quarkus-maven-plugin:1.2.0.Final:create \
-DprojectGroupId=com.okta \
-DprojectArtifactId=quarkus-client \
-DclassName="com.okta.quarkusclient.SecureResource" \
-Dextensions="quarkus-smallrye-reactive-messaging-kafka, oidc"
One resource:
package com.okta.quarkusclient;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/secured")
@RolesAllowed({"Everyone"})
public class SecureResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
}
A little more info, debugging CodeAuthenticationMechanism reveals this error:
Unauthorized: {"error":"invalid_request","error_description":"Cannot supply multiple client credentials. Use one of the following: credentials in the Authorization header, credentials in the post body, or a client_assertion in the post body."}
/cc @sberyozkin @pedroigor
@moksamedia Hi, thanks for the thorough analysis, I believe it has been fixed with Quarkus https://github.com/quarkusio/quarkus/tree/1.3.0.Alpha1, can you please try it ?
@sberyozkin That does work, thanks.
For posterity, here are the application.properties settings I used. I had to change the Okta auth server URL from https://dev-447850.okta.com to https://dev-447850.okta.com/oauth2/default.
quarkus.http.root-path=/kafka-client
quarkus.oidc.auth-server-url=https://dev-447850.okta.com/oauth2/default
quarkus.oidc.client-id={cliendId}
quarkus.oidc.credentials.secret={cliendSecret}
quarkus.oidc.authentication.scopes=openid,profile
quarkus.oidc.application-type=web-app
quarkus.oidc.authentication.redirect-path=/kafka-client
This is using Role-based auth on a /kafka-client/secured endpoint.
@Path("/secured")
@RolesAllowed({"Everyone"})
public class SecureResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
}
@sberyozkin Two questions:
1) when is 1.3.0 expected to be released?
2) I saw that this was covered in another ticked, but are you planning on updating the redirect_uri parameter so that it can be a static URL that's not a child of the request URI? Something more like /oauth/callback instead of the app base URL? Seems like a strange way to do that.
@moksamedia Thanks for the update.
Did you have to change the Okta endpoint address because it was not responding to the discovery request ? Then indeed, changing the address is required. The alternative option is to keep the original address but to use introspection-path and jwks-path properties though we actually haven't had any confirmation from the users they work.
Can you please check if the alternative option works and update #5827 if not ?
when is 1.3.0 expected to be released?
I don't know, hopefully soon enough.
I saw that this was covered in another ticked, but are you planning on updating the redirect_uri parameter so that it can be a static URL that's not a child of the request URI? Something more like /oauth/callback instead of the app base URL? Seems like a strange way to do that.
Nonetheless it worked for some users, and it really depends on the way the protected application interacts with the users. The primary purpose was to ensure the clients can be whitelisted based on the specific redirect URI value as asked by Aaron.
But yes it was too restrictive. A new restore-path-after-redirect property is now available and if set to false then the user would be returned to whatever redirect-path relative property is set.
Hope it helps, I'd like to close this issue soon, likely tomorrow due to a time difference
I only added the thing about changing the Okta endpoint so that if someone else found this trying to figure things out, they'd have correct info. It was my mistake. I don't think it's a problem with the OIDC extension. I'll close the ticket.
Hey @moksamedia @gsmet
I'am testing the 1.3.0.Alpha2 version with oidc security dependency.
When I enter the login/Password, i have the same behaviour with cyclic 302 between the Auth Server SSO (forgerock) and my front, and at the end nothing is displayed.

My config properties :
quarkus.oidc.auth-server-url=https://sso-XXXXXXXXXXXX/oauth2/preprod
quarkus.oidc.client-id=XXXXXXXXXXXXXXX
quarkus.oidc.application-type=web-app
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
quarkus.oidc.introspection-path=/.well-known/openid-configuration
quarkus.oidc.authentication.scopes=openid,profile,email
quarkus.oidc.authentication.redirect-path=/login/oauth2/code/oidc
quarkus.http.cors=true
quarkus.oidc.credentials.secret=XXXXXXXXXXXXXXXXXX
Another thing, that i could not explain, is if I put a breakPoint on line 186 io.quarkus.oidc.runtime.CodeAuthenticationMechanism.java and after the login a wait 3 sec. All are ok and the cyclic behaviour disappears.

And in log, i have this :
2020-02-28 01:41:32,076 WARNING [io.ver.cor.imp.BlockedThreadChecker] (vertx-blocked-thread-checker) Thread Thread[vert.x-eventloop-thread-1,5,main]=Thread[vert.x-eventloop-thread-1,5,main] has been blocked for 3002 ms, time limit is 2000 ms: io.vertx.core.VertxException: Thread blocked
at io.quarkus.oidc.runtime.CodeAuthenticationMechanism.lambda$performCodeFlow$1(CodeAuthenticationMechanism.java:186)
at io.quarkus.oidc.runtime.CodeAuthenticationMechanism$$Lambda$584/0x00000008006a7840.handle(Unknown Source)
at io.vertx.ext.auth.oauth2.impl.OAuth2AuthProviderImpl.lambda$authenticate$2(OAuth2AuthProviderImpl.java:249)
at io.vertx.ext.auth.oauth2.impl.OAuth2AuthProviderImpl$$Lambda$585/0x00000008006a7c40.handle(Unknown Source)
at io.vertx.ext.auth.oauth2.impl.flow.AuthCodeImpl.lambda$getToken$0(AuthCodeImpl.java:93)
at io.vertx.ext.auth.oauth2.impl.flow.AuthCodeImpl$$Lambda$586/0x00000008006a7040.handle(Unknown Source)
at io.vertx.ext.auth.oauth2.impl.flow.AbstractOAuth2Flow.lambda$getToken$0(AbstractOAuth2Flow.java:148)
at io.vertx.ext.auth.oauth2.impl.flow.AbstractOAuth2Flow$$Lambda$587/0x00000008006a7440.handle(Unknown Source)
at io.vertx.ext.auth.oauth2.impl.OAuth2API.lambda$null$1(OAuth2API.java:129)
at io.vertx.ext.auth.oauth2.impl.OAuth2API$$Lambda$522/0x00000008005c9c40.handle(Unknown Source)
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$$Lambda$523/0x0000000800640040.handle(Unknown Source)
at io.vertx.core.http.impl.HttpClientResponseImpl.handleEnd(HttpClientResponseImpl.java:248)
at io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.lambda$beginResponse$0(Http1xClientConnection.java:480)
at io.vertx.core.http.impl.Http1xClientConnection$StreamImpl$$Lambda$519/0x00000008005ca040.handle(Unknown Source)
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:499)
at io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.access$000(Http1xClientConnection.java:237)
at io.vertx.core.http.impl.Http1xClientConnection.handleResponseEnd(Http1xClientConnection.java:634)
at io.vertx.core.http.impl.Http1xClientConnection.handleHttpMessage(Http1xClientConnection.java:584)
at io.vertx.core.http.impl.Http1xClientConnection.handleMessage(Http1xClientConnection.java:566)
at io.vertx.core.net.impl.VertxHandler$$Lambda$517/0x00000008005cb440.handle(Unknown Source)
at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:369)
at io.vertx.core.impl.EventLoopContext.execute(EventLoopContext.java:43)
at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:232)
at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:173)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:316)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1470)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1219)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1266)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:493)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:432)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:271)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:377)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:363)
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.[email protected]/java.lang.Thread.run(Thread.java:834)
Do you have a solution for me please ?
Thanks.
I'm still having an issue getting the OIDC client to work with Okta. I'm using 1.3.0.CR2. I created an app using the following command:
mvn io.quarkus:quarkus-maven-plugin:1.3.0.CR2:create \
-DplatformVersion=1.3.0.CR2 -DplatformArtifactId=quarkus-bom \
-DprojectGroupId=com.okta -DprojectArtifactId=quarkus-client \
-DclassName="com.okta.quarkusclient.SecureResource" \
-Dextensions="quarkus-smallrye-reactive-messaging-kafka,oidc,quarkus-resteasy-qute"
Then I created a "Web" app on Okta and set the login redirect URI to be http://localhost:8080. I copy/pasted the settings into application.properties:
quarkus.oidc.auth-server-url=https://{OktaDomain}/oauth2/default
quarkus.oidc.client-id={ClientId}
quarkus.oidc.credentials.secret={ClientSecret}
quarkus.oidc.authentication.scopes=openid,profile
quarkus.oidc.application-type=web-app
quarkus.oidc.authentication.redirect-path=/
quarkus.oidc.cookie-path=/
It redirects me to log in successfully, but when it comes back to the app, it gives me a 401.

@mraible I have the same problem.
I specified the redirect-path but when it's called this url don't have the HTTPS protocol.
It is the good url but without the S of https.
My configuration :
quarkus.oidc.auth-server-url=https://MYURL
quarkus.oidc.application-type=web-app
quarkus.oidc.introspection-path=/.well-known/openid-configuration
quarkus.oidc.authentication.scopes=profile,email,myroles
quarkus.oidc.authentication.redirect-path=/login/oauth2/code/oidc
quarkus.http.cors=true
quarkus.oidc.authentication.restore-path-after-redirect=true
quarkus.oidc.credentials.client-secret.method=post
quarkus.oidc.credentials.client-secret.value={ClientSecret}
quarkus.oidc.client-id={ClientId}
The location in request is :_
https://MYURL/authorize?redirect_uri=http%3A%2F%2Fmysample.toto.fr%2Flogin%2Foauth2%2Fcode%2Foidc
Expected location is :
https://MYURL/authorize?redirect_uri=https%3A%2F%2Fmysample.toto.fr%2Flogin%2Foauth2%2Fcode%2Foidc
Do you have a solution for me please?
I use 1.3.1.Final Quarkus version.
Thanks.