I am trying to call an API with OAuth1.0. But the signature I am generating with my custom code is not matching with the signature that is present in postman. The reason I want both to match is because with Postman I am successfully able to call the API without any issue.
Dummy details that i tried:
URL: https://localhost:4857/fun
Signature Method:HMAC-SHA1
Consumer Key: a
Consumer Secret: b
Access Token: 123
Token Secret: abc
TimeStamp: 123
Nonce: 3
With these details I am getting the Signature URL String as
GET&https%3A%2F%2Flocalhost%3A4857%2Ffun&oauth_consumer_key%3Da%26oauth_nonce%3D3%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D123%26oauth_token%3D123
Key: b&abc
I am encoding both key and signature url string in UTF-8 encoding
Generated Signature from the python hmac module is
e5q17ELBiktwG%2F%2F7TAouAkNKcFI%3D
But Postman is generating the signature as Fs55QGeBXI%2BG3ckdHQLmjwI%2BeUQ%3D
Entire Postman output
GET /fun HTTP/1.1
Host: localhost:4857
Authorization: OAuth oauth_consumer_key="a",oauth_token="123",oauth_signature_method="HMAC-SHA1",oauth_timestamp="123",oauth_nonce="3",oauth_version="1.0",oauth_signature="Fs55QGeBXI%2BG3ckdHQLmjwI%2BeUQ%3D"
I had used the below code to generate the above signature
import hmac
from hashlib import sha1
import base64
import urllib.parse
consumerKey = 'a'
consumerSecret = 'b'
token = 123
tokenSecret = 'abc'
timestamp = 123
nonce = 3
key = '{}&{}'.format(consumerSecret,tokenSecret)
keyencoded = bytes(key,'utf-8')
url = 'https://localhost:4857/fun'
auth = 'oauth_consumer_key={}&oauth_nonce={}&oauth_signature_method=HMAC-SHA1&oauth_timestamp={}&oauth_token={}'.format(consumerKey,nonce,timestamp,token)
urlencoded = urllib.parse.quote(url , safe='')
authencoded = urllib.parse.quote(auth , safe='')
baseString = 'GET&'+urlencoded+'&'+authencoded
baseStringEncoded = bytes(baseString,'utf-8')
signature = hmac.new(keyencoded,baseStringEncoded,sha1)
signaturebase64 = base64.b64encode(signature.digest()).decode()
signUrlEncode = urllib.parse.quote(signaturebase64, safe='')
print(baseString)
print(signUrlEncode)
Please let me know what am I doing wrong?
I would really appreciate any help in understanding why postman is generating a different signature than my one.
Related
I'm using FastAPI's HTTPBearer class to receive authorization tokens on request headers.
This is my dependencies file as per the FastAPI docs, which is used to retrieve the token on any request to the API.
classroom_auth_scheme = HTTPBearer(
scheme_name="Google Auth Credentials",
bearerFormat="Bearer",
description="O-Auth2 Credentials obtained on frontend, used to authenticate with Google services",
)
def get_classroom_token(
token: str = Depends(classroom_auth_scheme),
) -> requests.ClassroomAuthCredentials:
"""Converts a json string of Authorization Bearer token into ClassroomAuthCredentials class
Args:
token (str, optional): Autorization Header Bearer Token. Defaults to Depends(auth_scheme).
Raises:
HTTPException: 400 level response meaning the token was not in the correct format
Returns:
requests.ClassroomAuthCredentials
"""
try:
# token.credentials is a JSON String -> want: pydantic Basemodel
token_dict = json.loads(token.credentials)
token = requests.ClassroomAuthCredentials.parse_obj(token_dict)
return token
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"{e}",
)
And this is how I receive the token in my routes:
#router.post("/test-auth", summary="Validate authentication with Google Classroom API")
async def test_auth(token=Depends(get_classroom_token)):
try:
gc_service_test = get_service(token)
gc_api_test = ClassroomApi(service=gc_service_test)
user_profile = gc_api_test.get_user_profile("me")
response: responses.ListGoogleClassroomCourses = {
"message": f"Auth Credentials Are Valid",
"userProfile": user_profile,
}
return JSONResponse(response)
except errors.HttpError as error:
# handle exceptions...
Is there a way to specify the data structure of token.credentials like there is for request body?
This would make it easier to access properties as well as provide a format in the authorize modal on the swagger docs for other developers on the team, so they don't have to guess what the required properties of the Authorization token are.
This is my data model of the token.credentials as a BaseModel
class ClassroomAuthCredentials(BaseModel):
token: str = Field(..., example="MyJWT")
clientId: str = Field(..., example="myClientId")
clientSecret: str = Field(..., example="myClientSecret")
refreshToken: str = Field(..., example="myRefreshToken")
scopes: list[str] = Field(
...,
example=[
"https://www.googleapis.com/auth/classroom.courses.readonly",
"https://www.googleapis.com/auth/classroom.coursework.students",
],
)
I am using a nodemcu esp8266 and the plan is to make a spotify api request to automate playing some songs, and I have a fully functional python script that does exactly that, but when I tried to convert it to upython it failed. I have now spent hours on this and have figured out that the problem is that the urequest for some reason only works on specific websites, for example if I try:
import urequests as requests
x = requests.get('https://www.spotify.com')
print(x.status_code)
i get a 302
but when I try:
import urequests as requests
x = requests.get('https://www.google.com')
print(x.status_code)
I get a 200. That problem percists with a few websites and with no valid response my urequests.put command does not return the things I need... any ideas how to fix it?
thank you in advance.
this is the code I am trying to run:
import urequests as requests
import ujson as json
refresh_token = "xxxxx"
base_64 = "xxxxx"
class Refresh:
def __init__(self):
self.refresh_token = refresh_token
self.base_64 = base_64
def refresh(self):
query = "https://accounts.spotify.com/api/token"
payload={"grant_type": "refresh_token", "refresh_token": refresh_token}
headers={'Authorization': 'Basic %s' % base_64}
data = (json.dumps(payload)).encode()
response = requests.post(query,
data=data,
headers=headers)
print(response.status_code)
print(response.reason)
a = Refresh()
a.refresh()
There are several things going on here that are going to cause your problems.
First, you're trying to send JSON data to the /api/token endpoint:
data = (json.dumps(payload)).encode()
response = requests.post(query,
data=data,
headers=headers)
...but according to the documentation, this endpoint excepts application/x-www-form-urlencoded data.
Second, while the documentation suggests you need to send a basicAuthorization header, in my experiments this evening I wasn't able to get that to work...but I was able to successfully refresh a token if I included the client id and secret in the request body.
You can see my forum post with this question here.
With that in mind, the following code seems to work on my esp8266 running micropython 1.18:
import urequests as requests
refresh_token = "..."
client_id = "..."
client_secret = "..."
class Refresh:
def __init__(self, refresh_token, client_id, client_secret):
self.refresh_token = refresh_token
self.client_id = client_id
self.client_secret = client_secret
def refresh(self):
url = "https://accounts.spotify.com/api/token"
data = "&".join(
[
"grant_type=refresh_token",
f"refresh_token={self.refresh_token}",
f"client_id={self.client_id}",
f"client_secret={self.client_secret}",
]
)
headers = {
"content-type": "application/x-www-form-urlencoded",
}
response = requests.post(url, data=data, headers=headers)
print(data)
print(response.status_code)
print(response.reason)
print(response.text)
a = Refresh(refresh_token, client_id, client_secret)
a.refresh()
I have set up a read-only API key on Binance to access account information like currency balances but I can't see the JSON data. The string query I put into the URL returns the following error:
{"code":-2014,"msg":"API-key format invalid."}
The URL I am using is this: https://api.binance.com/api/v3/account?X-MBX-APIKEY=**key**&signature=**s-key**
The documentation for Binance API can be found here: https://www.binance.com/restapipub.html. What am I doing wrong ?
Binance's websocket API kinda tricky to use. Also there is no way to use a secret key.
Common usage
Send HTTP POST request with your secret API key as a X-MBX-APIKEY header to https://api.binance.com/api/v1/userDataStream
You will get listen key which should be used for websocket connection. It will be available 1 hour.
{"listenKey": "your listen key here"}
Use it when connecting to Binance's websocket
wss://stream.binance.com:9443/ws/{your listen key here}
Python example
import ssl
from websocket import create_connection
import requests
KEY = 'your-secret-key'
url = 'https://api.binance.com/api/v1/userDataStream'
listen_key = requests.post(url, headers={'X-MBX-APIKEY': KEY})['listenKey']
connection = create_connection('wss://stream.binance.com:9443/ws/{}'.format(KEY),
sslopt={'cert_reqs': ssl.CERT_NONE})
def get_listen_key_by_REST(binance_api_key):
url = 'https://api.binance.com/api/v1/userDataStream'
response = requests.post(url, headers={'X-MBX-APIKEY': binance_api_key}) # ['listenKey']
json = response.json()
return json['listenKey']
print(get_listen_key_by_REST(binance_api_key))
def get_all_orders(symbol, binance_api_key, binance_secret_key):
"""Get all account orders; active, canceled, or filled.
Args: symbol: Symbol name, e.g. `BTCUSDT`.
Returns:
"""
from datetime import datetime, timezone, timedelta
now = datetime.now(timezone.utc)
epoch = datetime(1970, 1, 1, tzinfo=timezone.utc) # use POSIX epoch
posix_timestamp_micros = (now - epoch) // timedelta(microseconds=1)
posix_timestamp_millis = posix_timestamp_micros // 1000 # or `/ 1e3` for float
import hmac, hashlib
queryString = "symbol=" + symbol + "×tamp=" + str(
posix_timestamp_millis)
signature = hmac.new(binance_secret_key.encode(), queryString.encode(), hashlib.sha256).hexdigest()
url = "https://api.binance.com/api/v3/allOrders"
url = url + f"?{queryString}&signature={signature}"
response = requests.get(url, headers={'X-MBX-APIKEY': binance_api_key})
return response.json()
You put it in the header. Following is tested working PHP example borrowed from jaggedsoft binance PHP library, it's a signed request that will return the account status.
$api_key = "cool_key";
$secret = "awesome_secret";
$opt = [
"http" => [
"method" => "GET",
"header" => "User-Agent: Mozilla/4.0 (compatible; PHP Binance API)\r\nX-MBX-APIKEY: {$api_key}\r\n"
]
];
$context = stream_context_create($opt);
$params['timestamp'] = number_format(microtime(true)*1000,0,'.','');
$query = http_build_query($params, '', '&');
$signature = hash_hmac('sha256', $query, $secret);
$endpoint = "https://api.binance.com/wapi/v3/accountStatus.html?{$query}&signature={$signature}";
$res = json_decode(file_get_contents($endpoint, false, $context), true);
X-MBX-APIKEY should be set as a field in the HTTP header, and not as a HTTP parameter. See this page for more information on HTTP header fields.
However, I tried the same with Excel and could not get it running until now.
Another open question is how to use the secret key.
This worked for me:
base_url="https://api.binance.com"
account_info="/api/v3/account"
url="${base_url}${account_info}"
apikey="your_apikey"
secret="your_secret"
queryString="timestamp=$(date +%s)" #$(python3 binance_time.py) must sync
requestBody=""
signature="$(echo -n "${queryString}${requestBody}" | openssl dgst -sha256 -hmac $secret)"
signature="$(echo $signature | cut -f2 -d" ")"
req=$(curl -H "X-MBX-APIKEY: $apikey" -X GET "$url?$queryString&signature=$signature")
echo $req
You should set the API key in the request header, not as a parameter in the request url. Please provide more information on your request procedure (language, etc.).
If you are based in USA - make sure to switch your base url to https://api.binance.us
_httpClient.DefaultRequestHeaders.Add("X-MBX-APIKEY", "apikey");
_httpClient.DefaultRequestHeaders.Add("SecretKey", "secretkey");
curl -H "X-MBX-APIKEY:your_api_key" -X POST https://api.binance.com/api/v1/userDataStream
i would like to know can you transfert some currencies from Kraken to Poloniex using API functions ?
Didn't see anything talking about that.
Thank a lot
*
create new API key with "Withdraw funds" right on kraken
Go to account settings then click on "api" to go to settings api page, then click on "generate new key"
Fill all field and tick the box "Withdraw Funds", then validate.
add the poloniex deposit address in kraken (assuming deposit address already created)
Go to funding deposit page
then click on "withdraw" to go to funding withdraw page
Select the currency on the left side
(here we assume that you want withdraw BTC)
so you have to click on "Bitcoin (XBT)" on the left panel
Then click on "add address" then
fill both "Description" & "Bitcoin address" field.
Write down "Description" field because it will be required later when you will send API request to withdraw from Kraken to Poloniex.
Create the API request which will be sent to Kraken
Use the following code (re-use this example python library):
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import time
import requests
import urllib
import urllib2
import json
import hashlib
import httplib
import hmac
import random
import string
import base64
def _query( urlpath, req = {}, conn = None, headers = {}):
"""Low-level query handling.
Arguments:
urlpath -- API URL path sans host (string, no default)
req -- additional API request parameters (default: {})
conn -- kraken.Connection object (default: None)
headers -- HTTPS headers (default: {})
"""
uri = 'https://api.kraken.com'
url = uri + urlpath
if conn is None:
conn = Connection()
ret = conn._request(url, req, headers)
return json.loads(ret)
def query_private( method, req={}, conn = None):
#secret data
key = "123456789_my_api_key"
secret = "123456798_my_api_secret"
apiversion='0'
uri='https://api.kraken.com'
urlpath = '/' + apiversion + '/private/' + method
req['nonce'] = int(1000*time.time())
postdata = urllib.urlencode(req)
message = urlpath + hashlib.sha256(str(req['nonce']) +
postdata).digest()
signature = hmac.new(base64.b64decode(secret),
message, hashlib.sha512)
headers = {
'API-Key': key,
'API-Sign': base64.b64encode(signature.digest())
}
return _query(urlpath, req, conn, headers)
withdraw_params={
'asset': 'xbt',
'key': "Withdrawal address Description",
'amount': 0.25,
}
res=query_private('Withdraw', withdraw_params)
You'll need the withdrawFunds method from the Kraken API (https://www.kraken.com/help/api#withdraw-funds).
Using the Poloniex API, you'll need to get your deposit address using returnDepositAddresses. If you don't have a deposit address for the given cryptocurrency, use generateNewAddress.
Kraken API Documentation: https://www.kraken.com/help/api
Poloniex API Documentation: https://poloniex.com/support/api/
I am developing mobile apps using rhodes. I want to access private repo of github. I am having only username and password.
How to get token of given username and password.
Once you have only login and password you can use them using basic auth. First of all, check if this code shows you json data of desired repo. Username and password must be separated by a colon.
curl -u "user:pwd" https://api.github.com/repos/user/repo
If succeeded you should consider doing this request from code.
import urllib2
import json
from StringIO import StringIO
import base64
username = "user#example.com"
password = "naked_password"
req = urllib2.Request("https://api.github.com/repos/user/repo")
req.add_header("Authorization", "Basic " + base64.urlsafe_b64encode("%s:%s" % (username, password)))
req.add_header("Content-Type", "application/json")
req.add_header("Accept", "application/json")
res = urllib2.urlopen(req)
data = res.read()
repository = json.load(StringIO(data))
You should use oauth instead: http://developer.github.com/v3/oauth/
Github users can create Personal Access Tokens at their application settings. You can use this token as an alternative to username/password in basic http authentication to call the API or to access private repositories on the github website.
Simply use a client that supports basic http authentication. Set the username equal to the token, and the password equal to x-oauth-basic. For example with curl:
curl -u <token>:x-oauth-basic https://api.github.com/user
See also https://developer.github.com/v3/auth/.
Send A POST request to /authorizations
With headers
Content-Type: application/json
Accept: application/json
Authorization: Basic base64encode(<username>:<password>)
But remember to take Two factor Authentication in mind
https://developer.github.com/v3/auth/#working-with-two-factor-authentication
Here You will receive a token which can be used for further request
Follow this guide at help.github.com. It describes how to find your api-token (it's under "Account Settings" > "Account Admin") and configuring git so it uses the token.
Here is the code to use GitHub Basic Authentication in JavaScript
let username = "*******";
let password = "******";
let auth = "Basic " + new Buffer(username + ":" + password).toString("base64");
var options = {
host: 'api.github.com',
path: '/search/repositories?q=google%20maps%20api',
method: 'GET',
headers: {
'user-agent': 'node.js',
"Authorization": auth
}
};
var request = https.request(options, function (res) {
}));