Repository: quarkusio/quarkus
Issue: Recurring redirects in OIDC against Azure AD

### Describe the bug

Hey team,

I am trying to enable OIDC security for my web app (`authorization_code` flow) with Azure AD being the identity provider. The problem is that endpoint declaration like below fails with recurring redirects:

```java
@GET
@RolesAllowed("admin-role")
public Response doSmth() {}
```

The error flow goes as follows:
1. The request gets routed to the endpoint.
2. Authentication mechanism kicks in.
3. I get first proper redirect to the login page of the IDP, enter the data and press "ok".
5. Redirects start firing endlessly and are effectively killed by Chrome, endpoint returns `401`.

The logs aren't too helpful and look like this:
```txt
2021-09-23 18:07:40,537 DEBUG [org.jbo.res.res.i18n] (executor-thread-0) RESTEASY002315: PathInfo: /tellme/admin
2021-09-23 18:07:40,538 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (executor-thread-0) Authentication request redirect_uri parameter: http://localhost:8080/tellme/admin
2021-09-23 18:07:40,538 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (executor-thread-0) q_auth cookie 'max-age' parameter is set to 1800
2021-09-23 18:07:40,722 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-4) Token request redirect_uri parameter: http://localhost:8080/tellme/admin
2021-09-23 18:07:41,068 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-4) q_session cookie 'max-age' parameter is set to 3900
2021-09-23 18:07:41,068 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-4) Final redirect URI: http://localhost:8080/tellme/admin
2021-09-23 18:07:41,076 DEBUG [org.jbo.res.res.i18n] (executor-thread-0) RESTEASY002315: PathInfo: /tellme/admin
2021-09-23 18:07:41,077 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (executor-thread-0) Authentication request redirect_uri parameter: http://localhost:8080/tellme/admin
2021-09-23 18:07:41,077 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (executor-thread-0) q_auth cookie 'max-age' parameter is set to 1800
2021-09-23 18:07:41,234 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-4) Token request redirect_uri parameter: http://localhost:8080/tellme/admin
2021-09-23 18:07:41,578 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-4) q_session cookie 'max-age' parameter is set to 3900
2021-09-23 18:07:41,579 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-4) Final redirect URI: http://localhost:8080/tellme/admin
2021-09-23 18:07:42,856 DEBUG [io.qua.oid.run.CodeAuthenticationMechanism] (vert.x-eventloop-thread-4) The state cookie is missing after a redirect from IDP, authentication has failed
```

It seems to me like something goes wrong with how `redirect_uri` parameter is passed and treated by Azure. The value of the parameter seems to be valid and does not change between redirects, though.

### Expected behavior

Once I log in on the IDP page, the browser redirects me to a URI set in the `redirect_uri` parameter, which should match the endpoint I hit.

### Actual behavior

Once I log in on the IDP page I get redirected to the endpoint I hit.

### How to Reproduce?

To reproduce:

**1. Create a simple quarkus app with Resteasy and OIDC**

The only thing that matters is that the app's controller class should have an RBAC-protected endpoint. 

The contents of `application.properties`:
```txt
quarkus.oidc.auth-server-url=https://login.microsoftonline.com/TENANT_ID/v2.0
quarkus.oidc.application-type=web_app
quarkus.oidc.client-id=CLIENT_ID
quarkus.oidc.credentials.secret=CLIENT_SECRET
quarkus.oidc.authentication.scopes=offline_access
```

**2. Create an App in Azure, create the roles and permissions.**

In Azure Portal:
1. Create a new Azure app at Azure Active Directory -> App Registrations -> New Registration.
2. From the screen at Azure Active Directory -> App Registrations -> "your-app-name"
    * copy "Application ID" to `CLIENT_ID`, "Directory ID" to `TENANT_ID` placeholders in `application.properties` above.
    * press "Client credentials", generate a secret and replace `CLIENT_SECRET` placeholder.
    * press "Redirect URIs" and enter the full URI to the RBAC-protected endpoint in your app.
2. Go to Azure Active Directory -> App Registrations -> "your-app-name" -> App Roles and create at least one app role. The "Value" attribute will be the name of the role included in the ID JWT. 
3. Navigate to Azure Active Directory -> Enterprise Applications -> "your-app-name" -> Users and Groups -> Add User/Group and add your user account to the role created in p.2.
4. Go to Azure Active Directory -> App Registrations -> "your-app-name" -> API Permissions and press "Grant admin consent".

**3. Enter the name of the created role into `@RolesAllowed` on the protected endpoint.**
**4. Hit the endpoint.**

### Output of `uname -a` or `ver`

Darwin C8049 20.5.0 Darwin Kernel Version 20.5.0: Sat May  8 05:10:33 PDT 2021; root:xnu-7195.121.3~9/RELEASE_X86_64 x86_64

### Output of `java -version`

openjdk version "16.0.1" 2021-04-20 OpenJDK Runtime Environment (build 16.0.1+9-24) OpenJDK 64-Bit Server VM (build 16.0.1+9-24, mixed mode, sharing)

### GraalVM version (if different from Java)

not used

### Quarkus version or git rev

2.2.3.Final

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)

Apache Maven 3.8.1 (05c21c65bdfed0f71a2f2ada8b84da59348c4c5d)

### Additional information

_No response_

Changed files:
extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java

diff --git a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java
index 8e6e5e656fa..d72e8b7fbaa 100644
--- a/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java
+++ b/extensions/oidc/runtime/src/main/java/io/quarkus/oidc/runtime/CodeAuthenticationMechanism.java
@@ -54,6 +54,7 @@ public class CodeAuthenticationMechanism extends AbstractOidcAuthenticationMecha
     static final String SESSION_COOKIE_NAME = "q_session";
     static final String SESSION_MAX_AGE_PARAM = "session-max-age";
     static final Uni<Void> VOID_UNI = Uni.createFrom().voidItem();
+    static final Integer MAX_COOKIE_VALUE_LENGTH = 4096;
 
     private static final Logger LOG = Logger.getLogger(CodeAuthenticationMechanism.class);
 
@@ -388,9 +389,21 @@ public Uni<? extends Void> apply(Void t) {
 
                                     @Override
                                     public Void apply(String cookieValue) {
-                                        createCookie(context, configContext.oidcConfig,
+                                        String sessionCookie = createCookie(context, configContext.oidcConfig,
                                                 getSessionCookieName(configContext.oidcConfig),
-                                                cookieValue, sessionMaxAge);
+                                                cookieValue, sessionMaxAge).getValue();
+                                        if (sessionCookie.length() >= MAX_COOKIE_VALUE_LENGTH) {
+                                            LOG.warnf(
+                                                    "Session cookie length for the tenant %s is equal or greater than %d bytes."
+                                                            + " Browsers may ignore this cookie which will cause a new challenge for the authenticated users."
+                                                            + " Recommendations: 1. Set 'quarkus.oidc.token-state-manager.split-tokens=true'"
+                                                            + " to have the ID, access and refresh tokens stored in separate cookies."
+                                                            + " 2. Set 'quarkus.oidc.token-state-manager.strategy=id-refresh-tokens' if you do not need to use the access token"
+                                                            + " as a source of roles or to request UserInfo or propagate it to the downstream services."
+                                                            + " 3. Register a custom 'quarkus.oidc.TokenStateManager' CDI bean with the alternative priority set to 1.",
+                                                    configContext.oidcConfig.tenantId.get(),
+                                                    MAX_COOKIE_VALUE_LENGTH);
+                                        }
                                         fireEvent(SecurityEvent.Type.OIDC_LOGIN, securityIdentity);
                                         return null;
                                     }