OAuth 1.0のsignatureの生成の仕方がわからない


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]




間違っているのは `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)を参照してください。




間違っているのは `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)を参照してください。

