Enterprise connect - #2799
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds Enterprise Connect support for B2B integrations. The change provides WebFinger-based domain discovery, disables incompatible Auth0-managed session features, supports stateless callbacks and federated logout, exports the discovery utility, and adds documentation and tests. ChangesEnterprise Connect
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2799 +/- ##
==========================================
+ Coverage 87.98% 88.09% +0.10%
==========================================
Files 80 81 +1
Lines 11514 11709 +195
Branches 2385 2434 +49
==========================================
+ Hits 10131 10315 +184
- Misses 1338 1349 +11
Partials 45 45 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/server/auth-client.ts (1)
1474-1479: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winThe "no Auth0 session cookie" invariant is not enforced across the whole request lifecycle.
appType: 'b2b_integration'is documented as never writing an Auth0 session cookie (src/server/client.ts lines 307-308, EXAMPLES.md Line 6133), but the mode check is applied only on the standard redirect callback path. One path can still create the cookie, and the logout path cannot remove it. The combined result is a session cookie that the application believes cannot exist, cannot read throughgetSession(which throws in this mode), and cannot clear through logout.
src/server/auth-client.ts#L1474-L1479: gate the popup branch onappType. It ignores theonCallbackreturn value and always callssessionStore.set(Line 1518, Line 1588), andhandleLoginacceptschallengeMode=popupfrom the query string with no mode check. RejectchallengeMode: 'popup'whenappType === "b2b_integration", since popup step-up depends on an Auth0-managed session.src/server/auth-client.ts#L1053-L1069: callsessionStore.delete(req.cookies, ecLogoutResponse.cookies)before returning, guarded by!hasDomainMismatch, and calladdCacheControlHeadersForSession. This branch returns before the cleanup at lines 1165-1168, so a cookie written by the popup path or carried over from a deployment that adoptedappTypelater survives logout.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/server/auth-client.ts` around lines 1474 - 1479, The popup authentication branch around getSessionWithDomainCheck must reject challengeMode "popup" when appType is "b2b_integration", preventing sessionStore.set from creating an Auth0 session cookie; preserve existing popup behavior for other app types. In src/server/auth-client.ts lines 1053-1069, before the early logout return, call sessionStore.delete(req.cookies, ecLogoutResponse.cookies) only when !hasDomainMismatch, then call addCacheControlHeadersForSession so stale session cookies are removed and the response receives session cache headers.
🧹 Nitpick comments (8)
src/server/auth-client.ts (2)
232-246: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMove the return-value documentation above the type alias.
The JSDoc block sits inside the parameter list, after
session. It parses, but TSDoc attaches it to nothing. Editors show no hover text forOnCallbackHook, and a reader sees a return-value description positioned as if it documented thesessionparameter. This is the main contract users need for Enterprise Connect, so it should be visible on hover.📝 Proposed fix
+/** + * Returning `null` or nothing suppresses the Auth0 session cookie — the hook is + * expected to have persisted identity elsewhere. This is only valid on the + * successful callback path; error paths and the connected-account flow still + * require a `NextResponse`. + * + * When `appType: "b2b_integration"` is set the cookie is suppressed regardless + * of the return value, so returning nothing is the idiomatic Enterprise Connect + * pattern. Return a `NextResponse` to control the redirect destination. + */ export type OnCallbackHook = ( error: SdkError | null, ctx: OnCallbackContext, session: SessionData | null - /** - * Returning `null` or nothing suppresses the Auth0 session cookie — the hook is - * expected to have persisted identity elsewhere. This is only valid on the - * successful callback path; error paths and the connected-account flow still - * require a `NextResponse`. - * - * When `appType: "b2b_integration"` is set the cookie is suppressed regardless - * of the return value, so returning nothing is the idiomatic Enterprise Connect - * pattern. Return a `NextResponse` to control the redirect destination. - */ ) => Promise<NextResponse | null | void>;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/server/auth-client.ts` around lines 232 - 246, Move the existing return-value JSDoc block so it immediately precedes the OnCallbackHook type alias, ensuring it documents the alias and appears in editor hover text. Keep the callback parameters and return type unchanged.
2890-2899: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider extracting the duplicated error message.
This message is identical to the one at lines 1198-1202. A shared constant keeps the two guards in sync if the wording changes.
This is optional.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/server/auth-client.ts` around lines 2890 - 2899, Extract the duplicated InvalidConfigurationError message into a shared constant and reuse it in both the guard near onCallback and the matching guard around the earlier callback path. Preserve the existing wording and error behavior while ensuring future message changes stay synchronized.src/server/client.test.ts (2)
2049-2074: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider asserting the getters still work without
appType.This block confirms
getSessionand the warnings are unaffected. It does not confirm thatmfa,passkey, andpasswordlessstill return their sub-clients. Those three receive the most invasive replacement — a throwinggetdescriptor — so a negative assertion is cheap protection against the guard leaking outside Enterprise Connect mode.it.each(["mfa", "passkey", "passwordless"])( "leaves %s accessible", (member) => { const client = new Auth0Client({}) as unknown as Record<string, unknown>; expect(() => client[member]).not.toThrow(); expect(client[member]).toBeDefined(); } );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/server/client.test.ts` around lines 2049 - 2074, Extend the “without appType (no regression)” tests with a parameterized case for the Auth0Client getters mfa, passkey, and passwordless. Instantiate Auth0Client without appType, assert each corresponding property access does not throw, and verify it returns a defined sub-client.
1757-1768: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider restoring the environment variables in
afterEach.
beforeEachsets fiveprocess.enventries.afterEachrestores only theconsole.warnspy. The values persist into later suites in this file and into other suites in the same worker.This is optional if the file already resets environment state globally.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/server/client.test.ts` around lines 1757 - 1768, Restore the five process.env entries assigned in the beforeEach hook after each test, alongside consoleWarnSpy.mockRestore in afterEach. Preserve any prior or unset values rather than deleting or overwriting them unconditionally, and avoid changes if an existing file-wide environment reset already handles these keys.src/utils/webfingerCache.test.ts (1)
168-264: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider a test for
CACHE_MAX_SIZEeviction.The caching suite covers TTL, bypass, and key isolation. It does not cover the FIFO eviction branch in
setCacheEntry. A test that fills the cache past 1,000 distinct domains and asserts the oldest entry re-fetches would lock in the bound.This is optional. The eviction path is small and currently correct.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/webfingerCache.test.ts` around lines 168 - 264, Add an optional caching test in the “caching” suite that calls isFederatedDomain for more than CACHE_MAX_SIZE distinct domains, then repeats the oldest domain and verifies fetchSpy was called again because FIFO eviction removed its entry. Keep the test focused on the cache bound and use distinct domain keys.src/utils/webfingerCache.ts (1)
95-135: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winConsider coalescing concurrent lookups for the same key.
The cache stores only settled results. Concurrent logins for the same cold domain each issue their own WebFinger request. That is the exact burst pattern that produces the 429 handled on Line 116. Storing the in-flight
Promisein the map, keyed the same way, collapses the burst into one request.This is optional. The current behavior is correct and degrades safely.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/webfingerCache.ts` around lines 95 - 135, Optionally update the WebFinger lookup flow around the cache key and request function to coalesce concurrent cold-cache lookups: store the in-flight Promise in the same keyed map, return it for subsequent requests, and replace it with the settled result using the existing TTL behavior. Preserve current handling for successful, 404, 429, and error responses, including safe false returns and no caching where currently specified.src/server/auth-client.test.ts (1)
6029-6079: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse
runCallbackfor the remaining tests.These three tests rebuild the same
AuthClient, URL, transaction state, and encrypted cookie thatrunCallback(lines 5872-5927) already builds. They differ only bybeforeSessionSavedand aconsole.warnspy. That is roughly 150 duplicated lines directly below the helper introduced to prevent them.Add optional
beforeSessionSavedto the helper options and use it in all three.♻️ Proposed helper extension
async function runCallback({ onCallback, appType, + beforeSessionSaved, returnTo = "/dashboard" }: { onCallback: AuthClientOptions["onCallback"]; appType?: "b2b_integration"; + beforeSessionSaved?: AuthClientOptions["beforeSessionSaved"]; returnTo?: string; }) {onCallback, + beforeSessionSaved, appType });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/server/auth-client.test.ts` around lines 6029 - 6079, Extend the existing runCallback helper with an optional beforeSessionSaved callback option and pass it into the AuthClient configuration. Replace the duplicated AuthClient, callback URL, transaction state, and encrypted-cookie setup in all three remaining tests, including “does not run beforeSessionSaved on the passthrough path,” with runCallback calls while preserving each test’s callback and console.warn behavior.src/server/client.ts (1)
109-165: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winType the registry keys against
Auth0Clientto catch renames.
EC_UNAVAILABLE_MEMBERSisRecord<string, string>, and the two companion sets hold plain strings. Nothing links them to the real members. Three silent failure modes follow:
- A member is renamed. The entry keeps the old key and the member becomes available again in Enterprise Connect mode.
- A new getter is added to
EC_UNAVAILABLE_MEMBERSbut omitted fromEC_UNAVAILABLE_GETTERS.disableSessionMembersForEnterpriseConnectinstalls avalueproperty instead of aget, soclient.newGetterreturns a throwing function rather than throwing on access.buildSessionTransferRedirectbecomes async and stays inEC_UNAVAILABLE_SYNC_METHODS, producing the unhandled-rejection behavior the comment on lines 161-163 warns about.The doc block at lines 92-107 asks maintainers to keep these in sync manually. A key type makes the compiler do it.
♻️ Proposed typing
-const EC_UNAVAILABLE_MEMBERS: Record<string, string> = { +type EcUnavailableMember = keyof Auth0Client; + +const EC_UNAVAILABLE_MEMBERS: Partial<Record<EcUnavailableMember, string>> = {-const EC_UNAVAILABLE_GETTERS = new Set(["passwordless", "passkey", "mfa"]); +const EC_UNAVAILABLE_GETTERS = new Set<EcUnavailableMember>([ + "passwordless", + "passkey", + "mfa" +]);-const EC_UNAVAILABLE_SYNC_METHODS = new Set(["buildSessionTransferRedirect"]); +const EC_UNAVAILABLE_SYNC_METHODS = new Set<EcUnavailableMember>([ + "buildSessionTransferRedirect" +]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/server/client.ts` around lines 109 - 165, Type EC_UNAVAILABLE_MEMBERS keys against the corresponding members of Auth0Client instead of Record<string, string>, and type EC_UNAVAILABLE_GETTERS and EC_UNAVAILABLE_SYNC_METHODS using those same derived member-key unions. Ensure the registry and companion sets are compiler-checked when Auth0Client members are renamed, added, or change between getter and method/async behavior, preserving the existing runtime handling in disableSessionMembersForEnterpriseConnect.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@EXAMPLES.md`:
- Line 6150: Update the isFederatedDomain example guidance to explicitly
document that proxying the check through an unauthenticated browser-accessible
route enables domain enumeration. Instruct implementers to rate-limit the route
and treat its response as public information, while retaining the
server-side-only requirement.
- Line 6271: Update the Enterprise Connect reference in EXAMPLES.md to point to
the matching existing example directory, or remove the reference if no
corresponding example exists; ensure no link remains to
examples/with-enterprise-connect.
- Around line 6168-6187: Update the callback example around the session creation
flow: validate session.user["org_id"] against the organization expected for this
login before trusting it; replace the unsigned base64 app_session value with the
existing signed or encrypted session mechanism; set secure: true on the cookie;
and change the handleCallback error path to return a NextResponse redirect to
the error page instead of throwing, preserving the onCallback response contract.
- Around line 6142-6147: Update the POST route to validate that email is present
and contains a domain after “@” before calling isFederatedDomain. Retrieve the
database-backed connection and orgId values for the email domain, and return
isFederated, connection, and orgId from the route so the login form’s
destructuring and /auth/login query parameters receive defined values.
In `@src/server/auth-client.test.ts`:
- Line 6084: Move restoration of the console.warn spy from the individual tests
into an afterEach hook in the relevant test scope, using warnSpy.mockRestore()
or vi.restoreAllMocks(). Remove the test-local restore statements while
preserving the existing spy setup and assertions.
- Around line 4155-4180: Update the test “does not include id_token_hint even
when a session exists” to create and persist a session in the existing
StatelessSessionStore, then attach the resulting session cookie to the logout
request. Keep the existing assertion and configuration unchanged so handleLogout
exercises the session-present Enterprise Connect path and verifies that
id_token_hint remains omitted.
- Around line 4245-4268: Update the “clears transaction cookies on EC logout”
test to seed a transaction cookie on the logout request, using the configured
transaction store and its expected cookie name/value format. After handleLogout
returns, assert the response clears that cookie with maxAge 0, while retaining
the existing redirect-status assertion; this should specifically exercise
AuthClient.handleLogout’s transactionStore.deleteAll path.
In `@src/server/auth-client.ts`:
- Around line 1645-1656: Update the passthrough handling around the callback
result condition so any falsy res emits a diagnostic warning, including
non-Enterprise-Connect applications. Preserve the existing Enterprise
Connect-specific warning text for appType "b2b_integration", and add an
appropriate warning for other app types before the redirect/session-creation
path continues.
In `@src/server/client.test.ts`:
- Around line 1926-1937: Remove the duplicate test around
client.buildSessionTransferRedirect, or update it to explicitly verify that the
method does not return a promise and cannot leave an unhandled rejection; retain
the existing stricter throwing test separately.
In `@src/server/client.ts`:
- Around line 314-327: The Auth0Client JSDoc example currently demonstrates a
static organization that conflicts with the documented multi-organization
guidance. Update the example’s authorizationParameters to remove organization,
and add a concise comment showing that organization should be supplied per login
while noting the static value is appropriate only for a client serving exactly
one organization.
In `@src/utils/webfingerCache.ts`:
- Around line 88-93: Update the WebFinger fetch in isFederatedDomain to pass an
AbortSignal.timeout using the SDK’s configured HTTP timeout, matching
AuthClient.httpOptions. Preserve the existing catch behavior so a timeout
AbortError returns false through the current fallback path.
---
Outside diff comments:
In `@src/server/auth-client.ts`:
- Around line 1474-1479: The popup authentication branch around
getSessionWithDomainCheck must reject challengeMode "popup" when appType is
"b2b_integration", preventing sessionStore.set from creating an Auth0 session
cookie; preserve existing popup behavior for other app types. In
src/server/auth-client.ts lines 1053-1069, before the early logout return, call
sessionStore.delete(req.cookies, ecLogoutResponse.cookies) only when
!hasDomainMismatch, then call addCacheControlHeadersForSession so stale session
cookies are removed and the response receives session cache headers.
---
Nitpick comments:
In `@src/server/auth-client.test.ts`:
- Around line 6029-6079: Extend the existing runCallback helper with an optional
beforeSessionSaved callback option and pass it into the AuthClient
configuration. Replace the duplicated AuthClient, callback URL, transaction
state, and encrypted-cookie setup in all three remaining tests, including “does
not run beforeSessionSaved on the passthrough path,” with runCallback calls
while preserving each test’s callback and console.warn behavior.
In `@src/server/auth-client.ts`:
- Around line 232-246: Move the existing return-value JSDoc block so it
immediately precedes the OnCallbackHook type alias, ensuring it documents the
alias and appears in editor hover text. Keep the callback parameters and return
type unchanged.
- Around line 2890-2899: Extract the duplicated InvalidConfigurationError
message into a shared constant and reuse it in both the guard near onCallback
and the matching guard around the earlier callback path. Preserve the existing
wording and error behavior while ensuring future message changes stay
synchronized.
In `@src/server/client.test.ts`:
- Around line 2049-2074: Extend the “without appType (no regression)” tests with
a parameterized case for the Auth0Client getters mfa, passkey, and passwordless.
Instantiate Auth0Client without appType, assert each corresponding property
access does not throw, and verify it returns a defined sub-client.
- Around line 1757-1768: Restore the five process.env entries assigned in the
beforeEach hook after each test, alongside consoleWarnSpy.mockRestore in
afterEach. Preserve any prior or unset values rather than deleting or
overwriting them unconditionally, and avoid changes if an existing file-wide
environment reset already handles these keys.
In `@src/server/client.ts`:
- Around line 109-165: Type EC_UNAVAILABLE_MEMBERS keys against the
corresponding members of Auth0Client instead of Record<string, string>, and type
EC_UNAVAILABLE_GETTERS and EC_UNAVAILABLE_SYNC_METHODS using those same derived
member-key unions. Ensure the registry and companion sets are compiler-checked
when Auth0Client members are renamed, added, or change between getter and
method/async behavior, preserving the existing runtime handling in
disableSessionMembersForEnterpriseConnect.
In `@src/utils/webfingerCache.test.ts`:
- Around line 168-264: Add an optional caching test in the “caching” suite that
calls isFederatedDomain for more than CACHE_MAX_SIZE distinct domains, then
repeats the oldest domain and verifies fetchSpy was called again because FIFO
eviction removed its entry. Keep the test focused on the cache bound and use
distinct domain keys.
In `@src/utils/webfingerCache.ts`:
- Around line 95-135: Optionally update the WebFinger lookup flow around the
cache key and request function to coalesce concurrent cold-cache lookups: store
the in-flight Promise in the same keyed map, return it for subsequent requests,
and replace it with the settled result using the existing TTL behavior. Preserve
current handling for successful, 404, 429, and error responses, including safe
false returns and no caching where currently specified.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 8767f359-8fd5-486c-b445-82cdc784ee42
📒 Files selected for processing (8)
EXAMPLES.mdsrc/server/auth-client.test.tssrc/server/auth-client.tssrc/server/client.test.tssrc/server/client.tssrc/server/index.tssrc/utils/webfingerCache.test.tssrc/utils/webfingerCache.ts
| export async function POST(req: NextRequest) { | ||
| const { email } = await req.json(); | ||
| const emailDomain = email.split("@")[1]; | ||
| const isFederated = await isFederatedDomain(process.env.AUTH0_DOMAIN!, emailDomain); | ||
| return NextResponse.json({ isFederated }); | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
The example route does not return the fields the login form reads.
/api/check-domain returns { isFederated } only. The login form at Line 6204 destructures { isFederated, connection, orgId } from that same response, and Line 6212 puts both into the /auth/login query string. A reader who copies both snippets gets connection=undefined&organization=undefined.
The comment on Line 6211 states that connection and orgId come from the database through this route, so the route must return them.
Also validate email before splitting. If the body has no @, email.split("@")[1] is undefined and the WebFinger resource becomes urn:auth0:discovery:domain:undefined.
📝 Proposed fix for the route contract
export async function POST(req: NextRequest) {
const { email } = await req.json();
- const emailDomain = email.split("@")[1];
- const isFederated = await isFederatedDomain(process.env.AUTH0_DOMAIN!, emailDomain);
- return NextResponse.json({ isFederated });
+ const emailDomain =
+ typeof email === "string" ? email.split("@")[1]?.toLowerCase() : undefined;
+
+ if (!emailDomain) {
+ return NextResponse.json({ isFederated: false }, { status: 400 });
+ }
+
+ const isFederated = await isFederatedDomain(process.env.AUTH0_DOMAIN!, emailDomain);
+
+ if (!isFederated) {
+ return NextResponse.json({ isFederated: false });
+ }
+
+ // Look up the enterprise connection and organization for this domain.
+ const tenant = await db.tenants.findByEmailDomain(emailDomain);
+
+ return NextResponse.json({
+ isFederated: Boolean(tenant),
+ connection: tenant?.connection,
+ orgId: tenant?.orgId
+ });
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@EXAMPLES.md` around lines 6142 - 6147, Update the POST route to validate that
email is present and contains a domain after “@” before calling
isFederatedDomain. Retrieve the database-backed connection and orgId values for
the email domain, and return isFederated, connection, and orgId from the route
so the login form’s destructuring and /auth/login query parameters receive
defined values.
There was a problem hiding this comment.
this should be fixed, check it.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
ast-grep outline EXAMPLES.md --items all --type function --match 'POST|LoginPage'
printf '\n--- Domain-discovery example ---\n'
sed -n '6135,6185p' EXAMPLES.md
printf '\n--- Login-form example ---\n'
sed -n '6185,6235p' EXAMPLES.mdLength of output: 4279
@Piyush-85, I checked the current PR branch.
The route now returns connection and orgId for federated domains. This fixes the login form response-contract issue.
The email validation is still missing. email.split("@")[1] can throw when email is not a string. It can also produce undefined when the email has no domain. The route should validate the input before it calls isFederatedDomain.
The review comment remains valid for the input-validation part.
You are interacting with an AI system.
There was a problem hiding this comment.
Should be fixed, check
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- Enterprise Connect domain-discovery example ---'
sed -n '6135,6185p' EXAMPLES.md
printf '%s\n' '--- Enterprise Connect login-form example ---'
sed -n '6212,6250p' EXAMPLES.mdLength of output: 3808
@Piyush-85, I checked the current branch.
The route now returns connection and orgId. This fixes the login-form response contract.
The email validation is still incomplete.
- If
emailis not a string,email.includes("@")throws. - If
emailis"user@", the check passes andemailDomainis empty.
The route should validate the type and the domain before it calls isFederatedDomain. The review comment remains unresolved.
You are interacting with an AI system.
| } | ||
| ``` | ||
|
|
||
| `isFederatedDomain` calls Auth0's WebFinger endpoint and caches results (60 s for managed domains, 15 s for unmanaged). Call it server-side only — never from the browser. |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
Document the enumeration risk of proxying this check to the browser.
isFederatedDomain warns in its JSDoc that browser access "would expose the Auth0 domain and allow clients to enumerate your customers' domains" (src/utils/webfingerCache.ts, lines 50-51). The example route restores that capability: it is an unauthenticated POST that answers "is this domain one of your enterprise customers?" for any submitted domain.
"Call it server-side only" does not cover this. Add guidance to rate limit the route and to treat the answer as public information.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@EXAMPLES.md` at line 6150, Update the isFederatedDomain example guidance to
explicitly document that proxying the check through an unauthenticated
browser-accessible route enables domain enumeration. Instruct implementers to
rate-limit the route and treat its response as public information, while
retaining the server-side-only requirement.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
line=$(rg -n '^## Enterprise Connect \(B2B Integration\)$' EXAMPLES.md | cut -d: -f1)
if [ -z "$line" ]; then
echo "Enterprise Connect section not found in EXAMPLES.md" >&2
exit 1
fi
start=$((line))
end=$((line + 70))
sed -n "${start},${end}p" EXAMPLES.mdLength of output: 3686
@Piyush-85, the update documents the risk of calling isFederatedDomain from the browser directly.
The example still exposes the same result through an unauthenticated POST /api/check-domain route. The guidance must also state that this route enables domain enumeration, must be rate-limited, and must treat its response as public information.
The review comment remains unresolved.
You are interacting with an AI system.
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
section_line="$(rg -n '^## Enterprise Connect \(B2B Integration\)$' EXAMPLES.md | cut -d: -f1)"
if [ -z "$section_line" ]; then
echo "Enterprise Connect section not found in EXAMPLES.md" >&2
exit 1
fi
sed -n "${section_line},$((section_line + 85))p" EXAMPLES.mdLength of output: 4077
@Piyush-85, I checked the current EXAMPLES.md update.
The direct browser-call warning is now present. The example still exposes an unauthenticated POST /api/check-domain route. The documentation does not yet instruct users to:
- Rate-limit this route.
- Treat its response as public information.
The route also returns connection and orgId for managed domains. This makes the guidance necessary.
The review comment remains unresolved.
You are interacting with an AI system.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/utils/webfingerCache.ts (1)
113-137: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winCancel response bodies before exiting non-OK branches.
In the non-OK response path,
isFederatedDomainreturns without consuming or cancellingres.body. Under Node fetch, leaving response streams to garbage collection can prevent TCP connections from returning to the pool to other requests. Handle body cleanup early before the status-specific return branches.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils/webfingerCache.ts` around lines 113 - 137, Update isFederatedDomain’s non-OK response handling to cancel or consume res.body before the 404 and 429 early returns and before falling through for other error statuses. Perform this cleanup immediately after receiving the response, while preserving the existing caching and status-specific behavior.Source: MCP tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/utils/webfingerCache.ts`:
- Around line 113-137: Update isFederatedDomain’s non-OK response handling to
cancel or consume res.body before the 404 and 429 early returns and before
falling through for other error statuses. Perform this cleanup immediately after
receiving the response, while preserving the existing caching and
status-specific behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 9f99b0aa-02d5-44c6-8a75-f7086692e41d
📒 Files selected for processing (6)
EXAMPLES.mdsrc/server/auth-client.test.tssrc/server/auth-client.tssrc/server/client.test.tssrc/server/client.tssrc/utils/webfingerCache.ts
💤 Files with no reviewable changes (1)
- src/server/client.test.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- src/server/auth-client.test.ts
- src/server/client.ts
- EXAMPLES.md
- src/server/auth-client.ts
📋 Changes
Adds Enterprise Connect support via
appType: 'b2b_integration'onAuth0Client.New export -
isFederatedDomain(auth0Domain, emailDomain):Calls Auth0's WebFinger endpoint to determine whether an email domain is managed for enterprise SSO on the tenant. Returns
true/falsewith a TTL cache (60 s positive, 15 s negative).Export path:
@auth0/nextjs-auth0/server. Server-side only.New option —
Auth0ClientOptions.appType: 'b2b_integration':onCallbackis responsible for persisting identity to the app's own store.onCallbackreturn type extended toPromise<NextResponse | null | void>. Returningnull/voidsuppresses the Auth0 session cookie and redirects toreturnTo. Returning aNextResponsegives the developer full control — required for cookie-based sessions.getSession,getAccessToken,buildSessionTransferRedirect,getTokenByBackchannelAuth,mfa,passwordless,passkey, and others) throwInvalidConfigurationErrorwith actionable guidance rather than returningnullsilently. Synchronous methods throw synchronously; async methodsreturn a rejected promise.
offline_accessis in scope (no refresh tokens issued for this app type) ororganizationis not being passed per login.EC-aware logout:
The existing logout path set
federated=as an empty string in EC mode because noid_token_hintis available without an Auth0 session. This meant the enterprise IdP session was never terminated, causing the next login to silently reuse the previous user's session.handleLogoutnow detects EC mode and uses the OIDCend_session_endpointdirectly withfederated=true.Documentation:
EXAMPLES.md— new Enterprise Connect section coveringisFederatedDomain, SDK initialization, login form, protected pages, logout, and the unavailablemethods list.
examples/with-enterprise-connect— new example app with a working end-to-end EC flow including domain discovery, cookie-based own-session pattern, and federated logout.📎 References
RFC 7033 — WebFinger (IETF standard)
🎯 Testing
isFederatedDomaincovering all WebFinger response codes, TTL cache, case normalization, and rate limiting.onCallbackvoid warning.npx tsc --noEmitclean.npm run lintclean.Summary by CodeRabbit
New Features
Documentation
Bug Fixes