Skip to content

Conversation

@BrandtKruger
Copy link
Contributor

@BrandtKruger BrandtKruger commented Jan 20, 2026

  • Add CONNECTION_ID constant to KindeRequestParameters and KindeConstants
  • Implement getConnectionId() method in KindeToken interface and BaseToken
    • Supports direct connection_id claim
    • Supports nested ext_provider.connection_id structure
  • Add connection_id parameter support to authorizationUrlWithParameters()
  • Update J2EE filter and servlet to read connection_id from request parameters
    • Works with LOGIN, REGISTER, and CREATE_ORG actions
  • Add comprehensive test coverage:
    • ConnectionIdTest: 5 tests for authorization URL generation
    • ConnectionIdTokenTest: 8 tests for token extraction
    • ConnectionIdFilterTest: J2EE filter integration tests
  • Add JWT generator helpers for testing connection_id claims

This implementation enables:

  • Passing connection_id when generating authorization URLs for social/enterprise login
  • Extracting connection_id from tokens (both direct and nested structures)
  • Automatic connection_id support in J2EE via request parameters
  • Core support available for SpringBoot (requires Spring Security config)

All changes are backward compatible and optional.

Explain your changes

Suppose there is a related issue with enough detail for a reviewer to understand your changes fully. In that case, you can omit an explanation and instead include either “Fixes #XX” or “Updates #XX” where “XX” is the issue number.

Checklist

🛟 If you need help, consider asking for advice over in the Kinde community.

Summary by CodeRabbit

  • New Features

    • Support for passing a connection_id through authentication flows (login, registration, org creation), with related URL parameters (e.g., reauth/prompt/org name) and graceful handling when absent.
    • Tokens now expose a connection_id accessor that reads direct claims or nested provider fields.
  • Tests

    • Added comprehensive tests covering connection_id propagation in URLs and extraction from various token shapes and edge cases.

✏️ Tip: You can customize this high-level summary in your review settings.

- Add CONNECTION_ID constant to KindeRequestParameters and KindeConstants
- Implement getConnectionId() method in KindeToken interface and BaseToken
  - Supports direct connection_id claim
  - Supports nested ext_provider.connection_id structure
- Add connection_id parameter support to authorizationUrlWithParameters()
- Update J2EE filter and servlet to read connection_id from request parameters
  - Works with LOGIN, REGISTER, and CREATE_ORG actions
- Add comprehensive test coverage:
  - ConnectionIdTest: 5 tests for authorization URL generation
  - ConnectionIdTokenTest: 8 tests for token extraction
  - ConnectionIdFilterTest: J2EE filter integration tests
- Add JWT generator helpers for testing connection_id claims

This implementation enables:
- Passing connection_id when generating authorization URLs for social/enterprise login
- Extracting connection_id from tokens (both direct and nested structures)
- Automatic connection_id support in J2EE via request parameters
- Core support available for SpringBoot (requires Spring Security config)

All changes are backward compatible and optional.
@BrandtKruger BrandtKruger requested a review from a team as a code owner January 20, 2026 17:29
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 20, 2026

📝 Walkthrough

Walkthrough

Adds connection_id support: new constants, token extraction API and implementation, authorization URL propagation in filters/servlets, and unit tests plus test JWT helpers to validate behavior.

Changes

Cohort / File(s) Summary
Constants
kinde-core/src/main/java/com/kinde/constants/KindeConstants.java, kinde-core/src/main/java/com/kinde/session/KindeRequestParameters.java
Added public static final CONNECTION_ID = "connection_id" constant in both classes.
Token API & Impl
kinde-core/src/main/java/com/kinde/token/KindeToken.java, kinde-core/src/main/java/com/kinde/token/BaseToken.java
Added getConnectionId() to the interface (default null) and implemented it in BaseToken. Method returns direct connection_id claim or ext_provider.connection_id if present; returns null when absent or token invalid.
J2EE Filters & Servlets
kinde-j2ee/src/main/java/com/kinde/filter/KindeAuthenticationFilter.java, kinde-j2ee/src/main/java/com/kinde/servlet/KindeAuthenticationServlet.java
Propagates connection_id via a parameters map into authorization URL generation. Adds action-specific parameter augmentation (e.g., supports_reauth=true for LOGIN, prompt=create for REGISTER/CREATE_ORG), unknown-action guard, and null-URL validation.
Test JWT Helpers
kinde-core/src/test/java/com/kinde/token/jwt/JwtGenerator.java
Added generateIDTokenWithConnectionId(String) and generateIDTokenWithExtProviderConnectionId(String) to produce tokens containing connection_id (direct or nested) for tests.
Token Tests
kinde-core/src/test/java/com/kinde/token/ConnectionIdTokenTest.java
New suite testing extraction of connection_id across scenarios: direct claim, nested ext_provider, preference rules, null/missing cases, invalid token handling, and AccessToken compatibility.
Session Tests
kinde-core/src/test/java/com/kinde/session/ConnectionIdTest.java
New tests validating generated authorization URLs include connection_id (and related params like supports_reauth, prompt, org_code, lang) across flows (login, register, code grant, create org).
Filter Tests
kinde-j2ee/src/test/java/com/kinde/filter/ConnectionIdFilterTest.java
New tests mocking HTTP/request flow to verify filter behavior with and without connection_id, ensuring proper parameter propagation and redirects.

Sequence Diagram

sequenceDiagram
    participant Client as HTTP Client
    participant Filter as KindeAuthenticationFilter / Servlet
    participant Session as KindeClientSession
    participant Auth as AuthorizationUrl Generator
    participant Token as KindeToken

    Client->>Filter: Request (may include connection_id)
    Filter->>Filter: Extract connection_id, build params map
    alt connection_id Present
        Filter->>Session: authorizationUrlWithParameters(action, params)
    else No connection_id
        Filter->>Session: login(action)
    end
    Session->>Auth: Generate authorization URL (includes params)
    Auth->>Filter: Return URL
    Filter->>Client: Redirect to authorization URL
    Client->>Auth: Complete auth, receive token
    Client->>Token: Parse token
    Token->>Token: getConnectionId() -> check claim or ext_provider.connection_id
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 twitches whiskers
A tiny id hops through the lane,
From request to token, clear and plain,
It nests, it jumps, it finds its way,
One little claim that saves the day,
Hooray for connection_id — hip, hop, hooray! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Add Connection ID support across all frameworks' clearly and concisely summarizes the main change: adding connection ID support across multiple frameworks.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@kinde-core/src/test/java/com/kinde/session/ConnectionIdTest.java`:
- Line 27: The test currently calls
KindeEnvironmentSingleton.init(KindeEnvironmentSingleton.State.ACTIVE); to set
environment state; change this to
KindeEnvironmentSingleton.init(KindeEnvironmentSingleton.State.TEST); to align
with other unit tests (KindClientBuilderTest, KindTokenFactoryImplTest,
KindClientImplTest) unless ACTIVE is intentionally required—if ACTIVE is
intentional, add a brief comment above the call explaining why ACTIVE-specific
behavior is needed for ConnectionIdTest to justify the deviation.

In `@kinde-core/src/test/java/com/kinde/token/ConnectionIdTokenTest.java`:
- Around line 52-67: Update the test testGetConnectionIdPreferDirectOverNested
to actually verify precedence by creating a token that contains both a top-level
connection_id and a nested ext_provider.connection_id with different values; add
a helper in JwtGenerator (e.g., generateIDTokenWithBothConnectionIds(String
direct, String nested)) that injects both claims, then call
IDToken.init(tokenString, true) and assert KindeToken.getConnectionId() equals
the directConnectionId, ensuring the direct claim is preferred over
ext_provider.connection_id.

In `@kinde-j2ee/src/main/java/com/kinde/filter/KindeAuthenticationFilter.java`:
- Line 88: In KindeAuthenticationFilter replace the typo in the thrown
ServletException message—change "Must proved org_name query parameter to create
an organisation." to use "provided" so the exception reads something like "Must
provide org_name query parameter to create an organisation."; update the string
in the throw statement inside KindeAuthenticationFilter to correct the wording.
- Around line 70-97: The REGISTER and CREATE_ORG branches build parameter maps
for authorizationUrlWithParameters but omit parameters that the dedicated
methods add; update the REGISTER branch to add
registerParams.put("supports_reauth", "true") alongside prompt=create (so it
matches register()), and update the CREATE_ORG branch to add
createOrgParams.put("is_create_org", "true") alongside prompt=create and
org_name (so it matches createOrg()); modify the blocks that construct
registerParams and createOrgParams in KindeAuthenticationFilter (the branches
handling KindeAuthenticationAction.REGISTER and
KindeAuthenticationAction.CREATE_ORG and the calls to
kindeClientSession.authorizationUrlWithParameters(...)) to include those keys.

In `@kinde-j2ee/src/test/java/com/kinde/filter/ConnectionIdFilterTest.java`:
- Around line 83-116: The tests fail because KindeSingleton.setInstance(...)
does not exist; either add a static test-only setter on KindeSingleton (e.g.,
public/static void setInstance(KindeSingleton instance)) and a reset method
(clearInstance or setInstance(null)) so ConnectionIdFilterTest can inject and
clean up the singleton, or update ConnectionIdFilterTest to avoid modifying
global state (use dependency injection or obtain the singleton via a
factory/mocking approach or use reflection to set the private static field).
Ensure the change exposes/uses the symbols referenced in the test
(KindeSingleton.setInstance, KindeSingleton) and add cleanup after each test to
reset the singleton.
🧹 Nitpick comments (3)
kinde-core/src/main/java/com/kinde/token/BaseToken.java (1)

93-118: Use shared constant for connection_id lookups.
Avoids drift between token claims and parameter keys.

♻️ Suggested refactor
+import com.kinde.constants.KindeConstants;
@@
-        Object connectionId = getClaim("connection_id");
+        Object connectionId = getClaim(KindeConstants.CONNECTION_ID);
@@
-            Object nestedConnectionId = extProviderMap.get("connection_id");
+            Object nestedConnectionId = extProviderMap.get(KindeConstants.CONNECTION_ID);
kinde-core/src/test/java/com/kinde/token/ConnectionIdTokenTest.java (1)

97-124: Tests 7 and 8 cover identical scenarios.

Both testGetConnectionIdWithNullExtProvider and testGetConnectionIdWithExtProviderButNoConnectionId use JwtGenerator.generateIDToken(), which produces a token without any ext_provider or connection_id claims. To test the described behavior in test 8 (ext_provider present but without connection_id), you'd need a token with an ext_provider object that has other properties but lacks connection_id.

💡 Suggested approach

Add a JwtGenerator method like generateIDTokenWithEmptyExtProvider() or generateIDTokenWithExtProviderOtherKeys() that creates an ext_provider object without connection_id, then use it in testGetConnectionIdWithExtProviderButNoConnectionId.

kinde-core/src/test/java/com/kinde/session/ConnectionIdTest.java (1)

23-32: Consider adding @AfterEach cleanup to prevent test pollution.

The @BeforeEach calls fin() then init() on the singletons, which works for sequential tests, but adding explicit cleanup improves test isolation and makes the intent clearer.

💡 Suggested addition
`@AfterEach`
public void tearDown() {
    KindeGuiceSingleton.fin();
    KindeEnvironmentSingleton.fin();
}

public void setUp() {
KindeGuiceSingleton.fin();
KindeEnvironmentSingleton.fin();
KindeEnvironmentSingleton.init(KindeEnvironmentSingleton.State.ACTIVE);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for how State.ACTIVE vs State.TEST affects behavior
rg -n -B2 -A5 'getState\(\)' --type java | head -100
rg -n 'State\.(TEST|ACTIVE)' --type java | head -50

Repository: kinde-oss/kinde-java-sdk

Length of output: 3785


🏁 Script executed:

#!/bin/bash
# Read the ConnectionIdTest.java file to understand the test context
cat -n kinde-core/src/test/java/com/kinde/session/ConnectionIdTest.java

Repository: kinde-oss/kinde-java-sdk

Length of output: 8666


Clarify the use of ACTIVE state; consider using TEST for consistency with other test classes.

This test uses State.ACTIVE while other similar tests (KindClientBuilderTest, KindTokenFactoryImplTest, KindClientImplTest) use State.TEST. The test doesn't appear to require ACTIVE-specific behavior and uses test modules. If ACTIVE is intentional, document the reason; otherwise, align with the established pattern of using TEST state in unit tests.

🤖 Prompt for AI Agents
In `@kinde-core/src/test/java/com/kinde/session/ConnectionIdTest.java` at line 27,
The test currently calls
KindeEnvironmentSingleton.init(KindeEnvironmentSingleton.State.ACTIVE); to set
environment state; change this to
KindeEnvironmentSingleton.init(KindeEnvironmentSingleton.State.TEST); to align
with other unit tests (KindClientBuilderTest, KindTokenFactoryImplTest,
KindClientImplTest) unless ACTIVE is intentionally required—if ACTIVE is
intentional, add a brief comment above the call explaining why ACTIVE-specific
behavior is needed for ConnectionIdTest to justify the deviation.

Comment on lines +52 to +67
@Test
@DisplayName("getConnectionId should prefer direct connection_id over nested ext_provider.connection_id")
public void testGetConnectionIdPreferDirectOverNested() throws Exception {
// Create a token with direct connection_id
String directConnectionId = "conn_direct_123";

// For this test, we'll use the direct one and verify it's preferred
String tokenString = JwtGenerator.generateIDTokenWithConnectionId(directConnectionId);

KindeToken kindeToken = IDToken.init(tokenString, true);

assertNotNull(kindeToken);
assertTrue(kindeToken.valid());
assertEquals(directConnectionId, kindeToken.getConnectionId(),
"getConnectionId() should prefer direct connection_id claim");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Test doesn't verify preference behavior as described.

The test name and @DisplayName indicate it should verify that direct connection_id is preferred over nested ext_provider.connection_id, but it only creates a token with a direct claim. To properly test precedence, you need a token containing both claims with different values.

Consider adding a JwtGenerator method that creates a token with both claims, then verify the direct one wins:

💡 Example test approach
`@Test`
`@DisplayName`("getConnectionId should prefer direct connection_id over nested ext_provider.connection_id")
public void testGetConnectionIdPreferDirectOverNested() throws Exception {
    String directConnectionId = "conn_direct_123";
    String nestedConnectionId = "conn_nested_456";
    
    // Need a new JwtGenerator method that adds BOTH claims
    String tokenString = JwtGenerator.generateIDTokenWithBothConnectionIds(
            directConnectionId, nestedConnectionId);
    
    KindeToken kindeToken = IDToken.init(tokenString, true);
    
    assertEquals(directConnectionId, kindeToken.getConnectionId(), 
            "getConnectionId() should prefer direct connection_id over ext_provider.connection_id");
}
🤖 Prompt for AI Agents
In `@kinde-core/src/test/java/com/kinde/token/ConnectionIdTokenTest.java` around
lines 52 - 67, Update the test testGetConnectionIdPreferDirectOverNested to
actually verify precedence by creating a token that contains both a top-level
connection_id and a nested ext_provider.connection_id with different values; add
a helper in JwtGenerator (e.g., generateIDTokenWithBothConnectionIds(String
direct, String nested)) that injects both claims, then call
IDToken.init(tokenString, true) and assert KindeToken.getConnectionId() equals
the directConnectionId, ensuring the direct claim is preferred over
ext_provider.connection_id.

Comment on lines 70 to +97
if (kindeAuthenticationAction == KindeAuthenticationAction.LOGIN) {
authorizationUrl = kindeClientSession.login();
if (parameters.isEmpty()) {
authorizationUrl = kindeClientSession.login();
} else {
Map<String, String> loginParams = new HashMap<>(parameters);
loginParams.put("supports_reauth", "true");
authorizationUrl = kindeClientSession.authorizationUrlWithParameters(loginParams);
}
} else if (kindeAuthenticationAction == KindeAuthenticationAction.REGISTER) {
authorizationUrl = kindeClientSession.register();
if (parameters.isEmpty()) {
authorizationUrl = kindeClientSession.register();
} else {
Map<String, String> registerParams = new HashMap<>(parameters);
registerParams.put("prompt", "create");
authorizationUrl = kindeClientSession.authorizationUrlWithParameters(registerParams);
}
} else if (kindeAuthenticationAction == KindeAuthenticationAction.CREATE_ORG) {
if (req.getParameter(ORG_NAME) == null) {
throw new ServletException("Must proved org_name query parameter to create an organisation.");
}
authorizationUrl = kindeClientSession.createOrg(req.getParameter(ORG_NAME));
if (parameters.isEmpty()) {
authorizationUrl = kindeClientSession.createOrg(req.getParameter(ORG_NAME));
} else {
Map<String, String> createOrgParams = new HashMap<>(parameters);
createOrgParams.put("prompt", "create");
createOrgParams.put("org_name", req.getParameter(ORG_NAME));
authorizationUrl = kindeClientSession.authorizationUrlWithParameters(createOrgParams);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
cd /tmp || exit 1

# Find the file
find . -name "*.java" -path "*KindeAuthenticationFilter*" 2>/dev/null | head -5

Repository: kinde-oss/kinde-java-sdk

Length of output: 192


🏁 Script executed:

#!/bin/bash
# Search for authorizationUrlWithParameters implementation
rg -n -A 25 'authorizationUrlWithParameters' --type java

# Also search for login, register, createOrg implementations
rg -n -A 15 'public.*login\(\)' --type java | head -50
rg -n -A 15 'public.*register\(\)' --type java | head -50
rg -n -A 15 'public.*createOrg\(' --type java | head -50

Repository: kinde-oss/kinde-java-sdk

Length of output: 49664


Ensure dedicated method parameters are preserved when using authorizationUrlWithParameters() in filter code.

While authorizationUrlWithParameters() does respect session configurations (grant type, scopes, redirect URI, etc.), the filter code has gaps in parameter preservation:

  1. REGISTER: The dedicated register() method always adds supports_reauth=true, but the filter code only adds prompt=create when parameters exist—supports_reauth is not guaranteed.
  2. CREATE_ORG: The dedicated createOrg() method includes is_create_org=true, but the filter code does not preserve this parameter.

Update the filter code to explicitly add these parameters:

  • For REGISTER: Add registerParams.put("supports_reauth", "true");
  • For CREATE_ORG: Add createOrgParams.put("is_create_org", "true");

This ensures behavioral equivalence with the dedicated methods.

🤖 Prompt for AI Agents
In `@kinde-j2ee/src/main/java/com/kinde/filter/KindeAuthenticationFilter.java`
around lines 70 - 97, The REGISTER and CREATE_ORG branches build parameter maps
for authorizationUrlWithParameters but omit parameters that the dedicated
methods add; update the REGISTER branch to add
registerParams.put("supports_reauth", "true") alongside prompt=create (so it
matches register()), and update the CREATE_ORG branch to add
createOrgParams.put("is_create_org", "true") alongside prompt=create and
org_name (so it matches createOrg()); modify the blocks that construct
registerParams and createOrgParams in KindeAuthenticationFilter (the branches
handling KindeAuthenticationAction.REGISTER and
KindeAuthenticationAction.CREATE_ORG and the calls to
kindeClientSession.authorizationUrlWithParameters(...)) to include those keys.

}
} else if (kindeAuthenticationAction == KindeAuthenticationAction.CREATE_ORG) {
if (req.getParameter(ORG_NAME) == null) {
throw new ServletException("Must proved org_name query parameter to create an organisation.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typo: "proved" → "provided".

📝 Suggested fix
-                    throw new ServletException("Must proved org_name query parameter to create an organisation.");
+                    throw new ServletException("Must provide org_name query parameter to create an organisation.");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
throw new ServletException("Must proved org_name query parameter to create an organisation.");
throw new ServletException("Must provide org_name query parameter to create an organisation.");
🤖 Prompt for AI Agents
In `@kinde-j2ee/src/main/java/com/kinde/filter/KindeAuthenticationFilter.java` at
line 88, In KindeAuthenticationFilter replace the typo in the thrown
ServletException message—change "Must proved org_name query parameter to create
an organisation." to use "provided" so the exception reads something like "Must
provide org_name query parameter to create an organisation."; update the string
in the throw statement inside KindeAuthenticationFilter to correct the wording.

…eSingleton

- Replace non-existent setInstance() with Mockito.mockStatic() pattern
- Match existing test patterns in KindeAuthenticationFilterTest
- Fix import statement for CONNECTION_ID constant
- Add proper tearDown() to close MockedStatic
@codecov
Copy link

codecov bot commented Jan 20, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants