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

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版本+排查细节

  1. 升级Supabase Python SDK:旧版本可能存在Auth API的兼容性问题,跑这个命令更新:
pip install --upgrade supabase-py python-dotenv
  1. 确保邮箱完全匹配:输入的邮箱要和注册时完全一致(虽然Supabase邮箱不区分大小写,但保险起见尽量一模一样)。
  2. 查看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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 12:24:38