[GH-ISSUE #4496] Expo with Phone/Annonymous Plugins Fail #9957

Closed
opened 2026-04-13 05:48:42 -05:00 by GiteaMirror · 8 comments
Owner

Originally created by @SamJbori on GitHub (Sep 7, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/4496

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Follow better-auth guide for expo
  2. add anonymousClient or phoneNumberClient from better-auth/client/plugins

Current vs. Expected behavior

I wasn't expecting the app to error

What version of Better Auth are you using?

1.3.7

System info

{
  "system": {
    "platform": "linux",
    "arch": "x64",
    "version": "#1 SMP PREEMPT_DYNAMIC Debian 6.12.41-1 (2025-08-12)",
    "release": "6.12.41+deb13-amd64",
    "cpuCount": 8,
    "cpuModel": "Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz",
    "totalMemory": "31.11 GB",
    "freeMemory": "13.79 GB"
  },
  "node": {
    "version": "v22.18.0",
    "env": "development"
  },
  "packageManager": {
    "name": "pnpm",
    "version": "10.15.1"
  },
  "frameworks": [
    {
      "name": "react",
      "version": "19.0.0"
    }
  ],
  "databases": null,
  "betterAuth": {
    "version": "1.0.0", <- I am running 1.3.8 dead sure
    "config": null
  }
}

Which area(s) are affected? (Select all that apply)

Client

Auth config (if applicable)

import { createAuthClient } from "better-auth/react";
import { expoClient } from "@better-auth/expo/client";
import {
  phoneNumberClient,
  inferAdditionalFields,
  anonymousClient,
} from "better-auth/client/plugins";
import * as SecureStore from "expo-secure-store";
import type { auth } from "@hwa/server";

const authClient = createAuthClient({
  baseURL: "https://api.myapp.com", // Base URL of your Better Auth backend.
  plugins: [
    inferAdditionalFields<typeof auth>(),
    anonymousClient(),
    phoneNumberClient(),
    expoClient({
      scheme: "myapp",
      storagePrefix: "myapp",
      storage: SecureStore,
    }),
  ],
});

export const {
  phoneNumber: { sendOtp, verify: verifyOtp },
  signOut,
  useSession,
  getCookie,
} = authClient;

Additional context

No response

Originally created by @SamJbori on GitHub (Sep 7, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/4496 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Follow `better-auth` guide for expo 2. add `anonymousClient` or `phoneNumberClient` from `better-auth/client/plugins` ### Current vs. Expected behavior I wasn't expecting the app to error ### What version of Better Auth are you using? 1.3.7 ### System info ```bash { "system": { "platform": "linux", "arch": "x64", "version": "#1 SMP PREEMPT_DYNAMIC Debian 6.12.41-1 (2025-08-12)", "release": "6.12.41+deb13-amd64", "cpuCount": 8, "cpuModel": "Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz", "totalMemory": "31.11 GB", "freeMemory": "13.79 GB" }, "node": { "version": "v22.18.0", "env": "development" }, "packageManager": { "name": "pnpm", "version": "10.15.1" }, "frameworks": [ { "name": "react", "version": "19.0.0" } ], "databases": null, "betterAuth": { "version": "1.0.0", <- I am running 1.3.8 dead sure "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Client ### Auth config (if applicable) ```typescript import { createAuthClient } from "better-auth/react"; import { expoClient } from "@better-auth/expo/client"; import { phoneNumberClient, inferAdditionalFields, anonymousClient, } from "better-auth/client/plugins"; import * as SecureStore from "expo-secure-store"; import type { auth } from "@hwa/server"; const authClient = createAuthClient({ baseURL: "https://api.myapp.com", // Base URL of your Better Auth backend. plugins: [ inferAdditionalFields<typeof auth>(), anonymousClient(), phoneNumberClient(), expoClient({ scheme: "myapp", storagePrefix: "myapp", storage: SecureStore, }), ], }); export const { phoneNumber: { sendOtp, verify: verifyOtp }, signOut, useSession, getCookie, } = authClient; ``` ### Additional context _No response_
GiteaMirror added the locked label 2026-04-13 05:48:42 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Sep 7, 2025):

Hi @SamJbori! I'm Dosu and I’m helping the better-auth team.

This is a known compatibility issue: using anonymousClient or phoneNumberClient in Expo/React Native can trigger build errors because some dependencies (like jose or Node.js built-ins such as buffer and crypto) aren't available in the Expo runtime. This is especially true for Better Auth versions before and including 1.3.7, but even 1.3.8 only partially resolves it—Expo support for these plugins is still limited due to their server-oriented dependencies [source].

The expoClient plugin is safe for Expo, but the other plugins may still cause runtime errors. The latest release (after PR #4433) updates jose and related crypto dependencies to versions that avoid some Node.js built-ins, but you must use Node 20.19+ for development/builds [source].

What you can do:

  • Double-check your installed Better Auth version (pnpm list better-auth or check node_modules) to ensure you’re on 1.3.8+.
  • If you’re still seeing errors, please share the exact error message or stack trace—this will help confirm if it’s a Node.js built-in issue.
  • If the error is about missing Node modules (like node:buffer or node:crypto), there’s no full workaround except to avoid these plugins in Expo, or move the logic to your backend.
  • For Expo Web, avoid using client.getCookie()—use fetch with credentials: 'include' instead [source].

If you need phone/anonymous auth in Expo, the safest approach is to implement those flows on your backend and only use Expo-compatible plugins on the client. Let me know the error details if you want to dig deeper!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3263861225 --> @dosubot[bot] commented on GitHub (Sep 7, 2025): <!-- Greeting --> Hi @SamJbori! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a known compatibility issue: using `anonymousClient` or `phoneNumberClient` in Expo/React Native can trigger build errors because some dependencies (like `jose` or Node.js built-ins such as `buffer` and `crypto`) aren't available in the Expo runtime. This is especially true for Better Auth versions before and including 1.3.7, but even 1.3.8 only partially resolves it—Expo support for these plugins is still limited due to their server-oriented dependencies [[source]](https://github.com/better-auth/better-auth/issues/4471). The `expoClient` plugin is safe for Expo, but the other plugins may still cause runtime errors. The latest release (after PR #4433) updates `jose` and related crypto dependencies to versions that avoid some Node.js built-ins, but you must use Node 20.19+ for development/builds [[source]](https://github.com/better-auth/better-auth/pull/4433). **What you can do:** - Double-check your installed Better Auth version (`pnpm list better-auth` or check `node_modules`) to ensure you’re on 1.3.8+. - If you’re still seeing errors, please share the exact error message or stack trace—this will help confirm if it’s a Node.js built-in issue. - If the error is about missing Node modules (like `node:buffer` or `node:crypto`), there’s no full workaround except to avoid these plugins in Expo, or move the logic to your backend. - For Expo Web, avoid using `client.getCookie()`—use `fetch` with `credentials: 'include'` instead [[source]](https://github.com/better-auth/better-auth/issues/4392). If you need phone/anonymous auth in Expo, the safest approach is to implement those flows on your backend and only use Expo-compatible plugins on the client. Let me know the error details if you want to dig deeper! <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/11549e15-708a-4d01-8990-fd552cc7a999?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/11549e15-708a-4d01-8990-fd552cc7a999?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/11549e15-708a-4d01-8990-fd552cc7a999?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/11549e15-708a-4d01-8990-fd552cc7a999?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/11549e15-708a-4d01-8990-fd552cc7a999?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/11549e15-708a-4d01-8990-fd552cc7a999?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/11549e15-708a-4d01-8990-fd552cc7a999?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/4496)
Author
Owner

@SamJbori commented on GitHub (Sep 7, 2025):

Legend: production dependency, optional only, dev only

@hwa/mobile@1.0.0 /home/wj/Projects/hwaTNext/apps/mobile (PRIVATE)

dependencies:
better-auth 1.3.8

I am running it inside a turbo repo and I absolutely need Phone Login

 WARN  Attempted to import the module "/home/wj/Projects/hwaTNext/node_modules/@noble/ciphers/crypto.js" which is not listed in the "exports" of "/home/wj/Projects/hwaTNext/node_modules/@noble/ciphers" under the requested subpath "./crypto.js". Falling back to file-based resolution. Consider updating the call site or asking the package maintainer(s) to expose this API.
 WARN  Attempted to import the module "/home/wj/Projects/hwaTNext/node_modules/@noble/hashes/crypto.js" which is not listed in the "exports" of "/home/wj/Projects/hwaTNext/node_modules/@noble/hashes" under the requested subpath "./crypto.js". Falling back to file-based resolution. Consider updating the call site or asking the package maintainer(s) to expose this API.
Android Bundling failed 19452ms node_modules/expo-router/entry.js (1361 modules)
The package at "node_modules/jose/dist/node/esm/runtime/base64url.js" attempted to import the Node standard library module "node:buffer".
It failed because the native React runtime does not include the Node standard library.

I've tried installing @noble/hashes with no luck

<!-- gh-comment-id:3263873115 --> @SamJbori commented on GitHub (Sep 7, 2025): ```bash Legend: production dependency, optional only, dev only @hwa/mobile@1.0.0 /home/wj/Projects/hwaTNext/apps/mobile (PRIVATE) dependencies: better-auth 1.3.8 ``` I am running it inside a turbo repo and I absolutely need Phone Login ```bash WARN Attempted to import the module "/home/wj/Projects/hwaTNext/node_modules/@noble/ciphers/crypto.js" which is not listed in the "exports" of "/home/wj/Projects/hwaTNext/node_modules/@noble/ciphers" under the requested subpath "./crypto.js". Falling back to file-based resolution. Consider updating the call site or asking the package maintainer(s) to expose this API. WARN Attempted to import the module "/home/wj/Projects/hwaTNext/node_modules/@noble/hashes/crypto.js" which is not listed in the "exports" of "/home/wj/Projects/hwaTNext/node_modules/@noble/hashes" under the requested subpath "./crypto.js". Falling back to file-based resolution. Consider updating the call site or asking the package maintainer(s) to expose this API. Android Bundling failed 19452ms node_modules/expo-router/entry.js (1361 modules) The package at "node_modules/jose/dist/node/esm/runtime/base64url.js" attempted to import the Node standard library module "node:buffer". It failed because the native React runtime does not include the Node standard library. ``` I've tried installing `@noble/hashes` with no luck
Author
Owner

@dosubot[bot] commented on GitHub (Sep 7, 2025):

The errors you're seeing are due to the fact that Expo/React Native doesn't support Node.js built-in modules like buffer and crypto, which are required by dependencies of phoneNumberClient (and sometimes anonymousClient). Even with Better Auth 1.3.8 and the latest updates to jose and @noble/*, these plugins still rely on server-oriented code that can't run in the Expo runtime [source].

Workarounds like overriding the jose version, installing react-native-webcrypto, and importing it at the top level may help with some crypto errors, but they won't fully resolve the issue if other Node.js APIs are needed [source]. The maintainers recommend not using these plugins in Expo/React Native and instead handling phone authentication on your backend, exposing only Expo-safe endpoints to your mobile app [source].

If you need phone login in Expo, the best approach is to implement the phone number verification and session logic on your backend (using Better Auth's server APIs), then call those endpoints from your Expo app using the expoClient plugin for session management. Alternatively, consider using a platform-native solution like Firebase Auth for phone login in Expo.

Let me know if you want a step-by-step guide for delegating phone auth to your backend or integrating with Expo-native flows.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

<!-- gh-comment-id:3263875725 --> @dosubot[bot] commented on GitHub (Sep 7, 2025): <!-- Answer --> The errors you're seeing are due to the fact that Expo/React Native doesn't support Node.js built-in modules like `buffer` and `crypto`, which are required by dependencies of `phoneNumberClient` (and sometimes `anonymousClient`). Even with Better Auth 1.3.8 and the latest updates to `jose` and `@noble/*`, these plugins still rely on server-oriented code that can't run in the Expo runtime [[source](https://github.com/better-auth/better-auth/issues/4471)]. Workarounds like overriding the `jose` version, installing `react-native-webcrypto`, and importing it at the top level may help with some crypto errors, but they won't fully resolve the issue if other Node.js APIs are needed [[source](https://github.com/better-auth/better-auth/issues/4422)]. The maintainers recommend not using these plugins in Expo/React Native and instead handling phone authentication on your backend, exposing only Expo-safe endpoints to your mobile app [[source](https://github.com/better-auth/better-auth/issues/4471)]. If you need phone login in Expo, the best approach is to implement the phone number verification and session logic on your backend (using Better Auth's server APIs), then call those endpoints from your Expo app using the `expoClient` plugin for session management. Alternatively, consider using a platform-native solution like Firebase Auth for phone login in Expo. Let me know if you want a step-by-step guide for delegating phone auth to your backend or integrating with Expo-native flows. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/50ca2079-de04-431f-bc57-09d33862dc09?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/50ca2079-de04-431f-bc57-09d33862dc09?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/50ca2079-de04-431f-bc57-09d33862dc09?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/50ca2079-de04-431f-bc57-09d33862dc09?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/50ca2079-de04-431f-bc57-09d33862dc09?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/50ca2079-de04-431f-bc57-09d33862dc09?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/50ca2079-de04-431f-bc57-09d33862dc09?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/4496)
Author
Owner

@Kinfe123 commented on GitHub (Sep 9, 2025):

Can you update to the latest beta and check if the issue persists or not ?

<!-- gh-comment-id:3270850230 --> @Kinfe123 commented on GitHub (Sep 9, 2025): Can you update to the latest beta and check if the issue persists or not ?
Author
Owner

@terijaki commented on GitHub (Sep 9, 2025):

I tried with 1.3.9 and 1.3.9-beta.4but the issue remains:

Attempted to import the module "{LocalPath}/node_modules/@noble/hashes/crypto.js" which is not listed in the "exports" of "{LocalPath}/node_modules/@noble/hashes" under the requested subpath "./crypto.js". Falling back to file-based resolution. Consider updating the call site or asking the package maintainer(s) to expose this API.

The package at "node_modules/jose/dist/node/cjs/runtime/base64url.js" attempted to import the Node standard library module "node:buffer".
It failed because the native React runtime does not include the Node standard library.
<!-- gh-comment-id:3271460007 --> @terijaki commented on GitHub (Sep 9, 2025): I tried with `1.3.9` and `1.3.9-beta.4`but the issue remains: ``` Attempted to import the module "{LocalPath}/node_modules/@noble/hashes/crypto.js" which is not listed in the "exports" of "{LocalPath}/node_modules/@noble/hashes" under the requested subpath "./crypto.js". Falling back to file-based resolution. Consider updating the call site or asking the package maintainer(s) to expose this API. The package at "node_modules/jose/dist/node/cjs/runtime/base64url.js" attempted to import the Node standard library module "node:buffer". It failed because the native React runtime does not include the Node standard library. ```
Author
Owner

@SamJbori commented on GitHub (Sep 10, 2025):

First and Most, Thank you team for this wonderful package

I consider Anonymous and Phone Login a high priority in modern B2C apps and a must, I rebased my entire NextJS code from AuthJS to Better Auth or few reasons, but this was by far the biggest one, I believe this is extremely important to fix, Mobile Apps are not going away anytime soon, this wonderful package needs to work on mobile flawlessly.

<!-- gh-comment-id:3273981807 --> @SamJbori commented on GitHub (Sep 10, 2025): First and Most, Thank you team for this wonderful package I consider Anonymous and Phone Login a high priority in modern B2C apps and a must, I rebased my entire `NextJS` code from `AuthJS` to `Better Auth` or few reasons, but this was by far the **biggest one**, I believe this is extremely important to fix, Mobile Apps are not going away anytime soon, this wonderful package needs to work on mobile **flawlessly**.
Author
Owner

@ArvidAnderson commented on GitHub (Sep 10, 2025):

import * as ExpoCrypto from "expo-crypto";

if (typeof global.crypto === "undefined") {
	// @ts-expect-error polyfill crypto
	global.crypto = {};
}

global.crypto.getRandomValues = ExpoCrypto.getRandomValues;
// @ts-expect-error polyfill crypto
global.crypto.randomUUID = ExpoCrypto.randomUUID;

if (typeof globalThis !== "undefined") {
	globalThis.crypto = global.crypto;
}

import "expo-router/entry";

I got the phoneNumber plugin working in Expo by polyfilling the crypto module in my custom entry point. I'll use this as a workaround for now.

<!-- gh-comment-id:3274066875 --> @ArvidAnderson commented on GitHub (Sep 10, 2025): ```ts import * as ExpoCrypto from "expo-crypto"; if (typeof global.crypto === "undefined") { // @ts-expect-error polyfill crypto global.crypto = {}; } global.crypto.getRandomValues = ExpoCrypto.getRandomValues; // @ts-expect-error polyfill crypto global.crypto.randomUUID = ExpoCrypto.randomUUID; if (typeof globalThis !== "undefined") { globalThis.crypto = global.crypto; } import "expo-router/entry"; ``` I got the phoneNumber plugin working in Expo by polyfilling the crypto module in my custom entry point. I'll use this as a workaround for now.
Author
Owner

@dosubot[bot] commented on GitHub (Dec 10, 2025):

Hi, @SamJbori. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary

  • You reported errors using anonymousClient or phoneNumberClient plugins in Expo/React Native due to missing Node.js built-ins like buffer and crypto.
  • This is a known compatibility issue with Better Auth versions up to 1.3.8.
  • The recommended approach is to handle phone authentication on the backend and use the expoClient plugin on the client.
  • Updating to 1.3.9-beta did not resolve the issue, as confirmed by another user.
  • A temporary workaround involves polyfilling the crypto module in Expo to enable phoneNumberClient functionality.

Next Steps

  • Please let me know if this issue is still relevant with the latest version of better-auth by commenting here.
  • If I do not hear back within 7 days, I will automatically close this issue.

Thank you for your understanding and contribution!

<!-- gh-comment-id:3637856999 --> @dosubot[bot] commented on GitHub (Dec 10, 2025): Hi, @SamJbori. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary** - You reported errors using anonymousClient or phoneNumberClient plugins in Expo/React Native due to missing Node.js built-ins like buffer and crypto. - This is a known compatibility issue with Better Auth versions up to 1.3.8. - The recommended approach is to handle phone authentication on the backend and use the expoClient plugin on the client. - Updating to 1.3.9-beta did not resolve the issue, as confirmed by another user. - A temporary workaround involves polyfilling the crypto module in Expo to enable phoneNumberClient functionality. **Next Steps** - Please let me know if this issue is still relevant with the latest version of better-auth by commenting here. - If I do not hear back within 7 days, I will automatically close this issue. Thank you for your understanding and contribution!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#9957