chore: bring v5.11.0 changes into v6-development - #1618
Conversation
📝 WalkthroughWalkthroughThe v5.11.0 release adds IPSIE session-expiry handling, web passkey support, passkey error normalization, native credential validation, platform credential metadata propagation, documentation, tests, and release metadata updates. ChangesAuthentication features
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested reviewers: 🚥 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 |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
src/platforms/native/adapters/__tests__/NativeAuth0Client.spec.ts (1)
646-654: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert the error instance and
typeseparately.
toMatchObject({ constructor: PasskeyError, ... })does not express intent clearly and relies on Jest comparing a constructor property. Userejects.toBeInstanceOf(PasskeyError)with a stored promise, then asserttypeseparately, and move thePasskeyErrorimport out of the inlinerequireso the test continues under single-assertion isolation.🤖 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/__tests__/NativeAuth0Client.spec.ts` around lines 646 - 654, Update the getTokenByPasskey rejection test to store the rejected promise, assert it with rejects.toBeInstanceOf(PasskeyError), and separately assert the error’s type equals PasskeyErrorCodes.INVALID_PARAMETER. Move PasskeyError to a top-level import instead of using an inline require, while preserving the existing request inputs and single-assertion isolation.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 `@example/src/App.web.tsx`:
- Around line 218-226: Add explicit null checks to the credential results in
both the creation flow and the get flow, using the surrounding passkey handlers
and their PublicKeyCredential assignments. Treat a null result as an error and
throw the existing PasskeyError before assigning or forwarding the credential;
preserve the current catch behavior for rejected credential operations.
In `@ios/NativeBridge.swift`:
- Line 21: Update the sessionExpiresAtKey declaration to remove its trailing
semicolon, leaving the string value and constant unchanged.
In `@src/core/models/PasskeyError.ts`:
- Around line 190-201: Update PasskeyError.getMfaRequiredPayload so absent
this.json is normalized to an empty object before accessing payload fields,
while preserving the existing fallback values. Validate that json.mfa_token is a
string and use the existing empty-string fallback otherwise. Add coverage for an
MFA_REQUIRED error without JSON and verify it returns a payload without
throwing.
In `@src/platforms/web/adapters/__tests__/WebAuth0Client.spec.ts`:
- Around line 956-975: Update the getTokenByPasskey test to guarantee rejection
and execution of the getMfaRequiredPayload assertion: add an assertion count
covering the catch-block expectation or use Jest’s rejects form. Preserve the
existing expected payload values and ensure a resolved promise cannot make the
test pass.
---
Nitpick comments:
In `@src/platforms/native/adapters/__tests__/NativeAuth0Client.spec.ts`:
- Around line 646-654: Update the getTokenByPasskey rejection test to store the
rejected promise, assert it with rejects.toBeInstanceOf(PasskeyError), and
separately assert the error’s type equals PasskeyErrorCodes.INVALID_PARAMETER.
Move PasskeyError to a top-level import instead of using an inline require,
while preserving the existing request inputs and single-assertion isolation.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: ec7a1805-9247-4dab-a17c-a54bbb2fcb06
⛔ Files ignored due to path filters (2)
example/ios/Podfile.lockis excluded by!**/*.lockyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (31)
.versionA0Auth0.podspecCHANGELOG.mdCLAUDE.mdEXAMPLES-WEB.mdEXAMPLES.mdREADME.mdandroid/src/main/java/com/auth0/react/A0Auth0Module.ktandroid/src/main/java/com/auth0/react/CredentialsParser.ktexample/src/App.web.tsxios/NativeBridge.swiftpackage.jsonsrc/Auth0.tssrc/core/models/Credentials.tssrc/core/models/CredentialsManagerError.tssrc/core/models/PasskeyError.tssrc/core/models/__tests__/Credentials.spec.tssrc/core/models/__tests__/ErrorCodes.spec.tssrc/core/models/__tests__/PasskeyError.spec.tssrc/core/utils/telemetry.tssrc/platforms/native/adapters/NativeAuth0Client.tssrc/platforms/native/adapters/__tests__/NativeAuth0Client.spec.tssrc/platforms/native/adapters/__tests__/NativeCredentialsManager.errors.spec.tssrc/platforms/native/adapters/__tests__/NativeCredentialsManager.spec.tssrc/platforms/web/adapters/WebAuth0Client.tssrc/platforms/web/adapters/WebCredentialsManager.tssrc/platforms/web/adapters/__tests__/WebAuth0Client.spec.tssrc/platforms/web/adapters/__tests__/WebCredentialsManager.errors.spec.tssrc/platforms/web/adapters/__tests__/WebCredentialsManager.spec.tssrc/types/common.tssrc/types/parameters.ts
💤 Files with no reviewable changes (1)
- src/Auth0.ts
| let credential: PublicKeyCredential; | ||
| try { | ||
| credential = (await navigator.credentials.create({ | ||
| publicKey: | ||
| challenge.authParamsPublicKey as PublicKeyCredentialCreationOptions, | ||
| })) as PublicKeyCredential; | ||
| } catch (e) { | ||
| throw new PasskeyError(e as Error); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Add the null check that the documentation prescribes.
navigator.credentials.create() and .get() resolve to Credential | null. Both blocks cast the result to PublicKeyCredential without a null check, so a null resolution is forwarded as authResponse. The web adapter guard only rejects a string, and typeof null === 'object', so null reaches getTokenWithPasskey. EXAMPLES-WEB.md lines 306-309 documents the opposite pattern and throws on a missing credential. Align the example with the documentation.
🐛 Proposed fix for both flows
- let credential: PublicKeyCredential;
- try {
- credential = (await navigator.credentials.create({
- publicKey:
- challenge.authParamsPublicKey as PublicKeyCredentialCreationOptions,
- })) as PublicKeyCredential;
- } catch (e) {
- throw new PasskeyError(e as Error);
- }
+ let credential: PublicKeyCredential;
+ try {
+ const created = (await navigator.credentials.create({
+ publicKey:
+ challenge.authParamsPublicKey as PublicKeyCredentialCreationOptions,
+ })) as PublicKeyCredential | null;
+ if (!created) {
+ throw new Error('No passkey credential returned');
+ }
+ credential = created;
+ } catch (e) {
+ throw new PasskeyError(e as Error);
+ }Apply the same change to the navigator.credentials.get() block in onPasskeyLogin.
Also applies to: 254-262
🤖 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 `@example/src/App.web.tsx` around lines 218 - 226, Add explicit null checks to
the credential results in both the creation flow and the get flow, using the
surrounding passkey handlers and their PublicKeyCredential assignments. Treat a
null result as an error and throw the existing PasskeyError before assigning or
forwarding the credential; preserve the current catch behavior for rejected
credential operations.
| static let accessTokenKey = "accessToken"; | ||
| static let idTokenKey = "idToken"; | ||
| static let expiresAtKey = "expiresAt"; | ||
| static let sessionExpiresAtKey = "sessionExpiresAt"; |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove the trailing semicolon.
Line 21 violates the configured SwiftLint trailing_semicolon rule. Remove the semicolon to keep the lint check clean.
🧰 Tools
🪛 SwiftLint (0.65.0)
[Warning] 21-21: Lines should not have trailing semicolons
(trailing_semicolon)
🤖 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 `@ios/NativeBridge.swift` at line 21, Update the sessionExpiresAtKey
declaration to remove its trailing semicolon, leaving the string value and
constant unchanged.
Source: Linters/SAST tools
| public getMfaRequiredPayload(): MfaRequiredErrorPayload | null { | ||
| if (this.type !== PasskeyErrorCodes.MFA_REQUIRED) { | ||
| return null; | ||
| } | ||
|
|
||
| const json = this.json as any; | ||
| return { | ||
| mfaToken: json.mfa_token ?? '', | ||
| error: json.error ?? this.code, | ||
| errorDescription: json.error_description ?? this.message, | ||
| mfaRequirements: json.mfa_requirements, | ||
| }; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Handle absent MFA error JSON before reading payload fields.
AuthError.json is optional. If an AuthError has code mfa_required but no JSON body, json is undefined and Line 197 throws.
Normalize this.json to an object before reading fields. Validate mfa_token as a string. Add a test for an MFA-required error without JSON.
Proposed fix
- const json = this.json as any;
+ const json =
+ typeof this.json === 'object' && this.json !== null
+ ? (this.json as Record<string, unknown>)
+ : {};
+
return {
- mfaToken: json.mfa_token ?? '',
- error: json.error ?? this.code,
- errorDescription: json.error_description ?? this.message,
+ mfaToken: typeof json.mfa_token === 'string' ? json.mfa_token : '',
+ error: typeof json.error === 'string' ? json.error : this.code,
+ errorDescription:
+ typeof json.error_description === 'string'
+ ? json.error_description
+ : this.message,
mfaRequirements: json.mfa_requirements,
};📝 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.
| public getMfaRequiredPayload(): MfaRequiredErrorPayload | null { | |
| if (this.type !== PasskeyErrorCodes.MFA_REQUIRED) { | |
| return null; | |
| } | |
| const json = this.json as any; | |
| return { | |
| mfaToken: json.mfa_token ?? '', | |
| error: json.error ?? this.code, | |
| errorDescription: json.error_description ?? this.message, | |
| mfaRequirements: json.mfa_requirements, | |
| }; | |
| public getMfaRequiredPayload(): MfaRequiredErrorPayload | null { | |
| if (this.type !== PasskeyErrorCodes.MFA_REQUIRED) { | |
| return null; | |
| } | |
| const json = | |
| typeof this.json === 'object' && this.json !== null | |
| ? (this.json as Record<string, unknown>) | |
| : {}; | |
| return { | |
| mfaToken: typeof json.mfa_token === 'string' ? json.mfa_token : '', | |
| error: typeof json.error === 'string' ? json.error : this.code, | |
| errorDescription: | |
| typeof json.error_description === 'string' | |
| ? json.error_description | |
| : this.message, | |
| mfaRequirements: json.mfa_requirements, | |
| }; |
🤖 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/models/PasskeyError.ts` around lines 190 - 201, Update
PasskeyError.getMfaRequiredPayload so absent this.json is normalized to an empty
object before accessing payload fields, while preserving the existing fallback
values. Validate that json.mfa_token is a string and use the existing
empty-string fallback otherwise. Add coverage for an MFA_REQUIRED error without
JSON and verify it returns a payload without throwing.
|
|
||
| // Also verify getMfaRequiredPayload() returns structured data | ||
| try { | ||
| await client.getTokenByPasskey({ | ||
| authSession: 'auth-session-123', | ||
| authResponse: rawCredential, | ||
| }); | ||
| } catch (error: any) { | ||
| const payload = error.getMfaRequiredPayload(); | ||
| expect(payload).toEqual({ | ||
| mfaToken: 'mfa_tok_123', | ||
| error: 'mfa_required', | ||
| errorDescription: 'MFA is required', | ||
| mfaRequirements: { | ||
| challenge: [{ type: 'sms' }, { type: 'otp' }], | ||
| enroll: [{ type: 'email' }], | ||
| }, | ||
| }); | ||
| } | ||
| }); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Guard the try/catch assertion against a vacuous pass.
If getTokenByPasskey resolves, the catch block never runs and the test passes without checking getMfaRequiredPayload(). Add expect.assertions or use the rejects form so the payload assertion always executes.
💚 Proposed fix
// Also verify getMfaRequiredPayload() returns structured data
+ expect.assertions(2);
try {
await client.getTokenByPasskey({
authSession: 'auth-session-123',
authResponse: rawCredential,
});
+ throw new Error('Expected getTokenByPasskey to reject');
} catch (error: any) {
const payload = error.getMfaRequiredPayload();🤖 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/web/adapters/__tests__/WebAuth0Client.spec.ts` around lines 956
- 975, Update the getTokenByPasskey test to guarantee rejection and execution of
the getMfaRequiredPayload assertion: add an assertion count covering the
catch-block expectation or use Jest’s rejects form. Preserve the existing
expected payload values and ensure a resolved promise cannot make the test pass.
Merges
masterat v5.11.0 intov6-developmentso the v6 line carries the latest 5.x fixes and features. Keeps the two branches from drifting further apart before v6 ships.What it brings in: IPSIE
session_expiryenforcement with aSESSION_EXPIREDerror, web passkeys support, and My Account API support on the web platform.The v6-only changes are preserved through the merge — the SDK stays New Architecture-only, the legacy Android
oldarchspec remains removed, and thereact-native >=0.82.0peer floor is unchanged..versionandpackage.jsonmove to5.11.0as part of the sync.Summary by CodeRabbit
sessionExpiresAtand aSESSION_EXPIREDerror requiring re-authentication.