You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expo开发客户端Supabase魔法链接auth setSession静默挂起问题

Expo SDK 54 + Supabase Auth 魔法链接登录静默挂起问题

基于Expo SDK 54开发的应用,采用Supabase Auth隐式流程实现魔法链接登录。用户点击魔法链接后,深度链接回调可正常接收URL并解析片段,但调用supabase.auth.setSession()时会静默挂起,既不返回结果也不抛出错误,应用持续停留在“设置您的账户”加载界面。此前使用PKCE流程时,exchangeCodeForSession也出现过相同挂起问题,切换至隐式流程后问题依旧。

技术栈

  • Expo SDK 54
  • React Native(Hermes引擎)
  • @supabase/supabase-js v2.x(最新版)
  • expo-router 用于导航
  • EAS Build构建的iOS开发客户端(自定义URL Scheme)
  • 会话存储采用AsyncStorage适配器
  • 已安装并优先导入react-native-get-random-values polyfill

认证流程

Gate → 邮箱输入 → 发送链接 → 接收魔法链接 → 点击链接 → 深度链接打开应用 → 回调解析#access_token → setSession() → 挂起

已验证正常的环节

  • Supabase应用表验证查询(双向通信正常)
  • signInWithOtp魔法链接生成
  • 深度链接正常打开应用,URL格式为myapp://auth/callback#access_token=...&refresh_token=...
  • URL片段解析可正确提取令牌
  • 错误流程完全正常:令牌无效(otp_expired)时,回调可解析错误并导航回邮箱输入页,日志正常输出

挂起场景

  • 传入有效未使用令牌调用setSession({ access_token, refresh_token })时挂起
  • PKCE流程的exchangeCodeForSession曾出现相同挂起模式
  • 两个认证函数传入有效令牌时均静默挂起

诊断日志

点击未使用的全新魔法链接(成功流程):

[callback] run() entered, url: myapp://auth/callback#access_token=eyJ...&refresh_token=...&token_type=bearer&expires_in=3600
[callback] parsed fragment, has tokens: true
[callback] setSession start

后续无输出,setSession done日志从未打印。

点击已使用的魔法链接(Gmail预获取):

[callback] run() entered, url: myapp://auth/callback#error=access_denied&error_code=otp_expired&...
[callback] parsed fragment, has tokens: false errorCode: access_denied
[callback] error in fragment: access_denied Email link is invalid or has expired
[callback] routing to: /(auth)/email (error path)

错误流程完全正常,仅成功流程挂起。

已尝试的方案

  1. 带react-native-get-random-values polyfill的PKCE流程(仅提供crypto.getRandomValues,无crypto.subtle)
  2. 切换至隐式流程(flowType: 'implicit')避开PKCE
  3. 替换SecureStore适配器为AsyncStorage
  4. 多次重新构建EAS开发客户端
  5. 卸载重装应用清空AsyncStorage
  6. 使用多种邮件方式确保令牌未被预使用

代码配置

Supabase客户端配置(lib/supabase.ts)

import 'react-native-get-random-values';
import 'react-native-url-polyfill/auto';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { createClient } from '@supabase/supabase-js';

export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
  auth: {
    storage: AsyncStorage,
    autoRefreshToken: true,
    persistSession: true,
    detectSessionInUrl: false, // 自行处理深度链接回调
    flowType: 'implicit',
  },
});

回调处理器(app/auth/callback.tsx 相关片段)

const url = Linking.useURL();

useEffect(() => {
  if (!url) return;
  if (processedRef.current === url) return;
  processedRef.current = url;
  
  const run = async () => {
    console.log('[callback] run() entered, url:', url);
    
    const fragment = parseAuthFragment(url);
    console.log('[callback] parsed fragment, has tokens:', !!fragment?.accessToken);
    
    if (fragment?.error) {
      // ... 错误流程正常执行 ...
      return;
    }
    
    if (!fragment?.accessToken || !fragment?.refreshToken) {
      // ... 令牌缺失处理 ...
      return;
    }
    
    console.log('[callback] setSession start');
    const { error } = await supabase.auth.setSession({
      access_token: fragment.accessToken,
      refresh_token: fragment.refreshToken,
    });
    console.log('[callback] setSession done:', error); // ← 从未打印
    
    // ... 后续流程未执行 ...
  };
  
  run();
}, [url]);

相关Metro警告

supabase-js初始化时会触发警告:

WARN  WebCrypto API is not supported. Code challenge method will default to use plain instead of sha256.

切换至隐式流程后警告仍存在,推测supabase-js在隐式流程中仍调用crypto.subtle,因API缺失导致静默挂起。

疑问

是否有人遇到React Native + Hermes环境中Supabase魔法链接认证setSession/exchangeCodeForSession静默挂起的问题?
怀疑因缺少crypto.subtle(react-native-get-random-values未polyfill该API)导致。若已解决:

  • 添加完整WebCrypto polyfill是否有效?
  • 降级@supabase/supabase-js到特定版本是否可行?
  • 是否有兼容的Expo SDK+supabase-js+认证流程组合?
  • 是否需切换至邮箱密码认证作为临时方案?

应用架构其他环节均正常,仅成功流程因该挂起受阻。


内容的提问来源于stack exchange,提问作者Ana Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 22:57:27