fix: support runtime tenant/domain switching with per-client credential isolation #1564
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 (1)
📝 WalkthroughWalkthroughAdds ChangesMulti-tenant credential isolation and config-driven re-initialization
Sequence Diagram(s)sequenceDiagram
participant App as React app
participant Provider as Auth0Provider
participant Factory as Auth0ClientFactory
participant NativeClient as NativeAuth0Client
participant Bridge as NativeBridgeManager
participant Native as Native layer
App->>Provider: render with Auth0Options
Provider->>Factory: createClient(options)
Factory->>NativeClient: construct client for config signature
NativeClient->>Bridge: initialize(..., credentialsManagerStorageKey)
Bridge->>Native: initializeAuth0WithConfiguration(..., storage key)
Native-->>Bridge: create namespaced credentials store
App->>Provider: re-render with changed identity config
Provider->>Factory: createClient(options')
Factory->>NativeClient: new client or cache miss
NativeClient->>NativeClient: syncNativeConfig()
NativeClient->>Bridge: re-initialize if signature drifted
NativeClient->>Bridge: invoke bridged native method
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. 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 |
…into fix/multi-tenant-domain-switching
…pdate Auth0Provider to use it
…sage of credentialsManagerStorageKey
…into fix/multi-tenant-domain-switching
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/platforms/native/adapters/NativeAuth0Client.ts (1)
70-73: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
getDPoPHeadersstill bypasses native re-sync and can run with stale tenant config.Lines 201-204 add re-sync in the guarded bridge path, but Line 70-Line 73 and Line 169 call
this.bridge.getDPoPHeaders(...)directly. After a sibling client reconfigures the native singleton, this DPoP path can execute against the wrong native config.🐛 Proposed fix
const getDPoPHeadersForOrchestrator = async (params: DPoPHeadersParams) => { await this.ready; + await this.syncNativeConfig(); return this.bridge.getDPoPHeaders(params); }; @@ async getDPoPHeaders( params: DPoPHeadersParams ): Promise<Record<string, string>> { await this.ready; + await this.syncNativeConfig(); try { return await this.bridge.getDPoPHeaders(params); } catch (e) {Also applies to: 164-170, 201-204
🤖 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/platforms/native/adapters/NativeAuth0Client.ts` around lines 70 - 73, The getDPoPHeadersForOrchestrator function and the getDPoPHeaders call at line 169 are directly invoking bridge methods without triggering the native re-sync mechanism that is present in the guarded bridge path at lines 201-204. To fix this, ensure that both the getDPoPHeadersForOrchestrator function and the getDPoPHeaders call at line 169 use the same re-sync pattern that protects against stale native configuration. Extract or refactor the re-sync logic from lines 201-204 and apply it to guard the getDPoPHeaders calls so that the native configuration is always synchronized before executing these operations.src/specs/NativeA0Auth0.ts (1)
22-31: 🗄️ Data Integrity & Integration | 🟠 MajorEnsure
yarn codegenwas executed for the TurboModule spec update.The
credentialsManagerStorageKeyargument has been properly propagated across both iOS (ios/A0Auth0.mm,ios/NativeBridge.swift) and Android (A0Auth0Module.kt,A0Auth0Spec.kt) implementations. However, per coding guidelines, TurboModule spec changes require explicitly runningyarn codegento regenerate native bindings—please confirm this was done.🤖 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/specs/NativeA0Auth0.ts` around lines 22 - 31, After adding the new `credentialsManagerStorageKey` parameter to the `initializeAuth0WithConfiguration` method signature in the TurboModule spec, you must run the codegen command to regenerate the native bindings. Execute `yarn codegen` from the project root to ensure the native layer (iOS and Android implementations) are automatically regenerated with the updated method signature, keeping the TypeScript spec synchronized with the native implementations.Source: Coding guidelines
🧹 Nitpick comments (1)
src/core/utils/configSignature.ts (1)
13-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConvert the exported API comment to JSDoc.
Please use a
/** ... */block forgetConfigSignatureso the public API is documented consistently.Suggested fix
-// Stable, order-independent identity string for a config: keys the factory cache, the provider memo, and the native re-init decision. Object values are sorted so key order doesn't matter. +/** + * Stable, order-independent identity string for a config. + * Keys factory cache, provider memoization, and native re-init drift checks. + */ export function getConfigSignature(options: Auth0Options): string {As per coding guidelines, "Use JSDoc comments to document all public APIs".
🤖 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/core/utils/configSignature.ts` around lines 13 - 14, Convert the single-line comment above the getConfigSignature function to a JSDoc comment block. Replace the `//` comment that describes the stable, order-independent identity string functionality with a `/** ... */` JSDoc block that contains the same descriptive text. This ensures the public API is documented consistently using JSDoc format as per coding guidelines.Source: Coding guidelines
🤖 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 `@android/src/main/java/com/auth0/react/A0Auth0Module.kt`:
- Around line 304-309: In the catch block for the Exception `e` at the
biometrics authentication fallback, the promise.reject call for
BIOMETRICS_AUTHENTICATION_ERROR_CODE is missing the caught exception `e` as a
parameter, which loses critical debugging information including the stack trace
and root cause. Modify the promise.reject invocation to include the caught
exception `e` as the third parameter (throwable) and optionally append
`e.message` to the rejection message string so that the actual error details are
preserved for diagnosing why the Local Authentication Options parsing failed.
In `@EXAMPLES.md`:
- Around line 1958-1960: A blank blockquote line (containing only `>`) between
the two note sections in EXAMPLES.md is triggering the markdownlint MD028 error.
Remove the blank `>` line that separates the "Note: Switching tenants..."
blockquote from the "Important — credentials are shared..." blockquote so they
form a single continuous blockquote without a break in between.
In `@ios/NativeBridge.swift`:
- Line 13: The import of SimpleKeychain in NativeBridge.swift relies on it being
available only as a transitive dependency through Auth0, which creates fragility
in the build. To fix this, add SimpleKeychain as an explicit direct dependency
to the A0Auth0.podspec file by including a dependency declaration such as
s.dependency 'SimpleKeychain', '~> 1.3' (or the appropriate version constraint)
in the podspec alongside the existing Auth0 dependency declaration.
In `@src/core/utils/configSignature.ts`:
- Around line 4-11: The SIGNIFICANT_KEYS array in configSignature.ts is missing
the maxRetries configuration option, which means changes to maxRetries alone
won't trigger a reconfiguration of the native client instance, allowing stale
retry behavior to persist. Add maxRetries to the SIGNIFICANT_KEYS array as a
string literal to ensure it is included in the configuration signature for drift
detection, allowing the native initialization to properly respond to changes in
this value.
In `@src/platforms/native/adapters/__tests__/NativeAuth0Client.spec.ts`:
- Around line 25-28: Replace the `as any` type cast with `as unknown` in the
NativeAuth0Client static reset line where appliedNativeSignature is being set to
null. This maintains strict TypeScript typing guidelines while still allowing
access to the private static property for test cleanup purposes.
In `@src/platforms/native/bridge/INativeBridge.ts`:
- Line 38: The JSDoc parameter documentation for credentialsManagerStorageKey on
line 38 describes platform-specific behavior using inline notation instead of
the required explicit platform-only format. Update the comment to use the
standardized platform notation (e.g., **iOS only**, **Android only**) instead of
inline descriptions like "Android SharedPreferences name / iOS keychain
service". The documentation should clearly indicate which platforms use which
storage mechanism using the explicit platform-only notation format as defined in
the coding guidelines.
---
Outside diff comments:
In `@src/platforms/native/adapters/NativeAuth0Client.ts`:
- Around line 70-73: The getDPoPHeadersForOrchestrator function and the
getDPoPHeaders call at line 169 are directly invoking bridge methods without
triggering the native re-sync mechanism that is present in the guarded bridge
path at lines 201-204. To fix this, ensure that both the
getDPoPHeadersForOrchestrator function and the getDPoPHeaders call at line 169
use the same re-sync pattern that protects against stale native configuration.
Extract or refactor the re-sync logic from lines 201-204 and apply it to guard
the getDPoPHeaders calls so that the native configuration is always synchronized
before executing these operations.
In `@src/specs/NativeA0Auth0.ts`:
- Around line 22-31: After adding the new `credentialsManagerStorageKey`
parameter to the `initializeAuth0WithConfiguration` method signature in the
TurboModule spec, you must run the codegen command to regenerate the native
bindings. Execute `yarn codegen` from the project root to ensure the native
layer (iOS and Android implementations) are automatically regenerated with the
updated method signature, keeping the TypeScript spec synchronized with the
native implementations.
---
Nitpick comments:
In `@src/core/utils/configSignature.ts`:
- Around line 13-14: Convert the single-line comment above the
getConfigSignature function to a JSDoc comment block. Replace the `//` comment
that describes the stable, order-independent identity string functionality with
a `/** ... */` JSDoc block that contains the same descriptive text. This ensures
the public API is documented consistently using JSDoc format as per coding
guidelines.
🪄 Autofix (Beta)
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: 7b3a777a-a037-4a09-a37b-d00aad3578f9
⛔ Files ignored due to path filters (1)
example/ios/Podfile.lockis excluded by!**/*.lock
📒 Files selected for processing (19)
EXAMPLES.mdandroid/src/main/java/com/auth0/react/A0Auth0Module.ktandroid/src/main/oldarch/com/auth0/react/A0Auth0Spec.ktexample/ios/Auth0Example.xcodeproj/project.pbxprojios/A0Auth0.mmios/NativeBridge.swiftsrc/core/utils/__tests__/configSignature.spec.tssrc/core/utils/configSignature.tssrc/core/utils/index.tssrc/factory/Auth0ClientFactory.tssrc/factory/Auth0ClientFactory.web.tssrc/factory/__tests__/Auth0ClientFactory.spec.tssrc/hooks/Auth0Provider.tsxsrc/platforms/native/adapters/NativeAuth0Client.tssrc/platforms/native/adapters/__tests__/NativeAuth0Client.spec.tssrc/platforms/native/bridge/INativeBridge.tssrc/platforms/native/bridge/NativeBridgeManager.tssrc/specs/NativeA0Auth0.tssrc/types/common.ts
… for multi-tenant support
Summary
Fixes switching between Auth0 tenants (
domain/clientId) at runtime. Previously, changing thedomainorclientIddid not take effect — calls kept targeting the original tenant — and all clients shared a single native credentials store, so one tenant's session could surface for another.domain/clientIdonAuth0Providernow correctly switches the active tenant.Auth0clients (or reusing one after switching) now routes each call to the right tenant.Credential isolation
Adds an optional
credentialsManagerStorageKeytoAuth0Options. When set, it namespaces the native credentials store — the Android SharedPreferences file name and the iOS Keychain service — so each client/tenant gets an isolated store instead of sharing one.Available via both the
Auth0Providerprop and theAuth0class constructor. Works on bare React Native and Expo.There is no migration between stores. Changing or removing a previously-set key points a client at a different (empty) store, requiring a fresh login. Keep keys stable, and leave the primary tenant without a key. See the "Switching tenants at runtime" section in
EXAMPLES.md.Test plan
authorize()opens the newly selected tenant's login and the redirect resolves.Fixes #1520
Fixes #1523
Summary by CodeRabbit
Release Notes
New Features
credentialsManagerStorageKeyto scope native credentials storage (Android SharedPreferences / iOS Keychain) per tenant/client.Bug Fixes
Documentation