[GH-ISSUE #6936] Expo + better-auth + magic link does not seem to work as expected #10676

Closed
opened 2026-04-13 06:57:11 -05:00 by GiteaMirror · 9 comments
Owner

Originally created by @mfrachet on GitHub (Dec 22, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6936

Originally assigned to: @bytaesu on GitHub.

Is this suited for github?

  • Yes, this is suited for github

Magic Link session not persisting on Expo client (Hono backend)

First off, thanks for building and maintaining this project — really appreciate the work you all put in 🙏

Description

I'm struggling to get magic link authentication working between my Hono backend and Expo app. The flow completes successfully (email sent, token validated, redirect fires), but the session never gets set on the client.

Current behavior

  1. User enters email, authClient.signIn.magicLink is called from the Expo app
  2. User receives the magic link email with a valid token
  3. User clicks the link, it hits my backend at /api/v1/auth/magic-link/verify
  4. Backend returns a 302 redirect to cocottesrooms:///dashboard with a set-cookie header containing the session token
  5. Deep link fires correctly in the app
  6. Session is never set — both useSession hook and direct authClient.getSession() calls return nothing

Google OAuth works perfectly with the same setup, so this seems specific to magic links.

Expected behavior

After the redirect, the session should be available on the client via authClient.getSession() or the session hook.

Reproduction

Backend (auth.ts)

export const auth = (
  db: DrizzleDatabase,
  emailService: EmailService,
  mode: "development" | "production",
  googleClientId: string,
  googleClientSecret: string,
  baseURL: string,
  secret: string
) => {
  const trustedOrigins = ["cocottesrooms://"];
  if (mode === "development") {
    trustedOrigins.push("exp://");
  }

  return betterAuth({
    appName: "cocottes-rooms",
    basePath: "/api/v1/auth",
    baseURL,
    secret,
    database: drizzleAdapter(db, {
      provider: "pg",
      schema: authSchema,
    }),
    trustedOrigins,
    socialProviders: {
      google: {
        clientId: googleClientId,
        clientSecret: googleClientSecret,
      },
    },
    plugins: [
      expo({ disableOriginOverride: true }),
      magicLink({
        sendMagicLink: async ({ email, token, url }, ctx) => {
          await emailService.sendEmail(
            email,
            "Magic Link",
            `<a href="${url}">${url}</a>`
          );
        },
      }),
    ],
    advanced: {
      disableOriginCheck: true,
    },
  });
};

Backend route handler

app.on(["POST", "GET"], `${apiRoot}/auth/*`, async (c) => {
  const services = c.get("services");
  // services.auth is basically the returned value of the above function
  const response = await services.auth.handler(c.req.raw);
  return response;
});

Backend response (logged)

{
  "status": 302,
  "statusText": "FOUND",
  "headers": {
    "content-type": "application/json",
    "location": "cocottesrooms://dashboard",
    "set-cookie": "better-auth.session_token=E7jHcudkRUtkf93oMoBCEP2KNSwxmPTZ...; Max-Age=604800; Path=/; HttpOnly; SameSite=Lax"
  }
}

Frontend auth client (auth-client.ts)

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

export const authClient = createAuthClient({
  baseURL: `${process.env.EXPO_PUBLIC_API_URL}/api/v1/auth`,
  plugins: [
    expoClient({
      scheme: "cocottesrooms",
      storage: SecureStore,
    }),
    magicLinkClient(),
  ],
});

Frontend sign-in helper

export const magicLinkSignIn = async (email: string) => {
  const { data, error } = await authClient.signIn.magicLink({
    email,
    callbackURL: "/dashboard",
    newUserCallbackURL: "/dashboard",
    errorCallbackURL: "/error",
  });

  if (error) {
    throw error;
  }

  return data;
};

Environment

  • better-auth version: 1.4.7 (both expo and backend)
  • @better-auth/expo version: 1.4.7
  • Expo SDK: 54.0.29
  • Backend: 4.10.8"

Additional context

Google OAuth sign-in works correctly with the exact same configuration, which makes me think this might be specific to how magic link handles the session handoff to native apps.

Any guidance would be hugely appreciated — happy to provide more details or test things out!

Current vs. Expected behavior

I expected to be logged in and resolve a user session after the backend opens the deeplink but the current session (or a session imperatively fetch from a deeplink listener) resolves to null.

What version of Better Auth are you using?

1.4.7

System info

Backend: 

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:40 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T8132",
    "release": "24.6.0",
    "cpuCount": 10,
    "cpuModel": "Apple M4",
    "totalMemory": "16.00 GB",
    "freeMemory": "0.22 GB"
  },
  "node": {
    "version": "v22.14.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.2"
  },
  "frameworks": [
    {
      "name": "hono",
      "version": "^4.10.8"
    }
  ],
  "databases": [
    {
      "name": "drizzle",
      "version": "^0.45.0"
    },
    {
      "name": "@neondatabase/serverless",
      "version": "^1.0.2"
    }
  ],
  "betterAuth": {
    "version": "^1.4.7",
    "config": null
  }
}

Frontend:

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:40 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T8132",
    "release": "24.6.0",
    "cpuCount": 10,
    "cpuModel": "Apple M4",
    "totalMemory": "16.00 GB",
    "freeMemory": "0.16 GB"
  },
  "node": {
    "version": "v22.14.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.2"
  },
  "frameworks": [
    {
      "name": "react",
      "version": "19.1.0"
    }
  ],
  "databases": null,
  "betterAuth": {
    "version": "^1.4.7",
    "config": null
  }
}

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

Client

Auth config (if applicable)

export const auth = (
  db: DrizzleDatabase,
  emailService: EmailService,
  mode: "development" | "production",
  googleClientId: string,
  googleClientSecret: string,
  baseURL: string,
  secret: string
) => {
  const trustedOrigins = ["cocottesrooms://"];

  if (mode === "development") {
    trustedOrigins.push("exp://");
  }

  return betterAuth({
    appName: "cocottes-rooms",
    basePath: "/api/v1/auth",
    baseURL,
    secret,
    database: drizzleAdapter(db, {
      provider: "pg",
      schema: authSchema,
    }),
    trustedOrigins: trustedOrigins,
    socialProviders: {
      google: {
        clientId: googleClientId,
        clientSecret: googleClientSecret,
      },
    },
    plugins: [
      expo({ disableOriginOverride: true }),
      magicLink({
        sendMagicLink: async ({ email, token, url }, ctx) => {
          await emailService.sendEmail(
            email,
            "Magic Link",
            `<a href="${url}">${url}</a>`
          );
        },
      }),
    ],
    advanced: {
      disableOriginCheck: true,
    },
  });
};

Additional context

No response

Originally created by @mfrachet on GitHub (Dec 22, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6936 Originally assigned to: @bytaesu on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github # Magic Link session not persisting on Expo client (Hono backend) First off, thanks for building and maintaining this project — really appreciate the work you all put in 🙏 ## Description I'm struggling to get magic link authentication working between my Hono backend and Expo app. The flow completes successfully (email sent, token validated, redirect fires), but the session never gets set on the client. ## Current behavior 1. User enters email, `authClient.signIn.magicLink` is called from the Expo app 2. User receives the magic link email with a valid token 3. User clicks the link, it hits my backend at `/api/v1/auth/magic-link/verify` 4. Backend returns a `302` redirect to `cocottesrooms:///dashboard` with a `set-cookie` header containing the session token 5. Deep link fires correctly in the app 6. **Session is never set** — both `useSession` hook and direct `authClient.getSession()` calls return nothing Google OAuth works perfectly with the same setup, so this seems specific to magic links. ## Expected behavior After the redirect, the session should be available on the client via `authClient.getSession()` or the session hook. ## Reproduction ### Backend (`auth.ts`) ```ts export const auth = ( db: DrizzleDatabase, emailService: EmailService, mode: "development" | "production", googleClientId: string, googleClientSecret: string, baseURL: string, secret: string ) => { const trustedOrigins = ["cocottesrooms://"]; if (mode === "development") { trustedOrigins.push("exp://"); } return betterAuth({ appName: "cocottes-rooms", basePath: "/api/v1/auth", baseURL, secret, database: drizzleAdapter(db, { provider: "pg", schema: authSchema, }), trustedOrigins, socialProviders: { google: { clientId: googleClientId, clientSecret: googleClientSecret, }, }, plugins: [ expo({ disableOriginOverride: true }), magicLink({ sendMagicLink: async ({ email, token, url }, ctx) => { await emailService.sendEmail( email, "Magic Link", `<a href="${url}">${url}</a>` ); }, }), ], advanced: { disableOriginCheck: true, }, }); }; ``` ### Backend route handler ```ts app.on(["POST", "GET"], `${apiRoot}/auth/*`, async (c) => { const services = c.get("services"); // services.auth is basically the returned value of the above function const response = await services.auth.handler(c.req.raw); return response; }); ``` ### Backend response (logged) ```json { "status": 302, "statusText": "FOUND", "headers": { "content-type": "application/json", "location": "cocottesrooms://dashboard", "set-cookie": "better-auth.session_token=E7jHcudkRUtkf93oMoBCEP2KNSwxmPTZ...; Max-Age=604800; Path=/; HttpOnly; SameSite=Lax" } } ``` ### Frontend auth client (`auth-client.ts`) ```ts import { createAuthClient } from "better-auth/react"; import { expoClient } from "@better-auth/expo/client"; import { magicLinkClient } from "better-auth/client/plugins"; import * as SecureStore from "expo-secure-store"; export const authClient = createAuthClient({ baseURL: `${process.env.EXPO_PUBLIC_API_URL}/api/v1/auth`, plugins: [ expoClient({ scheme: "cocottesrooms", storage: SecureStore, }), magicLinkClient(), ], }); ``` ### Frontend sign-in helper ```ts export const magicLinkSignIn = async (email: string) => { const { data, error } = await authClient.signIn.magicLink({ email, callbackURL: "/dashboard", newUserCallbackURL: "/dashboard", errorCallbackURL: "/error", }); if (error) { throw error; } return data; }; ``` ## Environment - **better-auth version**: 1.4.7 (both expo and backend) - **@better-auth/expo version**: 1.4.7 - **Expo SDK**: 54.0.29 - **Backend**: 4.10.8" ## Additional context Google OAuth sign-in works correctly with the exact same configuration, which makes me think this might be specific to how magic link handles the session handoff to native apps. Any guidance would be hugely appreciated — happy to provide more details or test things out! ### Current vs. Expected behavior I expected to be logged in and resolve a user session after the backend opens the deeplink but the current session (or a session imperatively fetch from a deeplink listener) resolves to null. ### What version of Better Auth are you using? 1.4.7 ### System info ```bash Backend: { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:40 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T8132", "release": "24.6.0", "cpuCount": 10, "cpuModel": "Apple M4", "totalMemory": "16.00 GB", "freeMemory": "0.22 GB" }, "node": { "version": "v22.14.0", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.2" }, "frameworks": [ { "name": "hono", "version": "^4.10.8" } ], "databases": [ { "name": "drizzle", "version": "^0.45.0" }, { "name": "@neondatabase/serverless", "version": "^1.0.2" } ], "betterAuth": { "version": "^1.4.7", "config": null } } Frontend: { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:40 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T8132", "release": "24.6.0", "cpuCount": 10, "cpuModel": "Apple M4", "totalMemory": "16.00 GB", "freeMemory": "0.16 GB" }, "node": { "version": "v22.14.0", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.2" }, "frameworks": [ { "name": "react", "version": "19.1.0" } ], "databases": null, "betterAuth": { "version": "^1.4.7", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Client ### Auth config (if applicable) ```typescript export const auth = ( db: DrizzleDatabase, emailService: EmailService, mode: "development" | "production", googleClientId: string, googleClientSecret: string, baseURL: string, secret: string ) => { const trustedOrigins = ["cocottesrooms://"]; if (mode === "development") { trustedOrigins.push("exp://"); } return betterAuth({ appName: "cocottes-rooms", basePath: "/api/v1/auth", baseURL, secret, database: drizzleAdapter(db, { provider: "pg", schema: authSchema, }), trustedOrigins: trustedOrigins, socialProviders: { google: { clientId: googleClientId, clientSecret: googleClientSecret, }, }, plugins: [ expo({ disableOriginOverride: true }), magicLink({ sendMagicLink: async ({ email, token, url }, ctx) => { await emailService.sendEmail( email, "Magic Link", `<a href="${url}">${url}</a>` ); }, }), ], advanced: { disableOriginCheck: true, }, }); }; ``` ### Additional context _No response_
GiteaMirror added the locked label 2026-04-13 06:57:11 -05:00
Author
Owner

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

It seems you're experiencing issues with the magic link session not persisting in your Expo app when using the Hono backend. Here are some steps to help troubleshoot and ensure proper functionality:

  1. Verify Configuration:
    Check that your trustedOrigins in the backend configuration includes both your scheme (e.g., cocottesrooms://) and the Expo URL (e.g., exp://) in development mode. This is necessary for accepting incoming requests from the magic link [2].

  2. Cookie Management:
    Ensure the cookies are being managed correctly in your Expo app. The set-cookie header in the response from your backend should be properly received by the client. Verify that your Expo app is configured to handle cookies as expected, especially concerning the SecureStore you are using.

  3. Deep Linking:
    Verify that your app's deep linking is set up correctly. The link sent in the magic email should trigger the deep link to your app correctly. Check if there are any issues with parsing or handling that deep link in your client code.

  4. Testing with Different Accounts:
    Try testing with different email accounts to ensure that the issue is not related to a specific account or email provider.

  5. Debugging Session State:
    Utilize the useSession hook and log the output immediately after redirection to see if any part of the session state is being populated before returning null.

If you've verified these steps and the issue persists, consider reviewing if any additional contexts related to the system configuration could be affecting the session persistence.

Additionally, since similar issues have been discussed and are still open, you might want to tag Beka (@bekacru) and Max (@ping__) in your ongoing discussions for more in-depth support.

Is there any specific step from the above that you would like to explore further, or do you have additional details about your setup that could help diagnose this issue?

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

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3684018189 --> @better-auth-agent[bot] commented on GitHub (Dec 22, 2025): It seems you're experiencing issues with the magic link session not persisting in your Expo app when using the Hono backend. Here are some steps to help troubleshoot and ensure proper functionality: 1. **Verify Configuration:** Check that your `trustedOrigins` in the backend configuration includes both your scheme (e.g., `cocottesrooms://`) and the Expo URL (e.g., `exp://`) in development mode. This is necessary for accepting incoming requests from the magic link [[2]](https://www.better-auth.com/docs/plugins/magic-link). 2. **Cookie Management:** Ensure the cookies are being managed correctly in your Expo app. The `set-cookie` header in the response from your backend should be properly received by the client. Verify that your Expo app is configured to handle cookies as expected, especially concerning the `SecureStore` you are using. 3. **Deep Linking:** Verify that your app's deep linking is set up correctly. The link sent in the magic email should trigger the deep link to your app correctly. Check if there are any issues with parsing or handling that deep link in your client code. 4. **Testing with Different Accounts:** Try testing with different email accounts to ensure that the issue is not related to a specific account or email provider. 5. **Debugging Session State:** Utilize the `useSession` hook and log the output immediately after redirection to see if any part of the session state is being populated before returning null. If you've verified these steps and the issue persists, consider reviewing if any additional contexts related to the system configuration could be affecting the session persistence. Additionally, since similar issues have been discussed and are still open, you might want to tag Beka (@bekacru) and Max (@ping__) in your ongoing discussions for more in-depth support. Is there any specific step from the above that you would like to explore further, or do you have additional details about your setup that could help diagnose 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 22, 2025):

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

This is a common Expo + magic link integration pitfall. The session isn’t persisting because, in Expo/native, the session token must be handed off via a cookie query parameter in the deep link—not just a Set-Cookie header in the 302 response. Browsers handle cookies, but mobile deep links don’t, so the Expo plugin expects the backend to append the session cookie to the deep link URL (e.g., cocottesrooms:///dashboard?cookie=...) so it can extract and store it in SecureStore for future requests. If the deep link doesn’t have this parameter, the session will stay null even though the redirect works as expected ref ref.

Troubleshooting checklist:

  1. After clicking the magic link, check the deep link URL that opens your app. Does it have a cookie query parameter? If not, the backend isn’t appending it—usually a trustedOrigins or callback URL config issue.
  2. If the deep link has the cookie, log the SecureStore value after sign-in to confirm it’s being saved.
  3. If the session is still null after redirect, call await authClient.getSession() after the redirect to force a session refresh ref.
  4. Make sure your Expo app’s scheme matches what’s in trustedOrigins on the backend (e.g., cocottesrooms://), and that the Expo plugin is initialized before any sign-in attempt.

If the deep link is missing the cookie, double-check your backend config and trustedOrigins. If SecureStore isn’t saving the cookie, review your Expo plugin setup. Logging the full deep link and SecureStore contents after sign-in will pinpoint where the flow is breaking.

Let me know what you see in the deep link and SecureStore after the redirect—this will help narrow it down!

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

<!-- gh-comment-id:3684029287 --> @dosubot[bot] commented on GitHub (Dec 22, 2025): <!-- Greeting --> Hi @mfrachet! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a common Expo + magic link integration pitfall. The session isn’t persisting because, in Expo/native, the session token must be handed off via a `cookie` query parameter in the deep link—not just a `Set-Cookie` header in the 302 response. Browsers handle cookies, but mobile deep links don’t, so the Expo plugin expects the backend to append the session cookie to the deep link URL (e.g., `cocottesrooms:///dashboard?cookie=...`) so it can extract and store it in SecureStore for future requests. If the deep link doesn’t have this parameter, the session will stay null even though the redirect works as expected [ref](https://github.com/better-auth/better-auth/issues/3711) [ref](https://github.com/better-auth/better-auth/issues/4070). **Troubleshooting checklist:** 1. After clicking the magic link, check the deep link URL that opens your app. Does it have a `cookie` query parameter? If not, the backend isn’t appending it—usually a `trustedOrigins` or callback URL config issue. 2. If the deep link has the cookie, log the SecureStore value after sign-in to confirm it’s being saved. 3. If the session is still null after redirect, call `await authClient.getSession()` after the redirect to force a session refresh [ref](https://github.com/better-auth/better-auth/discussions/3982). 4. Make sure your Expo app’s scheme matches what’s in `trustedOrigins` on the backend (e.g., `cocottesrooms://`), and that the Expo plugin is initialized before any sign-in attempt. If the deep link is missing the cookie, double-check your backend config and trustedOrigins. If SecureStore isn’t saving the cookie, review your Expo plugin setup. Logging the full deep link and SecureStore contents after sign-in will pinpoint where the flow is breaking. Let me know what you see in the deep link and SecureStore after the redirect—this will help narrow it down! <!-- 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/95cd426e-82db-4c70-9731-29876bd7681c?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/95cd426e-82db-4c70-9731-29876bd7681c?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/95cd426e-82db-4c70-9731-29876bd7681c?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/95cd426e-82db-4c70-9731-29876bd7681c?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/95cd426e-82db-4c70-9731-29876bd7681c?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/95cd426e-82db-4c70-9731-29876bd7681c?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/95cd426e-82db-4c70-9731-29876bd7681c?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%20common%20Expo%20%2B%20magic%20link%20integration%20pitfall.%20The%20session%20isn%E2%80%99t%20persisting%20because%2C%20in%20Expo/native%2C%20the%20session%20token%20must%20be%20handed%20off%20via%20a%20%60cookie%60%20query%20parameter%20in%20the%20deep%20link%E2%80%94not%20just%20a%20%60Set-Cookie%60%20header%20in%20the%20302%20response.%20Browsers%20handle%20cookies%2C%20but%20mobile%20deep%20links%20don%E2%80%99t%2C%20so%20the%20Expo%20plugin%20expects%20the%20backend%20to%20append%20the%20session%20cookie%20to%20the%20deep%20link%20URL%20%28e.g.%2C%20%60cocottesrooms%3A///dashboard%3Fcookie%3D...%60%29%20so%20it%20can%20extract%20and%20store%20it%20in%20SecureStore%20for%20future%20requests.%20If%20the%20deep%20link%20doesn%E2%80%99t%20have%20this%20parameter%2C%20the%20session%20will%20stay%20null%20even%20though%20the%20redirect%20works%20as%20expected%C2%A0%5Bref%5D%28https%3A//github.com/better-auth/better-auth/issues/3711%29%C2%A0%5Bref%5D%28https%3A//github.com/better-auth/better-auth/issues/4070%29.%0A%0A%2A%2ATroubleshooting%20checklist%3A%2A%2A%0A1.%20After%20clicking%20the%20magic%20link%2C%20check%20the%20deep%20link%20URL%20that%20opens%20your%20app.%20Does%20it%20have%20a%20%60cookie%60%20query%20parameter%3F%20If%20not%2C%20the%20backend%20isn%E2%80%99t%20appending%20it%E2%80%94usually%20a%20%60trustedOrigins%60%20or%20callback%20URL%20config%20issue.%0A2.%20If%20the%20deep%20link%20has%20the%20cookie%2C%20log%20the%20SecureStore%20value%20after%20sign-in%20to%20confirm%20it%E2%80%99s%20being%20saved.%0A3.%20If%20the%20session%20is%20still%20null%20after%20redirect%2C%20call%20%60await%20authClient.getSession%28%29%60%20after%20the%20redirect%20to%20force%20a%20session%20refresh%C2%A0%5Bref%5D%28https%3A//github.com/better-auth/better-auth/discussions/3982%29.%0A4.%20Make%20sure%20your%20Expo%20app%E2%80%99s%20scheme%20matches%20what%E2%80%99s%20in%20%60trustedOrigins%60%20on%20the%20backend%20%28e.g.%2C%20%60cocottesrooms%3A//%60%29%2C%20and%20that%20the%20Expo%20plugin%20is%20initialized%20before%20any%20sign-in%20attempt.%0A%0AIf%20the%20deep%20link%20is%20missing%20the%20cookie%2C%20double-check%20your%20backend%20config%20and%20trustedOrigins.%20If%20SecureStore%20isn%E2%80%99t%20saving%20the%20cookie%2C%20review%20your%20Expo%20plugin%20setup.%20Logging%20the%20full%20deep%20link%20and%20SecureStore%20contents%20after%20sign-in%20will%20pinpoint%20where%20the%20flow%20is%20breaking.%0A%0ALet%20me%20know%20what%20you%20see%20in%20the%20deep%20link%20and%20SecureStore%20after%20the%20redirect%E2%80%94this%20will%20help%20narrow%20it%20down%21)&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/6936)
Author
Owner

@bytaesu commented on GitHub (Dec 22, 2025):

Hi @mfrachet, I'm looking into this!

<!-- gh-comment-id:3684282814 --> @bytaesu commented on GitHub (Dec 22, 2025): Hi @mfrachet, I'm looking into this!
Author
Owner

@bytaesu commented on GitHub (Dec 22, 2025):

Hi @mfrachet, could you let me know if this version resolves the issue?

npm i https://pkg.pr.new/better-auth/better-auth/@better-auth/expo@6939
<!-- gh-comment-id:3684453048 --> @bytaesu commented on GitHub (Dec 22, 2025): Hi @mfrachet, could you let me know if this version resolves the issue? ```sh npm i https://pkg.pr.new/better-auth/better-auth/@better-auth/expo@6939 ```
Author
Owner

@mfrachet commented on GitHub (Dec 23, 2025):

@bytaesu

Thanks a lot for your help 🙏🏻 . I think it's one step further, but it's still not working.

Here's the code I have:

 useEffect(() => {
    const link = Linking.addEventListener("url", async (event) => {
      console.log("url", event.url);
      const session = await authClient.getSession();

      console.log("session", session);
    });

    return () => {
      link.remove();
    };
  }, []);

And here are the logs I get:

 LOG  url cocottesrooms:///dashboard?cookie=better-auth.session_token%3DBHzA8IYNPIKyxNx3irS4fIj0OiKgugri.AtpwhyqnrQ%252Fmxo6DvE8vn8B6%252FM%252B5B6TJiKlpHPzLQvA%253D%3B+Max-Age%3D604800%3B+Path%3D%2F%3B+HttpOnly%3B+SameSite%3DLax

 LOG  session {"data": null, "error": null}

is there any additional thing I should do with the cookie?

<!-- gh-comment-id:3686146706 --> @mfrachet commented on GitHub (Dec 23, 2025): @bytaesu Thanks a lot for your help 🙏🏻 . I think it's one step further, but it's still not working. Here's the code I have: ```ts useEffect(() => { const link = Linking.addEventListener("url", async (event) => { console.log("url", event.url); const session = await authClient.getSession(); console.log("session", session); }); return () => { link.remove(); }; }, []); ``` And here are the logs I get: ``` LOG url cocottesrooms:///dashboard?cookie=better-auth.session_token%3DBHzA8IYNPIKyxNx3irS4fIj0OiKgugri.AtpwhyqnrQ%252Fmxo6DvE8vn8B6%252FM%252B5B6TJiKlpHPzLQvA%253D%3B+Max-Age%3D604800%3B+Path%3D%2F%3B+HttpOnly%3B+SameSite%3DLax LOG session {"data": null, "error": null} ``` is there any additional thing I should do with the cookie?
Author
Owner

@bytaesu commented on GitHub (Dec 23, 2025):

Hi @mfrachet,

Could you share a reproducible minimal repo if possible? I wanna check 🙂

<!-- gh-comment-id:3687165876 --> @bytaesu commented on GitHub (Dec 23, 2025): Hi @mfrachet, Could you share a reproducible minimal repo if possible? I wanna check 🙂
Author
Owner

@yogthesharma commented on GitHub (Dec 31, 2025):

This doesn't solve the issue @bytaesu i am building with expo (latest) better auth (latest: what you mentioned) but for backend i am using convex backend the magic link auth doesn't work on it. Plz drop a comment here once it works.

<!-- gh-comment-id:3702398303 --> @yogthesharma commented on GitHub (Dec 31, 2025): This doesn't solve the issue @bytaesu i am building with expo (latest) better auth (latest: what you mentioned) but for backend i am using convex backend the magic link auth doesn't work on it. Plz drop a comment here once it works.
Author
Owner

@maelp commented on GitHub (Feb 26, 2026):

I also posted an issue here for Capacitor https://github.com/better-auth/better-auth/issues/8163

<!-- gh-comment-id:3965716642 --> @maelp commented on GitHub (Feb 26, 2026): I also posted an issue here for Capacitor https://github.com/better-auth/better-auth/issues/8163
Author
Owner

@github-actions[bot] commented on GitHub (Apr 1, 2026):

This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.

<!-- gh-comment-id:4166556944 --> @github-actions[bot] commented on GitHub (Apr 1, 2026): This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10676