How to make an authenticated call to Google Cloud Endpoint? - authentication

I've set up a simple, standard environment Google App Engine project which uses Cloud Endpoints by going through the steps in the tutorial here:
https://cloud.google.com/endpoints/docs/frameworks/python/get-started-frameworks-python
This works great - I can make a curl call to the echo endpoint and get the expected result.
However, I can't successfully call the authenticated endpoint.
I'm following the steps here: https://cloud.google.com/endpoints/docs/frameworks/python/javascript-client and, while I can successfully sign in, when I send my sample authenticated request I get a 401 Unauthorized HTTP response.
From the log on the server I see :
Client ID is not allowed: <my client id>.apps.googleusercontent.com (/base/data/home/apps/m~bfg-data-analytics/20190106t144214.415219868228932029/lib/endpoints/users_id_token.py:508)
So far I've checked:
The web app is using the correct version of the cloud endpoints config.
The client ID in the endpoint config (x-google-audiences) matches the
client ID that the javascript web app is posting.
Any ideas on how to fix this?

Using the example code to set up the end point in:
https://cloud.google.com/endpoints/docs/frameworks/python/create_api
and
https://cloud.google.com/endpoints/docs/frameworks/python/service-account-authentication
And modifying the python code for generating a token from :
https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/endpoints/getting-started/clients/service_to_service_google_id_token
I've got it working.
Here's the server endpoint code:
import endpoints
from endpoints import message_types
from endpoints import messages
from endpoints import remote
class EchoRequest(messages.Message):
message = messages.StringField(1)
class EchoResponse(messages.Message):
"""A proto Message that contains a simple string field."""
message = messages.StringField(1)
ECHO_RESOURCE = endpoints.ResourceContainer(
EchoRequest,
n=messages.IntegerField(2, default=1))
#endpoints.api(
name='echo',
version='v1',
issuers={'serviceAccount': endpoints.Issuer(
'MY-PROJECT#appspot.gserviceaccount.com',
'https://www.googleapis.com/robot/v1/metadata/x509/MY-PROJECT#appspot.gserviceaccount.com')},
audiences={'serviceAccount': ['MY-PROJECT#appspot.gserviceaccount.com']})
class EchoApi(remote.Service):
# Authenticated POST API
# curl -H "Authorization: Bearer $token --request POST --header "Content-Type: applicationjson" --data '{"message":"echo"}' https://MY-PROJECT#appspot.com/_ah/api/echo/v1/echo?n=5
#endpoints.method(
# This method takes a ResourceContainer defined above.
ECHO_RESOURCE,
# This method returns an Echo message.
EchoResponse,
path='echo',
http_method='POST',
name='echo')
def echo(self, request):
print "getting current user"
user = endpoints.get_current_user()
print user
# if user == none return 401 unauthorized
if not user:
raise endpoints.UnauthorizedException
# Create an output message including the user's email
output_message = ' '.join([request.message] * request.n) + ' ' + user.email()
return EchoResponse(message=output_message)
api = endpoints.api_server([EchoApi])
And the code to generate a valid token
import base64
import json
import time
import google
import google.auth
from google.auth import jwt
def generate_token(audience, json_keyfile, client_id, service_account_email):
signer = google.auth.crypt.RSASigner.from_service_account_file(json_keyfile)
now = int(time.time())
expires = now + 3600 # One hour in seconds
payload = {
'iat': now,
'exp': expires,
'aud' : audience,
'iss': service_account_email,
'sub': client_id,
'email' : service_account_email
}
jwt = google.auth.jwt.encode(signer, payload)
return jwt
token = generate_token(
audience="MY-PROJECT#appspot.gserviceaccount.com", # must match x-google-audiences
json_keyfile="./key-file-for-service-account.json",
client_id="xxxxxxxxxxxxxxxxxxxxx", # client_id from key file
service_account_email="MY-PROJECT#appspot.gserviceaccount.com")
print token
Make an authenticated call with curl
export token=`python main.py`
curl -H "Authorization: Bearer $token" --request POST --header "Content-Type: application/json" --data '{"message":"secure"}' https://MY-PROJECT.appspot.com/_ah/api/echo/v1/echo?n=5

Related

how to generate auth 2.0 in karate I saw a sample in karate Demo project but in our case we need to send it as "Authorization Code"

How to generate OAuth 2.0 token via karate.
How we have tried in Postman:
On Authorization tab select OAuth 2.0
Select Header Prefix Bearer
Grant-Type is "Authorization Code"
Callback URL is selected as when we will click submit it redirects to a browser where we have to enter credentials and a user is validated once it is validated the browser redirects back to Postman
Add "Auth URL" and "Access Token URL"
Enter "Client ID" and "Client Secret"
Select "Client Authentication" as Send as Basic Auth Header.
Postman then redirects to a browser where we enter username and password and once authenticated it redirects user back to postman with access token.
Question:
When we provide grant_type as "authorization code" in Karate we are getting an error as {"error":"unsupported_grant_type","error_description":"Unsupported grant_type"}. What to provide here as when we provide "password" we are getting 401 and when we provide "authorization code" we are getting 400.
Secondly, Can we automate such scenario where a browser is invoked as well and we have to enter credentials can we achieve it via Karate as then we have to store the token and pass in the APIs?
Background:
* url 'http://localhost:8080/pathdetails'
Scenario: get all users and then get the first user by id
* path 'token'
* form field grant_type = 'authorization code'
* form field client_id = 'ourapiclient'
* form field client_secret = '324243324-3334-334-343-3432423424'
* method post
* status 200
* def accessToken = response.access_token
EDITED**********
I have now tried to send a API request to Auth URL which redirects to the browser and returns HTML page.
Given url 'http://localhost:8080/myurlpath/auth'
* form field response_type = 'code'
* form field client_id = 'abcc'
* form field scope = 'openconnect'
* form field redirect_uri = 'http://localhost:8080/redirecturlpath'
* form field state = 'cEY3R-YfsoM9232diS72COdHTA8uPv9K49pjZaPag5M.8akinzwobn8.abcd4'
* method get
* status 200
* print 'Response is........',response
This returned an HTML page which is exactly the same page I see when I send request from Postman. How to now enter username and password in karate on this html page as this page was returned as part of the response of above API.
I was expecting above will return me a code and after that I will call the request token endpoint but above redirected me to where I enter username and password and then once it is successful it redirects back to Postman and in URL I can see the code as well.
curl --request POST \
--url 'https://YOUR_DOMAIN/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=authorization_code \
--data 'client_id=YOUR_CLIENT_ID' \
--data client_secret=YOUR_CLIENT_SECRET \
--data code=YOUR_AUTHORIZATION_CODE \
--data 'redirect_uri=https://YOUR_APP/callback'
How to get the code which is needed by the token API?
I tried sending Auth API to access like below but no code or token got returned in the response.
Given driver 'http://localhost:8080/myurlpath/auth?scope=openconnect&state=cEY3R-YfsoM9232diS72COdHTA8uPv9K49pjZaPag5M.8akinzwobn8.abcd4&response_type=code&client_id=abcc&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fauth%2Fmyurlpath'
* fullscreen()
And input('#username', 'username')
And input('#password', 'password')
When click('#login')
The above doesn't return any error but it doesn't return the code I am looking for as well
#Maddy To see grant types You need access to auth0, or ask your devs to tell You what grants are implemented here you can read more:
https://auth0.com/docs/configure/applications/application-grant-types
And here You can read how to implement autorization-code flow:
https://auth0.com/docs/login/authentication/add-login-auth-code-flow
To make Your life easier You could ask devs to implement Password-realm-grant but this is not recommended.
Here is how rectify one of oAuth 2.0 token generation
* def cid = 'client_id'
* def csec = 'token_secret'
* def AuthCode = Java.type('com.test.qa.aut.authCode')
* print AuthCode.Code()
* def authentication = 'Basic ' + AuthCode.Code(cid, csec)
* print authentication
* url 'https://acpint.online.com/default/np/oauth2/'
* header Authorization = authentication
And header Content-Type = 'application/x-www-form-urlencoded; charset=utf-8'
* form field grant_type = 'client_credentials'
Then method post
And status 200
Then print response
Java class:
package com.test.qa.aut;
import java.util.Base64;
public class authCode {
public static String Code(String clientId, String clientSecret) {
String auth = clientId + ":" + clientSecret;
String authentication = Base64.getEncoder().encodeToString(auth.getBytes());
return authentication;
}
}

Cannot POST request using service account key file in Python, getting 'Invalid IAP credentials: Unable to parse JWT', '401 Status Code'

I am trying to send a POST request to a Google App Engine service with a JSON body accompanied by an authorization token. I am generating the access token from a local service account key JSON file. The code below is generating a credential but finally the authorization is being rejected. I also tried different ways already. Even tried writing the request in Postman with a Bearer token in the Header, or even as a plain cURL command. But whatever I try, getting a 401 authentication error. I need to make sure whether the problem is in my side or on the other side with the service. Explored every documentation avaliable but no luck.
from google.auth.transport import requests
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
CREDENTIAL_SCOPES = ["https://www.googleapis.com/auth/cloud-platform"]
CREDENTIALS_KEY_PATH = 'my-local-service-account-key-file.json'
#the example service url I am trying to hit with requests
url = 'https://test.appspot.com/submit'
headers = {"Content-Type": "application/json"}
#example data I am sending with the request body
payload = {
"key1": "value 1",
"key2": "value 2"
}
credentials = service_account.Credentials.from_service_account_file(
CREDENTIALS_KEY_PATH,
scopes=CREDENTIAL_SCOPES
)
credentials.refresh(requests.Request())
authed_session = AuthorizedSession(credentials)
response = authed_session.request('POST',
url,
headers=headers,
data=payload
)
#adding some debug lines for your help
print(response.text)
print(response.status_code)
print(response.headers)
Getting the Output:
Invalid IAP credentials: Unable to parse JWT
401
{'X-Goog-IAP-Generated-Response': 'true', 'Date': 'Mon, 03 May 2021 06:52:11 GMT', 'Content-Type': 'text/html', 'Server': 'Google Frontend', 'Content-Length': '44', 'Alt-Svc': 'h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"'}
IAP expects a JWT(OpenID Connect (OIDC)) token in the Authorization header while your method will attach an access token the the Authorization header instead. Take a look at the below code snippet to make a request to an IAP secured resource.
Your code needs to be something like the following:
from google.auth.transport.requests import Request
from google.oauth2 import id_token
import requests
def make_iap_request(url, client_id, method='GET', **kwargs):
"""Makes a request to an application protected by Identity-Aware Proxy.
Args:
url: The Identity-Aware Proxy-protected URL to fetch.
client_id: The client ID used by Identity-Aware Proxy.
method: The request method to use
('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
**kwargs: Any of the parameters defined for the request function:
https://github.com/requests/requests/blob/master/requests/api.py
If no timeout is provided, it is set to 90 by default.
Returns:
The page body, or raises an exception if the page couldn't be retrieved.
"""
# Set the default timeout, if missing
if 'timeout' not in kwargs:
kwargs['timeout'] = 90
# Obtain an OpenID Connect (OIDC) token from metadata server or using service
# account.
open_id_connect_token = id_token.fetch_id_token(Request(), client_id)
# Fetch the Identity-Aware Proxy-protected URL, including an
# Authorization header containing "Bearer " followed by a
# Google-issued OpenID Connect token for the service account.
resp = requests.request(
method, url,
headers={'Authorization': 'Bearer {}'.format(
open_id_connect_token)}, **kwargs)
if resp.status_code == 403:
raise Exception('Service account does not have permission to '
'access the IAP-protected application.')
elif resp.status_code != 200:
raise Exception(
'Bad response from application: {!r} / {!r} / {!r}'.format(
resp.status_code, resp.headers, resp.text))
else:
return resp.text
Note: The above method works with implicit credentials that can be set by running command: export GOOGLE_APPLICATION_CREDENTIALS=my-local-service-account-key-file.json to set the path to your service account in the environment and then run the python code from the same terminal.
Take a look at this link for more info.

Refreshing JWT in Flask returns "Only access tokens are allowed"

I have a strange problem with refreshing JWT token that I can't seem to find a solution for online.
My simple method for login:
#app.route("/api/login", methods=['POST'])
def app_login():
json = request.json
form = AppLoginForm.from_json(json)
password = json.get('password')
mobile = cleanup(json.get('mobile'))
user_found = User.query.filter(and_(User.mobile == mobile, or_(User.user_type == UserType.dashboard_user.value, User.user_type == UserType.end_user.value, User.user_type == UserType.dashboard_and_end_user.value))).first()
if user_found: #found
if bc.check_password_hash(user_found.password, password):
access_token = create_access_token(identity=user_found.mobile)
refresh_token = create_refresh_token(identity=user_found.mobile)
return send_response(True, None, { "access_token":access_token,"refresh_token":refresh_token }, 200)
else:
return send_response(False,[messages.WRONG_PASS], None, 406, {"case": UserLoginMeta.wrong_password.value})
My simple method for refreshing the JWT token:
#app.route('/api/refresh', methods=['POST'])
#jwt_refresh_token_required
def refresh_token():
''' refresh token endpoint '''
current_user = get_jwt_identity()
return send_response(True,None, [{ "access_token":create_access_token(identity=current_user)}])
Calling it the normal way with refresh token fails, and calling it with access token also fails:
Sending access token -> gives {"msg":"Only refresh tokens are allowed"}
curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTAzNDczNDksIm5iZiI6MTYxMDM0NzM0OSwianRpIjoiODk4YjU1YmQtZjQzOS00OTE4LTkzZWQtN2UwMDNlZmEyM2M0IiwiZXhwIjoxNjEwNzc5MzQ5LCJpZGVudGl0eSI6Ijk2NjU0MTgyMjY3OSIsImZyZXNoIjpmYWxzZSwidHlwZSI6ImFjY2VzcyIsInVzZXJfY2xhaW1zIjp7ImlkZW50aXR5IjoiOTY2NTQxODIyNjc5IiwiZGV2aWNlIjp7ImlkIjoxMDk3NCwiSU1FSTEiOiIzNTI3MTQ0ODAxMjU2NzMiLCJJTUVJMiI6IjM1MjcxNDQ4MDE3NzY3NCIsInVuaXF1ZV9kZXZpY2VfaWQiOiJEZXNlcnQyMDAwMDAwMTY2In0sIndhcnJhbnR5Ijp7ImlkIjoyNjgsInNlcmlhbF9udW1iZXIiOiJXLTI3MzciLCJzdGF0dXMiOjIsInN0YXR1c190ZXh0IjoiQWN0aXZlIiwiZXhwaXJ5X2RhdGUiOiIyMDIzLzAxLzA2IiwibW9udGhzX2xlZnQiOjI0LCJkYXlzX2xlZnQiOjV9LCJhem9tX2NhcmUiOm51bGwsInVzZXIiOnsiaWQiOjM5OSwibW9iaWxlIjoiOTY2NTQxODIyNjc5IiwiZW1haWwiOiJhLm5hd2FmQGF6b210ZWNoLmNvbSIsImZpcnN0X25hbWUiOiJBYmVlciIsImxhc3RfbmFtZSI6Ik5hd2FmIn19fQ.PkFwQfIwStFkt3pCkZK919H203rDpLOD-96kcNEcRHw" -X POST http://localhost:5000/api/refresh
Sending refresh token -> gives {"msg":"Only access tokens are allowed"}
curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTAzNDczNDksIm5iZiI6MTYxMDM0NzM0OSwianRpIjoiNDQxNzViNDYtNDZmZi00ZDUxLThmYzQtZTYwNjY4ZDlmNTU1IiwiZXhwIjoxNjEyOTM5MzQ5LCJpZGVudGl0eSI6Ijk2NjU0MTgyMjY3OSIsInR5cGUiOiJyZWZyZXNoIn0.VdevyrbAJL78TwNrPIPlWnyiB3swCtbg9cLwCMvmU8w" -X POST http://localhost:5000/api/refresh
Why is that??
I found the cause.
I have implemented a handler method on #app.before_request and my logic was broken and it has overridden the normal behavior of refresh token.
After I removed it, it worked Ok

What Bearer token should I be using for Firebase Cloud Messaging testing?

I am trying to send a test notification using Firebase Cloud Messaging via Postman. I'm doing a POST to this url
https://fcm.googleapis.com/v1/projects/[my project name]/messages:send
The Authorization tab in Postman is set to No Auth and my Headers tab looks like this
Content-Type: application/json
Authorization: Bearer [server key]
[server key] is a newly generated server key in the 'Cloud Messaging' tab of my Firebase project's 'Settings' area. I keep getting this error in response.
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
Based on everything I can find, I'm using the right token, but it seems Google disagrees. What should I be sending as the Authorization header to get past this error?
Steps to get Authentication Bearer:
Got to Google OAuth Playground: https://developers.google.com/oauthplayground
In the "Input your own scopes" for FCM use this url: https://www.googleapis.com/auth/firebase.messaging
Tap Authorize API.
Pick correct user for authorisation and allow access.
In the Step 2: Exchange authorization code for tokens tap Exchange authorisation code for tokens.
Access token is your Bearer.
Steps to send FCM using Postman:
URL to send: https://fcm.googleapis.com/v1/projects/projectid-34543/messages:send
Request Type: POST
Headers: Content-Type -> application/json & Authorization -> Bearer
In the body section enter APS payload with the right device token.
Click send.
In case you want to use cURL, for a data-notification:
curl --location --request POST 'https://fcm.googleapis.com/v1/projects/your-project-id/messages:send' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer your-access-token-*****-wqewe' \
--data-raw '{
"message": {
"token": "device-token-qwfqwee-***-qefwe",
"data": {
"Key1": "val1",
"Key2": "val2"
}
}
}'
You have to generate new access token in Postman.
First, ensure you have enabled FCM API in Google Developer Console.
Than go to Google Developer Console -> APIs & Services -> Credentials. Look at "OAuth 2.0 client IDs" section. There should be at least one item in list. Download it as json file.
In Postman open "Authorization" tab, select Type = "OAuth 2.0" than click "Get New Access Token". Dialog appears.
Fields:
Token Name - type what you want
Grant Type = Authorization Code
Callback URL = redirect_uris from downloaded json
Auth URL = auth_uri
Access Token URL = token_uri
Client ID = client_id
Client Secret = client_secret
Scope = "https://www.googleapis.com/auth/firebase.messaging"
State - leave empty
Client Authentication = default, Send As Basic Auth Header
Click "Request Token" and that's it.
The Bearer Token is the result of getting an OAuth access token with your firebase service account.
Get yourself a Firebase service account key.
Go to your firebase console > Settings > Service Accounts.
If your on Firebase Admin SDK generate new private key.
You use the service account key to authenticate yourself and get the bearer token.
Follow how to do that in Node, Python or Java here:
https://firebase.google.com/docs/cloud-messaging/auth-server.
So in Java you can get the token like this:
private static final String SCOPES = "https://www.googleapis.com/auth/firebase.messaging";
public static void main(String[] args) throws IOException {
System.out.println(getAccessToken());
}
private static String getAccessToken() throws IOException {
GoogleCredential googleCredential = GoogleCredential
.fromStream(new FileInputStream("service-account.json"))
.createScoped(Arrays.asList(SCOPES));
googleCredential.refreshToken();
return googleCredential.getAccessToken();
}
And now you can finally send your test notification with FCM.
Postman code:
POST /v1/projects/[projectId]/messages:send HTTP/1.1
Host: fcm.googleapis.com
Content-Type: application/json
Authorization: Bearer access_token_you_just_got
{
"message":{
"token" : "token_from_firebase.messaging().getToken()_inside_browser",
"notification" : {
"body" : "This is an FCM notification message!",
"title" : "FCM Message"
}
}
}
To generate an for testing push notification, you can use Google Developers OAuth 2.0 Playground
You can even send a test Push Notification using Google Developers OAuth 2.0 Playground itself.
Or if you want can use Postman / Terminal (curl command) as well.
Please find the detailed steps here, which I wrote.
Note : Instead of "Project name" in the Endpoint, you have to use "Project ID". Steps for getting the Project ID is also mentioned in the above link.
You should use definitely use Google-OAuth2.0, which can be generated using described steps in the provided link.
you can find detailed steps here, which I answered for similar question.

Binance API Keys

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 + "&timestamp=" + 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