Skip to content

Instantly share code, notes, and snippets.

@Naetmul
Created June 15, 2018 11:38
Show Gist options
  • Save Naetmul/14202860903068f71fe68bf946b7f573 to your computer and use it in GitHub Desktop.
Save Naetmul/14202860903068f71fe68bf946b7f573 to your computer and use it in GitHub Desktop.
Twitter (OAuth): Creating a signature in Python 3.6.5
from typing import Optional, Dict
from enum import Enum, auto
import base64
import hmac
import requests
class HttpMethod(Enum):
GET = auto()
POST = auto()
def percent_encode(s: str) -> str:
return requests.utils.quote(s, safe="")
# https://developer.twitter.com/en/docs/basics/authentication/guides/creating-a-signature.html
def create_signature(http_method: HttpMethod, base_url: str, params: Dict[str, str], consumer_secret: str, token_secret: Optional[str] = None):
parameter_string = get_parameter_string(params)
signature_base_string = get_signature_base_string(http_method, base_url, parameter_string)
signing_key = get_signing_key(consumer_secret, token_secret)
signature = calc_signature(signature_base_string, signing_key)
return signature
def get_parameter_string(params: Dict[str, str]) -> str:
output_str = ""
# Percent encode every key and value that will be signed.
param_list = []
for key, value in params.items():
percent_encoded_key = percent_encode(key)
percent_encoded_value = percent_encode(value)
param_list.append((percent_encoded_key, percent_encoded_value))
# Sort the list of parameters alphabetically by encoded key.
param_list.sort(key=lambda pair: pair[0])
# For each key/value pair
for index, pair in enumerate(param_list):
# Append the encoded key to the output string.
output_str = output_str + pair[0]
# Append the ‘=’ character to the output string.
output_str = output_str + "="
# Append the encoded value to the output string.
output_str = output_str + pair[1]
# If there are more key/value pairs remaining, append a ‘&’ character to the output string.
if index < len(param_list) - 1:
output_str = output_str + "&"
return output_str
def get_signature_base_string(http_method: HttpMethod, base_url: str, parameter_string: str) -> str:
# Convert the HTTP Method to uppercase and set the output string equal to this value.
if http_method is HttpMethod.GET:
http_method_str = "GET"
elif http_method is HttpMethod.POST:
http_method_str = "POST"
else:
raise NotImplementedError
output_str = http_method_str
# Append the ‘&’ character to the output string.
output_str = output_str + "&"
# Percent encode the URL and append it to the output string.
percent_encoded_url = percent_encode(base_url)
output_str = output_str + percent_encoded_url
# Append the ‘&’ character to the output string.
output_str = output_str + "&"
# Percent encode the parameter string and append it to the output string.
percent_encoded_parameter_string = percent_encode(parameter_string)
output_str = output_str + percent_encoded_parameter_string
return output_str
def get_signing_key(consumer_secret: str, token_secret: Optional[str] = None) -> str:
percent_encoded_consumer_secret = percent_encode(consumer_secret)
if token_secret is not None:
percent_encoded_token_secret = percent_encode(token_secret)
signing_key = percent_encoded_consumer_secret + "&" + percent_encoded_token_secret
else:
signing_key = percent_encoded_consumer_secret + "&"
return signing_key
def calc_signature(signature_base_string: str, signing_key: str) -> str:
# Passing the signature base string and signing key to the HMAC-SHA1 hashing algorithm.
key_bytes = signing_key.encode()
msg_bytes = signature_base_string.encode()
hmac_obj = hmac.new(key_bytes, msg_bytes, "sha1")
signature_bytes = hmac_obj.digest()
# This needs to be base64 encoded to produce the signature string.
encoded_bytes = base64.b64encode(signature_bytes)
signature = encoded_bytes.decode()
return signature
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment