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

为何我的OAuth 1.0签名无法通过Twitter API认证?

问题描述

调用Twitter API获取用户凭证时,持续返回认证失败错误:

{"errors":[{"code":32,"message":"Could not authenticate you."}]}

我的代码如下:

# Libraries
import requests
import urllib.parse
import time
import hmac
import hashlib
import base64

# Set your callback URL here
callback_url = 'https://twitter.com/lemonknowsall'

# Generate nonce and timestamp
timestamp = str(int(time.time()))
nonce = timestamp

# Define the OAuth signature method and version
signature_method = 'HMAC-SHA1'
oauth_version = '1.0'

# Encode the callback URL
encoded_callback_url = urllib.parse.quote(callback_url, safe='')

# Construct the base string
base_string = f'POST&{urllib.parse.quote("https://api.twitter.com/oauth/request_token", safe="")}&'
base_string += f'oauth_callback%3D{encoded_callback_url}%26'
base_string += f'oauth_consumer_key%3D{consumer_key}%26'
base_string += f'oauth_nonce%3D{nonce}%26'
base_string += f'oauth_signature_method%3D{signature_method}%26'
base_string += f'oauth_timestamp%3D{timestamp}%26'
base_string += f'oauth_version%3D{oauth_version}'

# Create the signing key
signing_key = f'{urllib.parse.quote(consumer_secret, safe="")}&'

# Generate the signature
signature = base64.b64encode(hmac.new(signing_key.encode('utf-8'), base_string.encode('utf-8'), hashlib.sha1).digest())

# Encode the signature
encoded_signature = urllib.parse.quote(signature, safe='')

# Construct the request URL
url = "https://api.twitter.com/oauth/request_token?"
url += f"oauth_callback={encoded_callback_url}"+"&"
url += f"oauth_consumer_key={consumer_key}"+"&"
url += "oauth_signature_method=HMAC-SHA1"+"&"
url += "oauth_version=1.0"+"&"
url += f"oauth_timestamp={timestamp}"+"&"
url += f"oauth_nonce={nonce}"+"&"
url += f"oauth_signature={encoded_signature}"

response = requests.request("POST", url)

print(response.text)

已确认consumer_key和consumer_secret已正确定义,回调URL也在Twitter开发者平台验证通过。替换Postman生成的encoded_signature就能成功响应,推测问题出在base_string或签名生成环节,但找不到具体错误。


解决方法

问题主要出在base_string的构建逻辑和签名编码处理上,以下是具体修正点:

1. 严格按字典序排列OAuth参数

OAuth 1.0要求base_string中的参数必须按参数名的ASCII字典序排列,手动拼接容易出错,建议用排序后的参数键值对构建:

# 替换原base_string构建代码
params = {
    'oauth_callback': callback_url,
    'oauth_consumer_key': consumer_key,
    'oauth_nonce': nonce,
    'oauth_signature_method': signature_method,
    'oauth_timestamp': timestamp,
    'oauth_version': oauth_version
}
# 按参数名ASCII排序
sorted_params = sorted(params.items())
# 编码每个键值对
encoded_params = [f"{urllib.parse.quote(k, safe='')}%3D{urllib.parse.quote(v, safe='')}" for k, v in sorted_params]
# 拼接成base_string的参数部分
params_string = '%26'.join(encoded_params)
base_string = f'POST&{urllib.parse.quote("https://api.twitter.com/oauth/request_token", safe="")}&{params_string}'

2. 签名需先转字符串再做URL编码

原代码直接对base64.b64encode返回的bytes对象做URL编码,会导致b'...'这类字节标识被错误编码,需先转成UTF-8字符串:

# 替换原签名生成和编码代码
signature = base64.b64encode(hmac.new(signing_key.encode('utf-8'), base_string.encode('utf-8'), hashlib.sha1).digest()).decode('utf-8')
encoded_signature = urllib.parse.quote(signature, safe='')

3. 推荐用Authorization头传递参数(可选)

Twitter OAuth 1.0更规范的做法是将OAuth参数放在Authorization请求头中,避免URL编码的潜在问题:

# 替换原URL构建和请求代码
auth_header = (
    f'OAuth oauth_callback="{encoded_callback_url}",'
    f'oauth_consumer_key="{consumer_key}",'
    f'oauth_nonce="{nonce}",'
    f'oauth_signature="{encoded_signature}",'
    f'oauth_signature_method="{signature_method}",'
    f'oauth_timestamp="{timestamp}",'
    f'oauth_version="{oauth_version}"'
)
headers = {'Authorization': auth_header}
response = requests.post("https://api.twitter.com/oauth/request_token", headers=headers)

应用以上修正后,即可生成符合要求的签名,解决认证失败问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 20:45:40