Skip to content

Conversation

omar-bear
Copy link
Contributor

@omar-bear omar-bear commented Jul 2, 2025

Describe your changes

Add expo plugin and trusted origins to better-auth config, to make socials login works on start ui native using start ui web server

Summary by CodeRabbit

  • New Features

    • Added Expo/native platform support for authentication, enabling social auth on mobile.
    • Introduced trusted origin(s) to improve auth flows for native apps.
  • Chores

    • Added the Expo auth dependency.
    • Exposed a new AUTH_TRUSTED_ORIGIN configuration variable and updated environment examples and server settings.
  • Localization

    • Added a new authentication error message "USER_ALREADY_HAS_PASSWORD" in English, French, Arabic, and Swahili.

Copy link

vercel bot commented Jul 2, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
start-ui ❌ Failed (Inspect) Jul 3, 2025 3:26pm
start-ui-web-restart ❌ Failed (Inspect) Jul 3, 2025 3:26pm

Copy link
Contributor

coderabbitai bot commented Jul 2, 2025

Walkthrough

Adds Expo social-auth plugin and trustedOrigins to the authentication config, introduces AUTH_TRUSTED_ORIGIN in server env schema and example, updates package dependencies, and adds a new localized auth error key in several locale files.

Changes

Cohort / File(s) Change Summary
Auth configuration
app/server/auth.tsx
Imported expo from @better-auth/expo, added expo() to the plugins array, and added trustedOrigins: string[] to the exported auth configuration (sourced from envServer.AUTH_TRUSTED_ORIGIN).
Environment schema
app/env/server.ts
Added AUTH_TRUSTED_ORIGIN as an optional server env entry (z.string()) to envServer configuration.
Environment example
.env.example
Added AUTH_TRUSTED_ORIGIN in the AUTH section with value "start-ui-native://,start-ui-native://*" and an inline comment indicating it’s the mobile app scheme for trustedOrigins.
Dependencies
package.json
Added dependency @better-auth/expo (1.2.10) and updated better-auth to 1.2.10.
Localization — new error key
app/locales/en/auth.json, app/locales/fr/auth.json, app/locales/ar/auth.json, app/locales/sw/auth.json
Added USER_ALREADY_HAS_PASSWORD entry under errorCode with respective translations.

Sequence Diagram(s)

sequenceDiagram
    participant ExpoApp as Client (Expo/native app)
    participant Server as App Server
    participant BetterAuth as BetterAuth core
    participant ExpoPlugin as @better-auth/expo

    Note over ExpoApp,Server: Native app starts OAuth/social auth flow
    ExpoApp->>Server: auth request / callback
    Server->>BetterAuth: handleAuth(request, { plugins: [..., expo()] })
    Note right of BetterAuth: trustedOrigins checked using envServer.AUTH_TRUSTED_ORIGIN
    BetterAuth->>ExpoPlugin: invoke expo plugin logic
    ExpoPlugin-->>BetterAuth: plugin response
    BetterAuth-->>Server: auth result
    Server-->>ExpoApp: final auth outcome / redirect
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • ntatoud
  • ivan-dalmet
  • yoannfleurydev

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description includes only a brief summary under “Describe your changes” and omits several mandatory sections from the repository’s template—most notably the “## Checklist” section and placeholders for screenshots and documentation—so it does not fully adhere to the required structure. Please update the PR description to include all sections from the template, especially the “## Checklist” with completed review items, and add “## Screenshots” and “## Documentation” entries if applicable, as well as an issue reference under “closes #<issue_id>” if relevant.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title “feat: add expo plugin and trusted origins” directly and succinctly summarizes the primary changes—integrating the Expo plugin and configuring trusted origins—without extraneous details or unrelated terms, making it clear and focused for reviewers.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-add-expo-better-auth

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b7dde30 and 6bb5c73.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • app/locales/ar/auth.json (1 hunks)
  • app/locales/en/auth.json (1 hunks)
  • app/locales/fr/auth.json (1 hunks)
  • app/locales/sw/auth.json (1 hunks)
  • app/server/auth.tsx (3 hunks)
  • package.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/server/auth.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Playwright E2E Tests
  • GitHub Check: 🔬 Tests (24)

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

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c8b459c and 123ca57.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • app/server/auth.tsx (3 hunks)
  • package.json (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
app/server/auth.tsx (1)
Learnt from: ivan-dalmet
PR: BearStudio/start-ui-web#532
File: src/server/config/oauth/providers/discord.ts:11-11
Timestamp: 2024-10-14T15:29:53.279Z
Learning: In `src/server/config/oauth/providers/discord.ts`, when defining the `zDiscordUser` schema, keep fields like `username` as nullable (e.g., `.nullish()`), as the Discord API might return null values despite the documentation stating otherwise.
🧬 Code Graph Analysis (1)
app/server/auth.tsx (1)
app/env/server.ts (1)
  • envServer (9-33)
🪛 ESLint
app/server/auth.tsx

[error] 21-21: 'inferAdditionalFields' is defined but never used. Allowed unused vars must match /^_/u.

(@typescript-eslint/no-unused-vars)


[error] 21-21: Remove this unused import of 'inferAdditionalFields'.

(sonarjs/unused-import)

🔇 Additional comments (4)
package.json (1)

47-47: LGTM - Dependency addition looks correct.

The @better-auth/expo dependency is properly added and the version aligns well with the existing better-auth ecosystem in the project.

app/server/auth.tsx (3)

5-5: LGTM - Expo plugin import correctly added.

The import is properly used in the plugins array configuration.


29-29: LGTM - Trusted origins configuration is appropriate.

The trusted origins configuration with start-ui-native:// and start-ui-native://* properly allows the native Expo app to authenticate with the web server. This follows the expected pattern for Expo deep linking authentication flows.


54-54: LGTM - Expo plugin correctly integrated.

The expo() plugin is properly added to the plugins array and will enable Expo-specific authentication functionality.

import { db } from '@/server/db';
import { sendEmail } from '@/server/email';
import { getUserLanguage } from '@/server/utils';
import { inferAdditionalFields } from 'better-auth/client/plugins';
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove unused import.

The inferAdditionalFields import is not used anywhere in the code and should be removed to keep the codebase clean.

-import { inferAdditionalFields } from 'better-auth/client/plugins';
📝 Committable suggestion

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

Suggested change
import { inferAdditionalFields } from 'better-auth/client/plugins';
🧰 Tools
🪛 ESLint

[error] 21-21: 'inferAdditionalFields' is defined but never used. Allowed unused vars must match /^_/u.

(@typescript-eslint/no-unused-vars)


[error] 21-21: Remove this unused import of 'inferAdditionalFields'.

(sonarjs/unused-import)

🤖 Prompt for AI Agents
In app/server/auth.tsx at line 21, the import statement for
inferAdditionalFields from better-auth/client/plugins is unused. Remove this
import line entirely to clean up the code and avoid unnecessary imports.

Copy link

sonarqubecloud bot commented Jul 3, 2025

Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8776fa0 and fd9c460.

📒 Files selected for processing (2)
  • .env.example (1 hunks)
  • app/env/server.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Playwright E2E Tests

.env.example Outdated
BETTER_AUTH_SECRET="REPLACE ME" # You can use `npx @better-auth/cli@latest secret` to a generated secret
SESSION_EXPIRATION_IN_SECONDS=2592000 # 30 days
SESSION_UPDATE_AGE_IN_SECONDS=86400 # 1 day (every 1 day the session expiration is updated)
AUTH_TRUSTED_ORIGIN="start-ui-native://*" # Mobile app scheme for trustedOrigins config
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Align env var with array semantics and allow multiple trusted origins (CSV).

better-auth expects an array for trustedOrigins. A single AUTH_TRUSTED_ORIGIN is limiting and semantically singular. Consider switching to a plural, comma-separated env to support multiple entries out of the box.

Apply this diff to the example:

-AUTH_TRUSTED_ORIGIN="start-ui-native://*" # Mobile app scheme for trustedOrigins config
+AUTH_TRUSTED_ORIGINS="start-ui-native://,start-ui-native://*" # Mobile app schemes for trustedOrigins config (CSV)

Follow-up:

  • Keep backward compatibility by reading both AUTH_TRUSTED_ORIGINS (CSV) and legacy AUTH_TRUSTED_ORIGIN (single), if you adopt the change in the code.
  • Ensure app/server/auth.tsx parses CSV when building the trustedOrigins array.

Run to locate all usages and assess impact (rename vs. dual support):

Additionally, verify whether better-auth accepts the wildcard form for custom schemes or if plain "scheme://" is sufficient:


🏁 Script executed:

#!/bin/bash
# Find occurrences of the old and proposed env names and trustedOrigins usage
rg -n -A2 -B2 $'AUTH_TRUSTED_ORIGIN\\b|AUTH_TRUSTED_ORIGINS\\b|trustedOrigins\\s*:'

Length of output: 756


🌐 Web query:

What formats does better-auth accept for the `trustedOrigins` option, and are custom URL schemes (e.g., start-ui-native:// or start-ui-native://*) supported?

💡 Result:

Better Auth accepts the following formats for the trustedOrigins option:

  • An array of static origin strings (e.g., "https://example.com")
  • A function that returns a list of origins dynamically
  • Wildcard patterns (including domain wildcards and protocol wildcards)
  • Custom URL schemes such as start-ui-native:// for deep links and mobile authentication flows[1][3][4].

Custom URL Schemes Support:

  • Trusted origins can use custom schemes like start-ui-native:// to enable deep linking for mobile or desktop apps[3][4].
  • You can list your custom scheme directly (e.g., "start-ui-native://").
  • Wildcards with custom schemes are supported when you have varying paths or want to match all routes within the scheme (e.g., "start-ui-native://*")[3].
  • This pattern is especially useful for Expo, React Native, and similar apps leveraging deep links after authentication[3].

Illustrative Example:

trustedOrigins: [
  "https://yourdomain.com",
  "start-ui-native://",
  "start-ui-native://*",
  "myapp-extension://*"
]
  • "start-ui-native://" allows exact matches.
  • "start-ui-native://*" matches any path or resource following the custom scheme, which is necessary if your app handles multiple deep-linked routes[3].

Key Details:

  • Wildcards can be used after both standard protocols and custom schemes, but the scheme itself (e.g., start-ui-native) must match exactly—wildcarding does not change the protocol/scheme matching logic[4].
  • For web origins, both domain and protocol wildcards are also supported (e.g., "https://*.example.com", "*.example.com"), with HTTPS preferred for security[4][1].
  • Custom schemes are intended for apps and browser extensions; for browsers, redirection to custom schemes usually must be handled client-side for security reasons[8].

References:

  • Full documentation: Better Auth config reference[1], security and trusted origins explanation[4], and Expo integration docs highlighting custom schemes and wildcards[3].
  • Client-side handling for redirects with custom schemes: GitHub discussion[8].

In summary:
Better Auth’s trustedOrigins can accept static URLs, dynamic lists, wildcard patterns, and custom URL schemes (including wildcards such as start-ui-native://*). Custom URL schemes are a first-class feature for deep linking in mobile and desktop apps and should be explicitly listed in your configuration for safe origin handling[3][4].

Citations:


Align AUTH_TRUSTED_ORIGINS for multiple origins

To support an array of trusted origins while preserving backward-compatibility:

• .env.example

-AUTH_TRUSTED_ORIGIN="start-ui-native://*" # Mobile app scheme for trustedOrigins config
+AUTH_TRUSTED_ORIGINS="start-ui-native://,start-ui-native://*" # Mobile app schemes for trustedOrigins config (CSV)

• app/env/server.ts
– Replace AUTH_TRUSTED_ORIGIN: z.string()
– Add AUTH_TRUSTED_ORIGINS: z.string().default('').transform(s => s.split(',').filter(Boolean))
– In your server config, coalesce:

const rawOrigins = env.AUTH_TRUSTED_ORIGINS.length
  ? env.AUTH_TRUSTED_ORIGINS
  : [env.AUTH_TRUSTED_ORIGIN];

• app/server/auth.tsx
– Change

trustedOrigins: [envServer.AUTH_TRUSTED_ORIGIN],

to

trustedOrigins: rawOrigins,

Ensure you read the new AUTH_TRUSTED_ORIGINS CSV first and fall back to the legacy AUTH_TRUSTED_ORIGIN for a smooth migration.

🤖 Prompt for AI Agents
In .env.example around line 26, the current AUTH_TRUSTED_ORIGIN entry only
supports a single origin; update the app to accept multiple origins by adding a
CSV-based AUTH_TRUSTED_ORIGINS variable and adjusting server parsing and usage:
in app/env/server.ts replace the single z.string() validator with a
z.string().default('').transform to split on commas and filter empties, and
coalesce at runtime to use AUTH_TRUSTED_ORIGINS when present or fall back to the
legacy AUTH_TRUSTED_ORIGIN; then update app/server/auth.tsx to pass the computed
rawOrigins to trustedOrigins instead of the single envServer.AUTH_TRUSTED_ORIGIN
so both multi-origin CSV and the old single value remain supported during
migration.

BETTER_AUTH_SECRET: z.string(),
SESSION_EXPIRATION_IN_SECONDS: z.coerce.number().int().default(2592000), // 30 days by default
SESSION_UPDATE_AGE_IN_SECONDS: z.coerce.number().int().default(86400), // 1 day by default
AUTH_TRUSTED_ORIGIN: z.string(),
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Provide a sane default and reduce friction in local dev.

AUTH_TRUSTED_ORIGIN is required with no default, while .env.example suggests "start-ui-native://*". Add a default to keep parity and avoid failures when the env is not set.

Apply this diff:

-    AUTH_TRUSTED_ORIGIN: z.string(),
+    AUTH_TRUSTED_ORIGIN: z.string().default('start-ui-native://*'),

Optional (future-proofing): if you decide to support multiple origins via CSV as suggested in .env.example, consider this alternative and adjust downstream code to expect an array:

// Optionally add alongside AUTH_TRUSTED_ORIGIN for backwards compatibility:
AUTH_TRUSTED_ORIGINS: z
  .string()
  .default('start-ui-native://,start-ui-native://*')
  .transform((v) =>
    v
      .split(',')
      .map((s) => s.trim())
      .filter(Boolean),
  ),

Confirm that app/server/auth.tsx actually consumes envServer.AUTH_TRUSTED_ORIGIN (or the proposed AUTH_TRUSTED_ORIGINS) when building the betterAuth trustedOrigins array, and that you’re not unintentionally hardcoding values:


🏁 Script executed:

#!/bin/bash
# Check usage of trustedOrigins and whether the env var is wired through
rg -n -A5 -B5 $'trustedOrigins\\s*:|AUTH_TRUSTED_ORIGIN\\b|AUTH_TRUSTED_ORIGINS\\b' app

Length of output: 1339


Provide a sane default for AUTH_TRUSTED_ORIGIN in your env schema

To match your .env.example and avoid runtime failures when AUTH_TRUSTED_ORIGIN isn’t set, add a default:

• File: app/env/server.ts (line 15)

-    AUTH_TRUSTED_ORIGIN: z.string(),
+    AUTH_TRUSTED_ORIGIN: z.string().default('start-ui-native://*'),

Optional future-proofing (support multiple origins via CSV):

AUTH_TRUSTED_ORIGINS: z
  .string()
  .default('start-ui-native://,start-ui-native://*')
  .transform(v =>
    v
      .split(',')
      .map(s => s.trim())
      .filter(Boolean),
  )

Note: app/server/auth.tsx already uses envServer.AUTH_TRUSTED_ORIGIN in its trustedOrigins array, so this default will be picked up automatically.

🤖 Prompt for AI Agents
In app/env/server.ts around line 15, the env schema requires AUTH_TRUSTED_ORIGIN
but provides no default which can cause runtime failures when the variable is
not set; update the zod schema to supply a sensible default (matching
.env.example) — e.g. set AUTH_TRUSTED_ORIGIN to a default like
'start-ui-native://,start-ui-native://*' or alternatively add
AUTH_TRUSTED_ORIGINS as a CSV string with a transform to produce an array of
trimmed, non-empty origins — ensure the schema uses .default(...) and, if using
the CSV approach, .transform(...) to split, trim and filter values so
app/server/auth.tsx can safely read trusted origins without runtime errors.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/server/auth.tsx (1)

28-29: Consider support for multiple trusted origins and fix grammar.

The current implementation wraps a single environment variable in an array. If multiple trusted origins are needed (e.g., for different mobile apps or environments), consider updating AUTH_TRUSTED_ORIGIN to accept a comma-separated list and splitting it here, or updating the environment schema to accept an array.

Additionally, the comment has a grammatical error: "can be delete" should be "can be deleted".

Apply this diff to fix the grammar:

-  // Allows an expo native app to use social auth, can be delete if no needed
+  // Allows an expo native app to use social auth, can be deleted if not needed

If multiple origins should be supported, consider this approach:

-  trustedOrigins: [envServer.AUTH_TRUSTED_ORIGIN],
+  trustedOrigins: envServer.AUTH_TRUSTED_ORIGIN.split(',').map(s => s.trim()),

And update the environment schema in app/env/server.ts accordingly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd9c460 and cb74fd7.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • .env.example (1 hunks)
  • app/env/server.ts (1 hunks)
  • app/server/auth.tsx (3 hunks)
  • package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • .env.example
  • app/env/server.ts
🧰 Additional context used
🧬 Code graph analysis (1)
app/server/auth.tsx (1)
app/env/server.ts (1)
  • envServer (9-34)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: 🔬 Tests (24)
  • GitHub Check: 🔬 Tests (22)
  • GitHub Check: 🔬 Tests (lts/*)
  • GitHub Check: Playwright E2E Tests
🔇 Additional comments (1)
app/server/auth.tsx (1)

1-1: The server-side expo() plugin requires no initialization parameters; calling expo() with no arguments is correct.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
app/env/server.ts (1)

15-15: Downstream handling confirmed, but add default for AUTH_TRUSTED_ORIGIN
The ternary in app/server/auth.tsx safely guards against undefined, so no runtime errors occur. However, to align with your .env.example and ensure a working default for local development, update the schema entry to:

AUTH_TRUSTED_ORIGIN: z.string().default('start-ui-native://*'),
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb74fd7 and b7dde30.

📒 Files selected for processing (3)
  • .env.example (1 hunks)
  • app/env/server.ts (1 hunks)
  • app/server/auth.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • .env.example
  • app/server/auth.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 🔬 Tests (22)
  • GitHub Check: 🔬 Tests (24)
  • GitHub Check: Playwright E2E Tests

Copy link

sonarqubecloud bot commented Oct 1, 2025

@HugoPerard HugoPerard merged commit 44fb48d into v3-main Oct 1, 2025
12 checks passed
@HugoPerard HugoPerard deleted the feat-add-expo-better-auth branch October 1, 2025 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants