Created
June 15, 2018 11:38
-
-
Save Naetmul/14202860903068f71fe68bf946b7f573 to your computer and use it in GitHub Desktop.
Twitter (OAuth): Creating a signature in Python 3.6.5
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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