Clerk Auth Implementation#4
Conversation
|
Warning Review limit reached
Next review available in: 23 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughIntegrates Clerk authentication into the Expo app with a root provider, auth-gated auth/tab layouts, sign-in and sign-up flows, authenticated user UI in tabs, and fallback text for missing subscription fields. ChangesClerk Authentication Integration
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 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: 9
🤖 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 `@app/_layout.tsx`:
- Around line 36-40: The ClerkProvider setup currently relies on a non-null
assertion for process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY, which can still
pass undefined at runtime and hide misconfiguration. Update the _layout
component to validate the Clerk publishable key before rendering ClerkProvider,
and throw a descriptive error if it is missing so the app fails fast during
bootstrap. Use the existing tokenCache and ClerkProvider render path as the
place to insert this guard, keeping the check close to where the key is
consumed.
- Around line 36-40: The root layout is hiding the splash too early, which can
reveal a blank frame before Clerk auth finishes loading. Update the root layout
in the component that wraps ClerkProvider and Stack to keep the
splash/placeholder visible until Clerk is loaded, or render a minimal loading
shell there instead of relying only on font readiness. Coordinate this with the
auth and tabs layouts that use useAuth().isLoaded so the app does not briefly
return null during cold start.
In `@app/`(auth)/sign-in.tsx:
- Around line 31-32: The sign-in flow is logging sensitive auth/session data in
`signIn` and related success/error paths, so replace the raw JSON/stringified
payloads and `session?.currentTask` output with generic messages only. Update
the logging in `app/(auth)/sign-in.tsx` around the `error` handling and session
usage to be gated behind `__DEV__`, and keep production logs free of auth
details.
- Around line 46-53: The sign-in flow in the needs_client_trust branch can
advance to the verification screen even when the email-code challenge is
unavailable or sendEmailCode() fails. Update the sign-in handler around
signIn.status, emailCodeFactor, and signIn.mfa.sendEmailCode() so the
verification step is reached only after confirming the email_code factor exists
and the challenge request succeeds; otherwise stop the transition and surface a
recoverable error or fallback path.
In `@app/`(auth)/sign-up.tsx:
- Around line 31-32: The sign-up error handling currently logs raw Clerk auth
state, which can expose sensitive identifiers and session details. In the
sign-up flow, update the `error` logging around the `signUp` /
`session.currentTask` checks to use a short dev-only message instead of
serializing the objects directly. Keep any debugging output gated behind a
development-only condition so nothing sensitive is emitted in production.
- Around line 99-102: The resend action in the sign-up flow is not guarded, so
repeated taps on the Pressable can trigger duplicate sendEmailCode() requests
and swallow failures. Update the signUp.verifications.sendEmailCode handler to
track an in-flight/loading state, disable the Pressable while the request is
pending, and catch errors so they surface as a local error state instead of
failing silently.
- Line 36: The sign-up flow in sign-up.tsx currently sends an email code
unconditionally after signUp.password(), which can stall when the remaining
missing_requirements are not an unverified email address. Update the logic
around signUp.password() and signUp.verifications.sendEmailCode() to first
inspect the Clerk state: if signUp.password() can already complete, finalize the
flow there, and only call sendEmailCode() when missing_requirements explicitly
includes an unverified email_address. Use the existing signUp,
missing_requirements, and sendEmailCode symbols to place the fix in the correct
branch.
In `@app/`(tabs)/index.tsx:
- Around line 21-22: The import order in index.tsx is invalid because the later
ESM imports must stay before the runtime statement that defines SafeAreaView.
Move the useUser/useClerk and Pressable imports above the SafeAreaView styled
declaration, keeping all imports grouped at the top so the module parses
correctly.
In `@app/`(tabs)/settings.tsx:
- Around line 13-15: The fallback display name and email lookup in settings are
using emailAddresses[0], which can pick the wrong address for users with
multiple emails. Update the settings screen logic around the displayName and
email values to use the primary email source instead of the first entry, and
apply the same fallback-name pattern used in app/(tabs)/index.tsx so both places
resolve identity from the same reliable field.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 853cc3d1-4400-4c86-b3b8-6eea82a75f4a
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (10)
app.jsonapp/(auth)/_layout.tsxapp/(auth)/sign-in.tsxapp/(auth)/sign-up.tsxapp/(tabs)/_layout.tsxapp/(tabs)/index.tsxapp/(tabs)/settings.tsxapp/_layout.tsxcomponents/SubscriptionCard.tsxpackage.json
| if (error) { | ||
| console.error(JSON.stringify(error, null, 2)); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file list =="
git ls-files 'app/(auth)/sign-in.tsx'
echo
echo "== outline =="
ast-grep outline 'app/(auth)/sign-in.tsx' --view expanded || true
echo
echo "== relevant lines =="
cat -n 'app/(auth)/sign-in.tsx' | sed -n '1,220p'
echo
echo "== console usages in file =="
rg -n 'console\.(log|error)|__DEV__|session\?\.currentTask|JSON\.stringify\(error' 'app/(auth)/sign-in.tsx'Repository: saikumarbt/react-native-recurly
Length of output: 8692
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Inspecting app/(auth)/sign-in.tsx...\n'
if [ -f 'app/(auth)/sign-in.tsx' ]; then
nl -ba 'app/(auth)/sign-in.tsx' | sed -n '1,220p'
fiRepository: saikumarbt/react-native-recurly
Length of output: 246
Avoid logging raw auth/session payloads. JSON.stringify(error, null, 2) and session?.currentTask can leak sensitive auth details into device logs; keep these messages generic and behind __DEV__. Also applies to app/(auth)/sign-in.tsx:39-40, 63-64.
🤖 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 `@app/`(auth)/sign-in.tsx around lines 31 - 32, The sign-in flow is logging
sensitive auth/session data in `signIn` and related success/error paths, so
replace the raw JSON/stringified payloads and `session?.currentTask` output with
generic messages only. Update the logging in `app/(auth)/sign-in.tsx` around the
`error` handling and session usage to be gated behind `__DEV__`, and keep
production logs free of auth details.
| } else if (signIn.status === "needs_client_trust") { | ||
| const emailCodeFactor = signIn.supportedSecondFactors.find( | ||
| (factor) => factor.strategy === "email_code", | ||
| ); | ||
|
|
||
| if (emailCodeFactor) { | ||
| await signIn.mfa.sendEmailCode(); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- app/(auth)/sign-in.tsx (outline) ---'
ast-grep outline 'app/(auth)/sign-in.tsx' --view expanded || true
echo
echo '--- relevant lines in app/(auth)/sign-in.tsx ---'
nl -ba 'app/(auth)/sign-in.tsx' | sed -n '1,180p'
echo
echo '--- search for needs_client_trust / sendEmailCode / verification screen ---'
rg -n 'needs_client_trust|sendEmailCode|email_code|verificationError|Enter the code sent to your email|auth-error' app -S || trueRepository: saikumarbt/react-native-recurly
Length of output: 411
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- app/(auth)/sign-in.tsx (1-220 with line numbers) ---'
awk '{printf("%4d %s\n", NR, $0)}' 'app/(auth)/sign-in.tsx' | sed -n '1,220p'
echo
echo '--- targeted search in app/ ---'
rg -n 'needs_client_trust|sendEmailCode|email_code|verificationError|Enter the code sent to your email|auth-error' app -S || trueRepository: saikumarbt/react-native-recurly
Length of output: 9014
Guard the email-code challenge before switching to the verification screen.
If email_code isn’t offered or sendEmailCode() fails, the sign-in flow still lands on the verify step with no way to continue or recover.
🤖 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 `@app/`(auth)/sign-in.tsx around lines 46 - 53, The sign-in flow in the
needs_client_trust branch can advance to the verification screen even when the
email-code challenge is unavailable or sendEmailCode() fails. Update the sign-in
handler around signIn.status, emailCodeFactor, and signIn.mfa.sendEmailCode() so
the verification step is reached only after confirming the email_code factor
exists and the challenge request succeeds; otherwise stop the transition and
surface a recoverable error or fallback path.
| if (error) { | ||
| console.error(JSON.stringify(error, null, 2)); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE='app/(auth)/sign-up.tsx'
wc -l "$FILE"
cat -n "$FILE" | sed -n '1,140p'Repository: saikumarbt/react-native-recurly
Length of output: 5604
🌐 Web query:
Clerk Expo signUp object currentTask session.currentTask documentation properties sensitive logging
💡 Result:
In Clerk Expo and related SDKs, session tasks and sign-up objects handle authentication flows with the following characteristics: Session and currentTask The Session object contains a currentTask property [1], which represents a pending session task that must be completed before a session can be fully activated [2]. If a session has a pending task, it remains in a pending state and generally cannot access protected resources [2]. You can access the session object using the useSession hook and check the currentTask property to determine if the user needs to complete further steps (e.g., MFA or profile completion) [1][2]. SignUp Object The SignUp object manages the lifecycle of a sign-up attempt [3]. It tracks status (e.g., complete, missing_requirements) and provides properties to manage identification fields (like email or phone number) and metadata [3][4][5]. A newer, experimental SignUpFuture object is also available for use in custom flows, offering a different API for driving account creation [4][5]. When a sign-up process is complete, its createdSessionId can be used to finalize the session [6][3]. Sensitive Logging Clerk provides mechanisms for debugging and telemetry, but users should be cautious regarding sensitive data: 1. Debug Logging: Clerk has introduced a debug logging subsystem (debugLogger) that provides insights into events like load, navigation, and session activation [7]. Because these logs may contain identifiers (user IDs, session IDs) or context data, care should be taken when using features that forward these to external endpoints [7]. 2. Telemetry: Clerk collects telemetry data for product improvements, which is strictly audited to exclude sensitive information like passwords, tokens, raw file contents, or PII [8][9]. You can opt out of telemetry using environment variables (e.g., CLERK_TELEMETRY_DISABLED=1) or the telemetry prop on the ClerkProvider component [8][9]. 3. Application Logs: The Clerk Dashboard's Application Logs page tracks security-relevant events (e.g., sign_in.completed) [10]. These logs are designed for auditing and debugging, and you should ensure that any custom logging you implement in your application does not inadvertently expose sensitive user information [10].
Citations:
- 1: https://clerk.com/docs/expo/reference/objects/session
- 2: https://clerk.com/docs/guides/development/custom-flows/authentication/session-tasks
- 3: https://clerk.com/docs/expo/reference/objects/sign-up
- 4: https://cdn.jsdelivr.net/npm/@clerk/clerk-js@6.4.0/dist/types/core/resources/SignUp.d.ts
- 5: https://clerk.com/docs/react-router/reference/objects/sign-up-future
- 6: https://clerk.com/docs/expo/reference/objects/sign-up-future
- 7: feat(clerk-js): Introduce debugLogger clerk/javascript#6452
- 8: https://clerk.com/docs/guides/how-clerk-works/security/clerk-telemetry
- 9: https://clerk.com/legal/telemetry
- 10: https://clerk.com/docs/guides/dashboard/logs/application-logs
Avoid logging raw Clerk auth state. error, session.currentTask, and signUp can expose identifiers and verification/session details; keep these logs out of production and replace them with a short dev-only message.
🤖 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 `@app/`(auth)/sign-up.tsx around lines 31 - 32, The sign-up error handling
currently logs raw Clerk auth state, which can expose sensitive identifiers and
session details. In the sign-up flow, update the `error` logging around the
`signUp` / `session.currentTask` checks to use a short dev-only message instead
of serializing the objects directly. Keep any debugging output gated behind a
development-only condition so nothing sensitive is emitted in production.
| return; | ||
| } | ||
|
|
||
| if (!error) await signUp.verifications.sendEmailCode(); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Handle the Clerk state before requesting a code. If signUp.password() can already complete, finalize there; only call sendEmailCode() when missing_requirements includes an unverified email_address, otherwise this sign-up flow can stall on non-verification 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 `@app/`(auth)/sign-up.tsx at line 36, The sign-up flow in sign-up.tsx currently
sends an email code unconditionally after signUp.password(), which can stall
when the remaining missing_requirements are not an unverified email address.
Update the logic around signUp.password() and
signUp.verifications.sendEmailCode() to first inspect the Clerk state: if
signUp.password() can already complete, finalize the flow there, and only call
sendEmailCode() when missing_requirements explicitly includes an unverified
email_address. Use the existing signUp, missing_requirements, and sendEmailCode
symbols to place the fix in the correct branch.
| <Pressable | ||
| className="auth-secondary-button mt-4" | ||
| onPress={() => signUp.verifications.sendEmailCode()} | ||
| > |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the target file and inspect the relevant region.
git ls-files 'app/(auth)/sign-up.tsx'
wc -l app/(auth)/sign-up.tsx
sed -n '1,180p' app/(auth)/sign-up.tsxRepository: saikumarbt/react-native-recurly
Length of output: 245
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file='app/(auth)/sign-up.tsx'
printf '\n== file exists ==\n'
git ls-files -- "$file"
printf '\n== line count ==\n'
wc -l -- "$file"
printf '\n== excerpt ==\n'
sed -n '1,220p' -- "$file"
printf '\n== search for resend and fetch status ==\n'
rg -n 'sendEmailCode|fetchStatus|disabled=' -- "$file"Repository: saikumarbt/react-native-recurly
Length of output: 7782
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect surrounding symbols to understand whether the button is already guarded elsewhere.
ast-grep outline 'app/(auth)/sign-up.tsx' --view expandedRepository: saikumarbt/react-native-recurly
Length of output: 280
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file='app/(auth)/sign-up.tsx'
printf '\n== excerpt around the button ==\n'
sed -n '70,130p' -- "$file"
printf '\n== grep for related state/handlers in file ==\n'
rg -n 'fetchStatus|signUp|verifications|sendEmailCode|disabled|loading|isLoading|pending|inFlight' -- "$file"Repository: saikumarbt/react-native-recurly
Length of output: 3421
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file='app/(auth)/sign-up.tsx'
printf '\n== excerpt around the button ==\n'
sed -n '1,220p' -- "$file"
printf '\n== symbols in the file ==\n'
rg -n 'fetchStatus|sendEmailCode|verifications|disabled|onPress|useState|useEffect|signUp' -- "$file"Repository: saikumarbt/react-native-recurly
Length of output: 8350
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Look for other resend-code implementations in the repo for comparison.
rg -n 'sendEmailCode\(\)|verifications\.sendEmailCode|resend.*code|email code' .Repository: saikumarbt/react-native-recurly
Length of output: 425
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the target component in smaller chunks to avoid the shell parsing issue.
file='app/(auth)/sign-up.tsx'
printf '\n== 1-140 ==\n'
sed -n '1,140p' -- "$file"
printf '\n== 141-260 ==\n'
sed -n '141,260p' -- "$file"Repository: saikumarbt/react-native-recurly
Length of output: 7058
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file='app/(auth)/sign-up.tsx'
# Show the exact lines around the resend button with line numbers.
nl -ba -- "$file" | sed -n '85,115p'
# Check whether this file already tracks a pending/error state for email-code resend.
rg -n 'error|pending|loading|disabled|sendEmailCode|verifications' -- "$file"Repository: saikumarbt/react-native-recurly
Length of output: 209
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Compare with any other sign-up or verification flows that handle resend/sendEmailCode.
rg -n 'sendEmailCode|send.*code|resend.*code|verification' app components srcRepository: saikumarbt/react-native-recurly
Length of output: 712
🌐 Web query:
Clerk signUp.verifications.sendEmailCode promise reject duplicate request in-flight resend code behavior
💡 Result:
When using Clerk's signUp.verifications.sendEmailCode() method, there is no built-in "promise rejection" specifically for "duplicate requests in-flight" that prevents the API call from executing. The method initiates a network request to the Clerk Frontend API to prepare the verification strategy [1][2][3]. Historically, Clerk has faced issues where multiple verification codes were triggered unintentionally, such as during component re-mounts, page refreshes, or React Strict Mode re-renders [4][5][6]. Recent updates, including PR #8548 (May 2026), have introduced deduplication logic to the Clerk UI components to prevent unnecessary re-preparation of pending verifications [7]. Key behaviors regarding duplicate or in-flight requests include: 1. Request Execution: Calling sendEmailCode() will generally trigger a network request [1][8]. If you call it multiple times manually (e.g., via rapid button clicks), the SDK will send multiple requests to the API, which may result in multiple emails being sent [9][10]. 2. SDK Deduplication: As of May 2026, Clerk's prebuilt UI components are designed to check the state of the existing signUp or signIn resource before calling "prepare" methods [7]. If a pending (unverified) verification is already present, these components will skip the automatic preparation to avoid sending a new code unless the user explicitly triggers a "Resend" action [7]. 3. Manual Implementation: If you are building a custom flow, the SDK does not automatically deduplicate multiple calls made by your code [9][10]. It is recommended to manage the "loading" or "in-flight" state manually in your application code—for example, by disabling the "Resend" button or tracking the request status—to prevent users from triggering multiple parallel requests [8]. 4. API Behavior: Calling prepare methods while a verification is already active usually invalidates the previous code and triggers a new one [9]. Relying on the API to handle deduplication is not recommended; client-side throttling or state management is the standard approach to ensure only one request is sent at a time [9][8]. To prevent duplicate codes in custom implementations, ensure your code checks the status of the signUp resource or manages a local loading state before executing the promise returned by sendEmailCode() [8].
Citations:
- 1: https://clerk.com/docs/expo/reference/objects/sign-up-future
- 2: https://cdn.jsdelivr.net/npm/@clerk/clerk-js@6.4.0/dist/types/core/resources/SignUp.d.ts
- 3: https://clerk-android.clerkstage.dev/source/api/com.clerk.api.signup/send-email-code.html
- 4: <SignIn> sends a new email OTP on every mount/refresh while a pending verification already exists clerk/javascript#8463
- 5: fix(clerk-js): Avoid triggering email code verification twice on React strict mode clerk/javascript#5095
- 6: Receiving Twice Email Verification Codes During Sign-In with Clerk clerk/javascript#4324
- 7: fix(ui): avoid re-preparing pending code verifications clerk/javascript#8548
- 8: https://clerk.com/docs/guides/development/custom-flows/authentication/email-sms-otp
- 9:
signIn.prepareFirstFactorsending two emails with different codes clerk/javascript#887 - 10: signInWithOtp can send duplicate email OTPs for email_code sign-in clerk/clerk-android#640
Disable the resend action while sendEmailCode() is in flight. It can fire duplicate requests on repeated taps, and failures should surface a local error instead of failing silently.
🤖 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 `@app/`(auth)/sign-up.tsx around lines 99 - 102, The resend action in the
sign-up flow is not guarded, so repeated taps on the Pressable can trigger
duplicate sendEmailCode() requests and swallow failures. Update the
signUp.verifications.sendEmailCode handler to track an in-flight/loading state,
disable the Pressable while the request is pending, and catch errors so they
surface as a local error state instead of failing silently.
| const displayName = user?.firstName || user?.fullName || user?.emailAddresses[0]?.emailAddress?.split("@")[0] || "User"; | ||
| const email = user?.emailAddresses[0]?.emailAddress || "No email"; | ||
| const memberSince = user?.createdAt ? dayjs(user.createdAt).format("MMMM D, YYYY") : "Recently"; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the referenced files and inspect the relevant lines.
git ls-files 'app/(tabs)/*.tsx' | sed 's#^`#FILE` #'
echo
echo '--- app/(tabs)/settings.tsx ---'
cat -n 'app/(tabs)/settings.tsx' | sed -n '1,120p'
echo
echo '--- app/(tabs)/index.tsx ---'
cat -n 'app/(tabs)/index.tsx' | sed -n '1,120p'
echo
echo '--- Search for Clerk email fields ---'
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' 'primaryEmailAddress|emailAddresses\[0\]|fullName|firstName' .Repository: saikumarbt/react-native-recurly
Length of output: 8589
🌐 Web query:
Clerk UserResource primaryEmailAddress emailAddresses ordering first item primary email address
💡 Result:
In Clerk's User object, the emailAddresses property is an array of all email addresses associated with the user [1][2]. This array is not guaranteed to be ordered in any specific way, such as placing the primary email address at the first index [1][2]. To reliably retrieve the primary email address from the User object, you should use the primaryEmailAddress property (if available in your environment) or derive it using the primaryEmailAddressId [1][3][4]. When using the Clerk frontend SDKs (e.g., in React), the User object typically includes a primaryEmailAddress property that directly points to the primary EmailAddressResource [1][4]. When using backend SDKs or environments where primaryEmailAddress is not provided, you can identify the primary email by matching the primaryEmailAddressId against the emailAddresses array [4]: const primaryEmail = user.emailAddresses.find( (email) => email.id === user.primaryEmailAddressId); This approach ensures you correctly identify the primary email regardless of its position within the emailAddresses array [4].
Citations:
- 1: https://clerk.com/docs/react/reference/objects/user
- 2: https://clerk.com/docs/nextjs/reference/objects/user
- 3: https://clerk.com/docs/reference/backend/types/backend-user
- 4:
useUserhas a differently typed user object thancurrentUserandclerkClient.users.getUserclerk/javascript#2176
Use the primary email instead of emailAddresses[0]. emailAddresses is an unordered list, so the first item can be the wrong address for multi-email users. app/(tabs)/index.tsx:31 uses the same fallback-name pattern and should follow the same source.
🤖 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 `@app/`(tabs)/settings.tsx around lines 13 - 15, The fallback display name and
email lookup in settings are using emailAddresses[0], which can pick the wrong
address for users with multiple emails. Update the settings screen logic around
the displayName and email values to use the primary email source instead of the
first entry, and apply the same fallback-name pattern used in
app/(tabs)/index.tsx so both places resolve identity from the same reliable
field.
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)
app/_layout.tsx (1)
29-35: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winDuplicate
if (!fontsLoaded) return null;block.Lines 29-31 and 33-35 are identical guards; the second is dead code left over from editing.
♻️ Proposed fix
if (!fontsLoaded) { return null; } - if (!fontsLoaded) { - return null; - } - const publishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY;🤖 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 `@app/_layout.tsx` around lines 29 - 35, There is a duplicated fonts-loaded guard in the _layout component: the second identical `if (!fontsLoaded) return null;` block is dead code. Remove the redundant duplicate and keep only one early return in the layout logic so the component continues after `fontsLoaded` is true.
🤖 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 `@app/_layout.tsx`:
- Around line 29-35: There is a duplicated fonts-loaded guard in the _layout
component: the second identical `if (!fontsLoaded) return null;` block is dead
code. Remove the redundant duplicate and keep only one early return in the
layout logic so the component continues after `fontsLoaded` is true.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 54b20335-9146-4e0f-9119-0aa394bd77cb
📒 Files selected for processing (2)
.env.exampleapp/_layout.tsx
No description provided.