Apple authClient.signIn.social() never resolves in production/release builds (Expo/React Native) #2628

Closed
opened 2026-03-13 10:09:20 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @skempisty on GitHub (Dec 29, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Title

authClient.signIn.social() never resolves in production/release builds (Expo/React Native)

Description

I'm using better-auth with @better-auth/expo for Apple Sign In in a React Native/Expo app. The OAuth flow works perfectly in development but hangs in production/release builds (TestFlight).

Versions

  • better-auth: 1.3.7
  • @better-auth/expo: 1.3.7
  • Expo SDK: ~52.0.47

The Problem

When calling authClient.signIn.social({ provider: "apple", callbackURL: "/" }) in a production build:

  1. The function is called and makes a successful POST request to my server (I see 200 response in Vercel logs)
  2. The server returns the Apple OAuth URL correctly
  3. But the promise never resolves - no response is returned to the app, no error is thrown
  4. The Apple Sign In browser/modal never opens
  5. Alerts/logs placed after the await never execute

In development, the same code works perfectly - I receive the response with the OAuth URL and the flow completes.

Client setup

import { createAuthClient } from "better-auth/react";
import { expoClient } from "@better-auth/expo/client";
import * as SecureStore from "expo-secure-store";

const scheme = process.env.EXPO_PUBLIC_APP_VARIANT === 'development' ? 'seent-dev' : 'seent';
const baseURL = process.env.EXPO_PUBLIC_API_URL; // https://www.seen-t.com

export const authClient = createAuthClient({
  baseURL,
  plugins: [
    expoClient({
      scheme,
      storagePrefix: "seent-auth",
      storage: SecureStore,
    }),
  ],
});

Sign-in code

const response = await authClient.signIn.social({
  provider: "apple",
  callbackURL: "/",
});
// This alert never shows in production, but works in dev
Alert.alert("Response", JSON.stringify(response));

Server setup

export const auth = betterAuth({
  plugins: [expo()],
  socialProviders: {
    apple: {
      clientId: process.env.APPLE_CLIENT_ID, // Services ID
      clientSecret: process.env.APPLE_CLIENT_SECRET,
    },
  },
});

Key observations

  • Google Sign In using the same pattern (authClient.signIn.social({ provider: "google" })) works fine in production
  • The server receives the request and returns 200 in both dev and production
  • The difference is only in dev vs release build on the client side
  • No errors are thrown - the promise simply never resolves

Current vs. Expected behavior

Expected behavior

The promise should resolve with the OAuth URL (or open the browser automatically) in production builds, just like it does in development.

What version of Better Auth are you using?

1.3.7

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 23.6.0: Mon Jul 29 21:14:30 PDT 2024; root:xnu-10063.141.2~1/RELEASE_ARM64_T6000",
    "release": "23.6.0",
    "cpuCount": 8,
    "cpuModel": "Apple M1 Pro",
    "totalMemory": "16.00 GB",
    "freeMemory": "0.16 GB"
  },
  "node": {
    "version": "v22.21.1",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.4"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "16.0.10"
    },
    {
      "name": "react",
      "version": "^18"
    }
  ],
  "databases": [
    {
      "name": "@prisma/client",
      "version": "6.9.0"
    }
  ],
  "betterAuth": {
    "version": "^1.3.7",
    "config": null
  }
}

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

Client, Backend

Auth config (if applicable)

export const auth = betterAuth({
  plugins: [expo()],
  socialProviders: {
    apple: {
      clientId: process.env.APPLE_CLIENT_ID, // Services ID
      clientSecret: process.env.APPLE_CLIENT_SECRET,
    },
  },
});

Additional context

Apple login works with my current code on web and on local mobile app builds. However on test flight / production specifically it's not working.

Originally created by @skempisty on GitHub (Dec 29, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce ## Title `authClient.signIn.social()` never resolves in production/release builds (Expo/React Native) ## Description I'm using `better-auth` with `@better-auth/expo` for Apple Sign In in a React Native/Expo app. The OAuth flow works perfectly in development but hangs in production/release builds (TestFlight). ## Versions - `better-auth`: 1.3.7 - `@better-auth/expo`: 1.3.7 - Expo SDK: ~52.0.47 ## The Problem When calling `authClient.signIn.social({ provider: "apple", callbackURL: "/" })` in a production build: 1. The function is called and makes a successful POST request to my server (I see 200 response in Vercel logs) 2. The server returns the Apple OAuth URL correctly 3. **But the promise never resolves** - no response is returned to the app, no error is thrown 4. The Apple Sign In browser/modal never opens 5. Alerts/logs placed after the `await` never execute In development, the same code works perfectly - I receive the response with the OAuth URL and the flow completes. ## Client setup ```typescript import { createAuthClient } from "better-auth/react"; import { expoClient } from "@better-auth/expo/client"; import * as SecureStore from "expo-secure-store"; const scheme = process.env.EXPO_PUBLIC_APP_VARIANT === 'development' ? 'seent-dev' : 'seent'; const baseURL = process.env.EXPO_PUBLIC_API_URL; // https://www.seen-t.com export const authClient = createAuthClient({ baseURL, plugins: [ expoClient({ scheme, storagePrefix: "seent-auth", storage: SecureStore, }), ], }); ``` ## Sign-in code ```typescript const response = await authClient.signIn.social({ provider: "apple", callbackURL: "/", }); // This alert never shows in production, but works in dev Alert.alert("Response", JSON.stringify(response)); ``` ## Server setup ```typescript export const auth = betterAuth({ plugins: [expo()], socialProviders: { apple: { clientId: process.env.APPLE_CLIENT_ID, // Services ID clientSecret: process.env.APPLE_CLIENT_SECRET, }, }, }); ``` ## Key observations - Google Sign In using the same pattern (`authClient.signIn.social({ provider: "google" })`) works fine in production - The server receives the request and returns 200 in both dev and production - The difference is only in dev vs release build on the client side - No errors are thrown - the promise simply never resolves ### Current vs. Expected behavior ## Expected behavior The promise should resolve with the OAuth URL (or open the browser automatically) in production builds, just like it does in development. ### What version of Better Auth are you using? 1.3.7 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 23.6.0: Mon Jul 29 21:14:30 PDT 2024; root:xnu-10063.141.2~1/RELEASE_ARM64_T6000", "release": "23.6.0", "cpuCount": 8, "cpuModel": "Apple M1 Pro", "totalMemory": "16.00 GB", "freeMemory": "0.16 GB" }, "node": { "version": "v22.21.1", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.4" }, "frameworks": [ { "name": "next", "version": "16.0.10" }, { "name": "react", "version": "^18" } ], "databases": [ { "name": "@prisma/client", "version": "6.9.0" } ], "betterAuth": { "version": "^1.3.7", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Client, Backend ### Auth config (if applicable) ```typescript export const auth = betterAuth({ plugins: [expo()], socialProviders: { apple: { clientId: process.env.APPLE_CLIENT_ID, // Services ID clientSecret: process.env.APPLE_CLIENT_SECRET, }, }, }); ``` ### Additional context Apple login works with my current code on web and on local mobile app builds. However on test flight / production specifically it's not working.
GiteaMirror added the expobug labels 2026-03-13 10:09:20 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Dec 29, 2025):

It sounds like you're experiencing a frustrating issue with authClient.signIn.social() not resolving in production builds of your Expo/React Native app when trying to implement Apple Sign-In. This has been a relevant topic within the community. Here are some steps for troubleshooting:

  1. Ensure correct clientId and clientSecret: For native iOS apps, ensure you're using the app/bundle ID for clientId instead of the service ID. The service ID is used for web applications, while the app ID is required for native apps [2].

  2. Check OAuth flow: You might want to verify if certain settings for the OAuth flow in your production build are set correctly, especially since you mentioned it works fine in development. Check if the callback URL is properly configured and allowed in your Apple Developer account settings.

  3. Enable debugging in production: If possible, enable logging for network requests in your production build to see if there are any underlying requests that are being blocked or not handled as expected.

  4. Use idToken: If you aren't already, consider using the idToken after acquiring it from the Apple authentication response. You can retry the social sign-in using the idToken as part of the request to ensure proper identification.

  5. Clear cache: Don't forget to clear your build cache when making changes. An Expo command you can run is npx expo start --clear to ensure that the development server is serving the latest files.

If you've checked all these options and still face issues, it might be helpful to tag @bekacru or @ping__ from the Better Auth team in your message so they can provide specific assistance.

What additional steps have you taken so far to troubleshoot this issue?

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

@better-auth-agent[bot] commented on GitHub (Dec 29, 2025): It sounds like you're experiencing a frustrating issue with `authClient.signIn.social()` not resolving in production builds of your Expo/React Native app when trying to implement Apple Sign-In. This has been a relevant topic within the community. Here are some steps for troubleshooting: 1. **Ensure correct `clientId` and `clientSecret`:** For native iOS apps, ensure you're using the app/bundle ID for `clientId` instead of the service ID. The service ID is used for web applications, while the app ID is required for native apps [[2]](https://github.com/better-auth/better-auth/pull/966). 2. **Check OAuth flow:** You might want to verify if certain settings for the OAuth flow in your production build are set correctly, especially since you mentioned it works fine in development. Check if the callback URL is properly configured and allowed in your Apple Developer account settings. 3. **Enable debugging in production:** If possible, enable logging for network requests in your production build to see if there are any underlying requests that are being blocked or not handled as expected. 4. **Use `idToken`:** If you aren't already, consider using the `idToken` after acquiring it from the Apple authentication response. You can retry the social sign-in using the `idToken` as part of the request to ensure proper identification. 5. **Clear cache:** Don't forget to clear your build cache when making changes. An Expo command you can run is `npx expo start --clear` to ensure that the development server is serving the latest files. If you've checked all these options and still face issues, it might be helpful to tag @bekacru or @ping__ from the Better Auth team in your message so they can provide specific assistance. What additional steps have you taken so far to troubleshoot this issue? _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

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

This is a known issue with Expo/React Native production builds and Better Auth's mobile OAuth flow. The most common causes are:

  • The deep linking scheme (e.g., seent) is not set up correctly in your app.json/app.config.js and Info.plist for production. The scheme must match exactly between your Expo config, your Better Auth client, and your Apple developer console. If the scheme is missing or mismatched, the browser/modal will not open and the promise will hang ref.
  • The /api/auth/expo-authorization-proxy endpoint is missing from your backend. This endpoint is required for mobile OAuth to work; if it's missing, the promise will never resolve and the modal won't open ref.
  • trustedOrigins and cookie settings are not configured for production. Make sure your backend includes your app scheme (e.g., seent://), exp://, and https://appleid.apple.com in trustedOrigins, and that your state cookie uses sameSite: 'none' and secure: true ref.
  • The callbackURL should be a full deep link (e.g., seent://) or use / so that the Expo client can convert it. If you use a relative path, make sure the Expo client is correctly converting it to a deep link ref.
  • Apple Sign In requires proper entitlements and Info.plist configuration for production/TestFlight. Double-check that your production build includes the correct Sign In with Apple capability and all required Info.plist keys.

Troubleshooting steps:

  1. Confirm your scheme is set in app.json and matches your Better Auth client and Apple config.
  2. Make sure your backend includes the Expo plugin and exposes /api/auth/expo-authorization-proxy.
  3. Update your Better Auth backend config to include all trusted origins and set the state cookie attributes.
  4. If you still see the hang, add logs before and after the await authClient.signIn.social call and inside your deep link handler to see where the flow stops.
  5. For Apple, ensure your client secret is valid and not expired; consider using a dynamic client secret generator if your app stays up for long periods ref.

If Google works but Apple doesn't, it's almost always a config or entitlement issue specific to Apple, not a Better Auth bug. If you need a checklist or want to share your app.json and Info.plist, I can help spot any issues.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Dec 29, 2025): <!-- Answer --> This is a known issue with Expo/React Native production builds and Better Auth's mobile OAuth flow. The most common causes are: - The deep linking scheme (e.g., `seent`) is not set up correctly in your `app.json`/`app.config.js` and Info.plist for production. The scheme must match exactly between your Expo config, your Better Auth client, and your Apple developer console. If the scheme is missing or mismatched, the browser/modal will not open and the promise will hang [ref](https://github.com/better-auth/better-auth/issues/7025). - The `/api/auth/expo-authorization-proxy` endpoint is missing from your backend. This endpoint is required for mobile OAuth to work; if it's missing, the promise will never resolve and the modal won't open [ref](https://github.com/better-auth/better-auth/issues/6207). - `trustedOrigins` and cookie settings are not configured for production. Make sure your backend includes your app scheme (e.g., `seent://`), `exp://`, and `https://appleid.apple.com` in `trustedOrigins`, and that your state cookie uses `sameSite: 'none'` and `secure: true` [ref](https://github.com/better-auth/better-auth/issues/6483). - The callbackURL should be a full deep link (e.g., `seent://`) or use `/` so that the Expo client can convert it. If you use a relative path, make sure the Expo client is correctly converting it to a deep link [ref](https://github.com/better-auth/better-auth/blob/4d7d7d5a76b5e0e90d42238f00751584ec07afa7/packages/expo/src/client.ts#L258-L445). - Apple Sign In requires proper entitlements and Info.plist configuration for production/TestFlight. Double-check that your production build includes the correct `Sign In with Apple` capability and all required Info.plist keys. Troubleshooting steps: 1. Confirm your scheme is set in `app.json` and matches your Better Auth client and Apple config. 2. Make sure your backend includes the Expo plugin and exposes `/api/auth/expo-authorization-proxy`. 3. Update your Better Auth backend config to include all trusted origins and set the state cookie attributes. 4. If you still see the hang, add logs before and after the `await authClient.signIn.social` call and inside your deep link handler to see where the flow stops. 5. For Apple, ensure your client secret is valid and not expired; consider using a dynamic client secret generator if your app stays up for long periods [ref](https://github.com/better-auth/better-auth/issues/1522). If Google works but Apple doesn't, it's almost always a config or entitlement issue specific to Apple, not a Better Auth bug. If you need a checklist or want to share your `app.json` and Info.plist, I can help spot any issues. <!-- 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/22fdf5c3-2a8b-495a-8124-a52d6cab11ef?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/22fdf5c3-2a8b-495a-8124-a52d6cab11ef?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/22fdf5c3-2a8b-495a-8124-a52d6cab11ef?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/22fdf5c3-2a8b-495a-8124-a52d6cab11ef?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/22fdf5c3-2a8b-495a-8124-a52d6cab11ef?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/22fdf5c3-2a8b-495a-8124-a52d6cab11ef?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/22fdf5c3-2a8b-495a-8124-a52d6cab11ef?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20is%20a%20known%20issue%20with%20Expo/React%20Native%20production%20builds%20and%20Better%20Auth%27s%20mobile%20OAuth%20flow.%20The%20most%20common%20causes%20are%3A%20%0A%0A-%20The%20deep%20linking%20scheme%20%28e.g.%2C%20%60seent%60%29%20is%20not%20set%20up%20correctly%20in%20your%20%60app.json%60/%60app.config.js%60%20and%20Info.plist%20for%20production.%20The%20scheme%20must%20match%20exactly%20between%20your%20Expo%20config%2C%20your%20Better%20Auth%20client%2C%20and%20your%20Apple%20developer%20console.%20If%20the%20scheme%20is%20missing%20or%20mismatched%2C%20the%20browser/modal%20will%20not%20open%20and%20the%20promise%20will%20hang%C2%A0%5Bref%5D%28https%3A//github.com/better-auth/better-auth/issues/7025%29.%0A-%20The%20%60/api/auth/expo-authorization-proxy%60%20endpoint%20is%20missing%20from%20your%20backend.%20This%20endpoint%20is%20required%20for%20mobile%20OAuth%20to%20work%3B%20if%20it%27s%20missing%2C%20the%20promise%20will%20never%20resolve%20and%20the%20modal%20won%27t%20open%C2%A0%5Bref%5D%28https%3A//github.com/better-auth/better-auth/issues/6207%29.%0A-%20%60trustedOrigins%60%20and%20cookie%20settings%20are%20not%20configured%20for%20production.%20Make%20sure%20your%20backend%20includes%20your%20app%20scheme%20%28e.g.%2C%20%60seent%3A//%60%29%2C%20%60exp%3A//%60%2C%20and%20%60https%3A//appleid.apple.com%60%20in%20%60trustedOrigins%60%2C%20and%20that%20your%20state%20cookie%20uses%20%60sameSite%3A%20%27none%27%60%20and%20%60secure%3A%20true%60%C2%A0%5Bref%5D%28https%3A//github.com/better-auth/better-auth/issues/6483%29.%0A-%20The%20callbackURL%20should%20be%20a%20full%20deep%20link%20%28e.g.%2C%20%60seent%3A//%60%29%20or%20use%20%60/%60%20so%20that%20the%20Expo%20client%20can%20convert%20it.%20If%20you%20use%20a%20relative%20path%2C%20make%20sure%20the%20Expo%20client%20is%20correctly%20converting%20it%20to%20a%20deep%20link%C2%A0%5Bref%5D%28https%3A//github.com/better-auth/better-auth/blob/4d7d7d5a76b5e0e90d42238f00751584ec07afa7/packages/expo/src/client.ts%23L258-L445%29.%0A-%20Apple%20Sign%20In%20requires%20proper%20entitlements%20and%20Info.plist%20configuration%20for%20production/TestFlight.%20Double-check%20that%20your%20production%20build%20includes%20the%20correct%20%60Sign%20In%20with%20Apple%60%20capability%20and%20all%20required%20Info.plist%20keys.%0A%0ATroubleshooting%20steps%3A%0A1.%20Confirm%20your%20scheme%20is%20set%20in%20%60app.json%60%20and%20matches%20your%20Better%20Auth%20client%20and%20Apple%20config.%0A2.%20Make%20sure%20your%20backend%20includes%20the%20Expo%20plugin%20and%20exposes%20%60/api/auth/expo-authorization-proxy%60.%0A3.%20Update%20your%20Better%20Auth%20backend%20config%20to%20include%20all%20trusted%20origins%20and%20set%20the%20state%20cookie%20attributes.%0A4.%20If%20you%20still%20see%20the%20hang%2C%20add%20logs%20before%20and%20after%20the%20%60await%20authClient.signIn.social%60%20call%20and%20inside%20your%20deep%20link%20handler%20to%20see%20where%20the%20flow%20stops.%0A5.%20For%20Apple%2C%20ensure%20your%20client%20secret%20is%20valid%20and%20not%20expired%3B%20consider%20using%20a%20dynamic%20client%20secret%20generator%20if%20your%20app%20stays%20up%20for%20long%20periods%C2%A0%5Bref%5D%28https%3A//github.com/better-auth/better-auth/issues/1522%29.%0A%0AIf%20Google%20works%20but%20Apple%20doesn%27t%2C%20it%27s%20almost%20always%20a%20config%20or%20entitlement%20issue%20specific%20to%20Apple%2C%20not%20a%20Better%20Auth%20bug.%20If%20you%20need%20a%20checklist%20or%20want%20to%20share%20your%20%60app.json%60%20and%20Info.plist%2C%20I%20can%20help%20spot%20any%20issues.)&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/7049)
Author
Owner

@skempisty commented on GitHub (Dec 29, 2025):

Thanks @dosu. I checked the expo-authorization-proxy endpoint and I think this is the issue.

When I curl the endpoint, it returns 404:

curl -X POST "https://www.seen-t.com/api/auth/expo-authorization-proxy" -H "Content-Type: application/json" -d '{}'
# Returns 404

curl "https://www.seen-t.com/api/auth/expo-authorization-proxy"
# Also returns 404

However, other auth endpoints work fine:

curl -X POST "https://www.seen-t.com/api/auth/sign-in/social" -H "Content-Type: application/json" -d '{"provider":"apple"}'
# Returns: {"url":"https://appleid.apple.com/auth/authorize?...","redirect":true}

My server setup in libs/auth.ts:

import { expo } from "@better-auth/expo";

export const auth = betterAuth({
  plugins: [
    expo(),
    // other plugins...
  ],
  // ...
});

And my Next.js API route (pages/api/auth/[...all].ts):

import { toNodeHandler } from "better-auth/node"
import { auth } from "@/libs/auth"

export const config = { api: { bodyParser: false } }

export default toNodeHandler(auth.handler)

It seems like the expo() plugin is not registering the expo-authorization-proxy endpoint, even though the plugin is included. Other endpoints like sign-in/social work correctly.

Note: I cannot upgrade past better-auth 1.3.7 right now. Everything else works at this version, and upgrading would require upgrading many other packages which isn't feasible at this time.

Questions:

  1. Why would expo-authorization-proxy return 404 while other endpoints work?
  2. Is there additional configuration needed for the expo() plugin in version 1.3.7?
  3. How can I verify the expo plugin routes are being registered?

@dosu

@skempisty commented on GitHub (Dec 29, 2025): Thanks @dosu. I checked the `expo-authorization-proxy` endpoint and I think this is the issue. When I curl the endpoint, it returns 404: ```bash curl -X POST "https://www.seen-t.com/api/auth/expo-authorization-proxy" -H "Content-Type: application/json" -d '{}' # Returns 404 curl "https://www.seen-t.com/api/auth/expo-authorization-proxy" # Also returns 404 ``` However, other auth endpoints work fine: ```bash curl -X POST "https://www.seen-t.com/api/auth/sign-in/social" -H "Content-Type: application/json" -d '{"provider":"apple"}' # Returns: {"url":"https://appleid.apple.com/auth/authorize?...","redirect":true} ``` My server setup in `libs/auth.ts`: ```typescript import { expo } from "@better-auth/expo"; export const auth = betterAuth({ plugins: [ expo(), // other plugins... ], // ... }); ``` And my Next.js API route (`pages/api/auth/[...all].ts`): ```typescript import { toNodeHandler } from "better-auth/node" import { auth } from "@/libs/auth" export const config = { api: { bodyParser: false } } export default toNodeHandler(auth.handler) ``` It seems like the `expo()` plugin is not registering the `expo-authorization-proxy` endpoint, even though the plugin is included. Other endpoints like `sign-in/social` work correctly. Note: I cannot upgrade past `better-auth` 1.3.7 right now. Everything else works at this version, and upgrading would require upgrading many other packages which isn't feasible at this time. Questions: 1. Why would `expo-authorization-proxy` return 404 while other endpoints work? 2. Is there additional configuration needed for the `expo()` plugin in version 1.3.7? 3. How can I verify the expo plugin routes are being registered? @dosu
Author
Owner

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

The /expo-authorization-proxy endpoint is registered automatically as a GET route by the expo() plugin in better-auth 1.3.7—no extra config is needed. If you hit it with POST (as in your first curl), it will always return 404; it only responds to GET requests with an authorizationURL query param plugin code.

If you get 404 on GET as well, common causes are: the plugin isn't actually included, the endpoint is disabled via disabledPaths, or custom middleware/proxying is interfering before the auth handler route registration logic. There are no hidden environment gates or plugin order requirements.

To check what plugin endpoints are registered, you can log:

console.log(auth.handler.options.plugins?.map(p => Object.keys(p.endpoints || {})))

in your API route. If /expo-authorization-proxy isn't present, something is blocking the plugin from being loaded or its endpoints from being merged.

Also, make sure you don't have custom middleware, rewrites, or proxies in your Next.js API route chain that could block or reroute /api/auth/expo-authorization-proxy discussion.

Finally, test the endpoint with a GET request like:

curl "https://www.seen-t.com/api/auth/expo-authorization-proxy?authorizationURL=https://example.com"

If you still get 404, try isolating your auth handler in a minimal setup to rule out external interference.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Dec 29, 2025): <!-- Answer --> The /expo-authorization-proxy endpoint is registered automatically as a GET route by the expo() plugin in better-auth 1.3.7—no extra config is needed. If you hit it with POST (as in your first curl), it will always return 404; it only responds to GET requests with an authorizationURL query param [plugin code](https://github.com/better-auth/better-auth/blob/4d7d7d5a76b5e0e90d42238f00751584ec07afa7/packages/expo/src/routes.ts#L5-L34). If you get 404 on GET as well, common causes are: the plugin isn't actually included, the endpoint is disabled via disabledPaths, or custom middleware/proxying is interfering before the auth handler [route registration logic](https://github.com/better-auth/better-auth/blob/4d7d7d5a76b5e0e90d42238f00751584ec07afa7/packages/better-auth/src/api/index.ts#L56-L303). There are no hidden environment gates or plugin order requirements. To check what plugin endpoints are registered, you can log: ```js console.log(auth.handler.options.plugins?.map(p => Object.keys(p.endpoints || {}))) ``` in your API route. If /expo-authorization-proxy isn't present, something is blocking the plugin from being loaded or its endpoints from being merged. Also, make sure you don't have custom middleware, rewrites, or proxies in your Next.js API route chain that could block or reroute /api/auth/expo-authorization-proxy [discussion](https://github.com/better-auth/better-auth/issues/3362). Finally, test the endpoint with a GET request like: ```bash curl "https://www.seen-t.com/api/auth/expo-authorization-proxy?authorizationURL=https://example.com" ``` If you still get 404, try isolating your auth handler in a minimal setup to rule out external interference. <!-- 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/c9825fa9-b240-43ff-a886-b77768ee1e98?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/c9825fa9-b240-43ff-a886-b77768ee1e98?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/c9825fa9-b240-43ff-a886-b77768ee1e98?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/c9825fa9-b240-43ff-a886-b77768ee1e98?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/c9825fa9-b240-43ff-a886-b77768ee1e98?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/c9825fa9-b240-43ff-a886-b77768ee1e98?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/c9825fa9-b240-43ff-a886-b77768ee1e98?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=The%20/expo-authorization-proxy%20endpoint%20is%20registered%20automatically%20as%20a%20GET%20route%20by%20the%20expo%28%29%20plugin%20in%20better-auth%201.3.7%E2%80%94no%20extra%20config%20is%20needed.%20If%20you%20hit%20it%20with%20POST%20%28as%20in%20your%20first%20curl%29%2C%20it%20will%20always%20return%20404%3B%20it%20only%20responds%20to%20GET%20requests%20with%20an%20authorizationURL%20query%20param%C2%A0%5Bplugin%20code%5D%28https%3A//github.com/better-auth/better-auth/blob/4d7d7d5a76b5e0e90d42238f00751584ec07afa7/packages/expo/src/routes.ts%23L5-L34%29.%0A%0AIf%20you%20get%20404%20on%20GET%20as%20well%2C%20common%20causes%20are%3A%20the%20plugin%20isn%27t%20actually%20included%2C%20the%20endpoint%20is%20disabled%20via%20disabledPaths%2C%20or%20custom%20middleware/proxying%20is%20interfering%20before%20the%20auth%20handler%C2%A0%5Broute%20registration%20logic%5D%28https%3A//github.com/better-auth/better-auth/blob/4d7d7d5a76b5e0e90d42238f00751584ec07afa7/packages/better-auth/src/api/index.ts%23L56-L303%29.%20There%20are%20no%20hidden%20environment%20gates%20or%20plugin%20order%20requirements.%0A%0ATo%20check%20what%20plugin%20endpoints%20are%20registered%2C%20you%20can%20log%3A%0A%60%60%60js%0Aconsole.log%28auth.handler.options.plugins%3F.map%28p%20%3D%3E%20Object.keys%28p.endpoints%20%7C%7C%20%7B%7D%29%29%29%0A%60%60%60%0Ain%20your%20API%20route.%20If%20/expo-authorization-proxy%20isn%27t%20present%2C%20something%20is%20blocking%20the%20plugin%20from%20being%20loaded%20or%20its%20endpoints%20from%20being%20merged.%0A%0AAlso%2C%20make%20sure%20you%20don%27t%20have%20custom%20middleware%2C%20rewrites%2C%20or%20proxies%20in%20your%20Next.js%20API%20route%20chain%20that%20could%20block%20or%20reroute%20/api/auth/expo-authorization-proxy%C2%A0%5Bdiscussion%5D%28https%3A//github.com/better-auth/better-auth/issues/3362%29.%0A%0AFinally%2C%20test%20the%20endpoint%20with%20a%20GET%20request%20like%3A%0A%60%60%60bash%0Acurl%20%22https%3A//www.seen-t.com/api/auth/expo-authorization-proxy%3FauthorizationURL%3Dhttps%3A//example.com%22%0A%60%60%60%0AIf%20you%20still%20get%20404%2C%20try%20isolating%20your%20auth%20handler%20in%20a%20minimal%20setup%20to%20rule%20out%20external%20interference.)&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/7049)
Author
Owner

@skempisty commented on GitHub (Dec 30, 2025):

Thank you @himself65 . I was able to get Apple signin working by using native IOS apple signin, but it would be nice to be able to use the web/callback signin as well so I can support it on Android as well.

I will work on upgrading my better-auth package so I can make use of your fix!

@skempisty commented on GitHub (Dec 30, 2025): Thank you @himself65 . I was able to get Apple signin working by using native IOS apple signin, but it would be nice to be able to use the web/callback signin as well so I can support it on Android as well. I will work on upgrading my better-auth package so I can make use of your fix!
Author
Owner

@Alvi24 commented on GitHub (Jan 21, 2026):

Thank you @himself65 . I was able to get Apple signin working by using native IOS apple signin, but it would be nice to be able to use the web/callback signin as well so I can support it on Android as well.

I will work on upgrading my better-auth package so I can make use of your fix!

hey @skempisty how did you implement native iOS apple signin?
did you use expo-apple-authentication?

@Alvi24 commented on GitHub (Jan 21, 2026): > Thank you [@himself65](https://github.com/himself65) . I was able to get Apple signin working by using native IOS apple signin, but it would be nice to be able to use the web/callback signin as well so I can support it on Android as well. > > I will work on upgrading my better-auth package so I can make use of your fix! hey @skempisty how did you implement native iOS apple signin? did you use expo-apple-authentication?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2628