Python调用Supabase重置未认证用户密码时提示Token无效/过期的问题排查
Python调用Supabase重置未认证用户密码时提示Token无效/过期的问题排查
我之前也遇到过类似的问题,折腾了好一阵才找到原因,结合你的脚本和Supabase Auth的工作机制,咱们一步步拆解可能的问题和解决办法:
先说说最可能踩中的坑:脚本流程设计不合理
你的脚本现在是发送重置链接后立刻强制进入更新密码步骤,但实际场景里,用户需要时间去查收邮件、复制链接——而Supabase的重置token默认只有10分钟有效期(虽然这个时间够,但如果用户操作慢一点,或者脚本一直挂着导致会话状态异常,就容易触发token无效的错误)。
解决办法:改成菜单式交互
让用户可以自主选择什么时候执行“发送链接”和“更新密码”,比如先发送链接,退出脚本处理邮件,再回来更新密码:
def main(): supabase: Client = get_supabase_object() print("Connected to Supabase client successfully!\n") while True: print("=== Password Reset Tool ===") print("1. Send Password Reset Email") print("2. Set New Password Using Reset Link") print("3. Exit") choice = input("Enter your choice (1/2/3): ") if choice == "1": send_reset_link(supabase) elif choice == "2": update_password(supabase) elif choice == "3": print("Exiting tool. Goodbye!") break else: print("Invalid choice. Please enter 1, 2, or 3.\n") if __name__ == "__main__": main()
这样完全避免了流程时序导致的问题,用户操作起来也更灵活。
第二个隐患:手动Split提取Token的方式不靠谱
你用link.split("token=")[1].split("&type")[0]提取token,看起来没问题,但如果链接里的参数顺序变化(虽然Supabase默认不会,但万一有URL编码的特殊字符呢?比如token里包含&?),就会提取到错误的token。
解决办法:用URL解析库正规提取
用Python内置的urllib.parse来解析链接参数,绝对不会出错:
from urllib.parse import urlparse, parse_qs def extract_token_from_link(link): parsed_url = urlparse(link) query_params = parse_qs(parsed_url.query) if "token" not in query_params: raise ValueError("Invalid link. No token found.") # 注意query_params返回的是列表,取第一个元素 return query_params["token"][0]
然后在update_password里替换成:
token = extract_token_from_link(link)
第三个可能:Verify OTP后的会话没有正确绑定
Supabase的Python客户端理论上会自动保存verify_otp后的临时会话,但有时候因为网络波动或SDK版本问题,会话没有被正确绑定到客户端,导致后续update_user因为没有授权而报错(表面上是token无效,实际是会话丢失)。
解决办法:手动绑定临时会话
在verify_otp成功后,手动把会话设置到客户端:
resp_1 = supabase.auth.verify_otp({ "email": email, "type": "recovery", "token": token, }) # 手动校验会话是否存在,然后绑定 if not resp_1.session: raise ValueError("Temporary session not established. Verify OTP may have failed.") supabase.auth.set_session(resp_1.session.access_token, resp_1.session.refresh_token)
最后:升级SDK版本+排查细节
- 升级Supabase Python SDK:旧版本可能存在Auth API的兼容性问题,跑这个命令更新:
pip install --upgrade supabase-py python-dotenv
- 确保邮箱完全匹配:输入的邮箱要和注册时完全一致(虽然Supabase邮箱不区分大小写,但保险起见尽量一模一样)。
- 查看Verify OTP的响应:运行脚本时留意
RESP_1的输出,如果verify_otp失败,响应里的error字段会给出具体原因(比如token过期、邮箱不匹配),这是最直接的排查线索。
整合所有修正后的完整脚本
import os from urllib.parse import urlparse, parse_qs from supabase import create_client, Client from dotenv import load_dotenv load_dotenv() def get_supabase_object() -> Client: url: str = os.environ["SUPABASE_URL"] key: str = os.environ["SUPABASE_KEY"] supabase: Client = create_client(url, key) return supabase def send_reset_link(supabase: Client): try: email = input("Please insert your email\n") resp = supabase.auth.reset_password_for_email(email) print("RESP=") print(resp) print("\nIf your email is already registered, you will receive a password reset email! Please check your inbox.\n") except Exception as e: print("Failed to send reset email: ", str(e), "\n") def extract_token_from_link(link): parsed_url = urlparse(link) query_params = parse_qs(parsed_url.query) if "token" not in query_params: raise ValueError("Invalid link. No token found.") return query_params["token"][0] def update_password(supabase: Client): try: link = input("Please paste the link you received via email\n") email = input("Please insert your email\n") password = input("Please insert your new password\n") # Extract token from the link using URL parser token = extract_token_from_link(link) print("TOKEN = ", token) # Verify the recovery token resp_1 = supabase.auth.verify_otp({ "email": email, "type": "recovery", "token": token, }) print("RESP_1=") print(resp_1) print("\n") # Manually set the temporary session if not resp_1.session: raise ValueError("Temporary session not established. Verify OTP may have failed.") supabase.auth.set_session(resp_1.session.access_token, resp_1.session.refresh_token) # Update the password resp_2 = supabase.auth.update_user({ "password": password }) print("RESP_2=") print(resp_2) print("\n") print("Password updated successfully\n") except Exception as e: print("Failed to update password: ", str(e), "\n") def main(): supabase: Client = get_supabase_object() print("Connected to Supabase client successfully!\n") while True: print("=== Password Reset Tool ===") print("1. Send Password Reset Email") print("2. Set New Password Using Reset Link") print("3. Exit") choice = input("Enter your choice (1/2/3): ") if choice == "1": send_reset_link(supabase) elif choice == "2": update_password(supabase) elif choice == "3": print("Exiting tool. Goodbye!") break else: print("Invalid choice. Please enter 1, 2, or 3.\n") if __name__ == "__main__": main()
按照这个脚本操作,应该就能解决token无效/过期的问题了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

