85415


OAuthのsignatureをライブラリを使用しないで、生成したいのですが、おそらく間違っており、headesの`oauth_token`にconsumer_secretを設定するのが正しいのかがわかりません。

signatureは`oauth`系の値を`&`で結合して、`SHA1`でハッシュ値に変換みたいな流れだと思っています。

どこがまちがえているのでしょうか？

## エラー

[code]

    urllib.error.HTTPError: HTTP Error 401: Unauthorized
    
    "code": 32,
    "message": "Could not authenticate you."
    
[/code]

[code]

    import calendar
    import time
    import uuid
    import urllib.parse
    import urllib.request
    import hmac
    import hashlib
    
    def getSignature(values):
      values = list(map(lambda x: urllib.parse.quote(x), values))
      joinedValue = "&".join(values).encode("utf-8")
      signature = hmac.new(joinedValue, None, hashlib.sha1).hexdigest()
      return signature
    
    request_token_url = "https://api.twitter.com/oauth/request_token"
    http_method = "POST"
    consumer_key = "FakeConsumerKey"
    consumer_secret = "FakeConsumerSecretKey"
    nonce = str(uuid.uuid4()) # Only ASCII
    signature_method = "HMAC-SHA1"
    timestamp = str(calendar.timegm(time.gmtime()))
    version = "1.0"
    
    valueForSignature = [
      http_method,
      request_token_url,
      consumer_key,
      consumer_secret,
      nonce,
    ]
    
    signature = getSignature(valueForSignature)
    
    callbackURL = "https://localhost:8000"
    
    headers = {
      "oauth_nonce": nonce,
      "oauth_callback": callbackURL,
      "oauth_signature_method": signature_method,
      "oauth_timestamp": timestamp,
      "oauth_consumer_key": consumer_key,
      "oauth_signature": signature,
      "oauth_version": version,
    }
    
    values = [f"{key}=\"{urllib.parse.quote(value)}\"" for key, value in headers.items()]
    
    authorization = ",".join(values)
    authorization = f"OAuth {authorization}"
    
    params = {
      "oauth_callback": callbackURL,
    }
    
    req = urllib.request.Request('{}?{}'.format(request_token_url, urllib.parse.urlencode(params)))
    req.add_header("Authorization", authorization)
    
    print(authorization)
    
    with urllib.request.urlopen(req) as res:
      data = res.read().decode('utf-8')
      print(data)
    
    
[/code]


CC BY-SA 4.0
2021-12-29T06:36:55.593
85393
2022-01-02T10:07:28.330
2021-12-29T09:00:46.507
40856
40856
question
python oauth
OAuth 1.0のsignatureの生成の仕方がわからない


間違っているのは `joinedValue` を作るときリクエストパラメータが足りない・正規化していないことと、 HMAC-SHA1
に署名キーを渡していないところです。

OAuth 1.0 の署名は以下の手順で作成します。

  1. 署名ベース文字列を作成する 
    1. 正規化済みパラメータ文字列を作成する 
      1. すべての HTTP リクエストパラメータと `oauth_*` パラメータを収集する
      2. すべてのキーと値をパーセントエンコードする
      3. （エンコード後の）キーのアルファベット昇順でキー・値ペアを並べ替える
      4. 各ペアについてキーと値を `=` で結合する
      5. それらを順に `&` で結合したものを署名ベース文字列とする
    2. ベース URL を作成する 
      1. リクエスト URL からクエリ文字列とフラグメントを取り除いたものをベース URL とする
    3. 大文字の HTTP メソッド名と、ベース URL をパーセントエンコードしたものと、正規化済みパラメータ文字列をパーセントエンコードしたものを、この順で `&` で結合したものを署名ベース文字列とする
  2. 署名キーを作成する 
    1. コンシューマーシクレットをパーセントエンコードしたものと、 OAuth トークンシークレットをパーセントエンコードしたものを、この順で `&` で結合したものを署名キーとする
  3. 署名キーをキーに、署名ベース文字列をメッセージにして HMAC-SHA1 を計算する
  4. 計算結果のバイナリ文字列を Base64 エンコードしたものを署名とする

実例を交えた正確な説明は[RFC5849（日本語訳）](https://openid-foundation-
japan.github.io/rfc5849.ja.html#anchor6)を参照してください。


CC BY-SA 4.0
2021-12-30T13:43:32.547
85415
2021-12-30T13:51:48.343
2021-12-30T13:51:48.343
2259
2259
85393
answer


うまくいったコードを載せておきます。

[code]

    import time, uuid
    import urllib.parse
    import urllib.request
    import hmac, hashlib, base64
    
    consumerKey = "FakeConsumerKey"
    consumerSecretKey = "FakeSecretConsumerKey"
    requestTokenURL = "https://api.twitter.com/oauth/request_token"
    httpMethod = "POST"
    oauthVersion = "1.0"
    signatureMethod = "HMAC-SHA1"
    nonce = str(uuid.uuid4())
    timestamp = str(int(time.time()))
    accessTokenSecret = "" # ここは空で良い
    
    def encodeURL(value):
      # Oauth1.0で許可されている文字列(許可されている文字は変換されない)
      # https://developer.twitter.com/ja/docs/authentication/oauth-1-0a/percent-encoding-parameters
      return urllib.parse.quote(value, safe="-._~")
    
    def getParameterString(parameters):
      encodedValues = dict([(encodeURL(key), encodeURL(value)) for key, value in parameters.items()])
      sortedValues = dict(sorted(encodedValues.items()))
      eachJoinedValues = list([f"{key}={value}" for key, value in sortedValues.items()])
      joinedValue = "&".join(eachJoinedValues)
      return joinedValue
    
    oauth_params = {
      "oauth_consumer_key": consumerKey,
      "oauth_nonce": nonce,
      "oauth_signature_method": signatureMethod,
      "oauth_timestamp": timestamp,
      "oauth_version": oauthVersion,
    }
    
    parameterString = getParameterString(oauth_params)
    
    parameters = [
      httpMethod,
      requestTokenURL,
      parameterString,
    ]
    
    def getBaseString(parameters):
      encodedValues = list([encodeURL(parameter) for parameter in parameters])
      joinedValue = "&".join(encodedValues)
      return joinedValue
    
    baseString = getBaseString(parameters)
    
    key = f"{encodeURL(consumerSecretKey)}&{encodeURL(accessTokenSecret)}"
    
    def getSignature(key, message):
      hashedValue = hmac.new(key.encode(), message.encode(), hashlib.sha1).digest()
      signature = base64.b64encode(hashedValue).decode()
      return signature
    
    signature = getSignature(key, baseString)
    
    oauthValues = {
      "oauth_consumer_key": consumerKey,
      "oauth_nonce": nonce,
      "oauth_signature": signature,
      "oauth_signature_method": signatureMethod,
      "oauth_timestamp": timestamp,
      "oauth_version": oauthVersion,
    }
    
    joinedOauthValus = list([f"{encodeURL(key)}=\"{encodeURL(value)}\"" for key, value in oauthValues.items()])
    oauth = ",".join(joinedOauthValus)
    authorization = f"OAuth {oauth}"
    
    request = urllib.request.Request(requestTokenURL, method=httpMethod)
    request.add_header("Authorization", authorization)
    
    with urllib.request.urlopen(request) as response:
      data = response.read().decode()
      values = data.split("&")
      oauth_token = values[0].split("=")[1]
      url = f"https://api.twitter.com/oauth/authenticate?oauth_token={oauth_token}"
      print(url)
    
[/code]


CC BY-SA 4.0
2022-01-02T10:07:28.330
85444
2022-01-02T10:07:28.330
40856
85393
answer