I have the following code and I also read the post from Bittrex. My nonce and apikey are used for HMAC calculation, but I receive the APISIGN_NOT_PROVIDED error.
For this version, we use a standard HMAC-SHA512 signing. Append apikey
and nonce to your request and calculate the HMAC hash and include it
under an apisign header. Note: the nonce is not respected right now
but will be enforced later.
if true
% code
url_base = 'https://bittrex.com/api/v1.1/market/getopenorders';
body = [url_base,'?apikey=',apikey,'&nonce=',nonce];
sign = hmac(secret_key, body, 'SHA-512');
json = urlread( body, 'Get', {'apisign', sign} )
end
Since urlread is not recommended anymore (reference here), just for the sake of curiosity, try the currently recommended alternative webread:
url_base = 'https://bittrex.com/api/v1.1/market/getopenorders/';
url_full = [url_base '?apikey=' apikey '&nonce=' nonce];
sign = hmac(secret_key,url_full,'SHA-512');
opt = weboptions('ContentType','json','HeaderFields',{'apisign' sign},'RequestMethod','get');
json = webread(url_full,opt);
Also, don't forget to put a breakpoint in your code and check how sign looks like, just to be sure you are forwarding properly formatted data in your HTTPS request headers.
Related
I wanted to know how I can validate HTTP messages with JWS Detached. Currently, I am receiving x-sign-jws request in header which looks like below
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..UXwjHxU3tFlrzPMupG04zROiEcHFQpCg3l7J4Axr1fE
I need to verify this at my end whether the request is right or not using my secrete Key
Ex: 12345678
I am using firebase/jwt and tried below code
$hed = getallheaders();
$recievedJwt = $hed["X-Sign-Jws"];
$decoded = JWT::decode($recievedJwt, $secret_key, array('JWT','HS256'));```
but I am not getting any result.
I searched on net I found the article which mentioned below steps:
Validation HTTP message with JWS Detached:
a) Get the HTTP header "x-sign-jws",
b) Get BASE64URL HTTP body
c) Put generate string b) into the Payload section
d) Validate JWS
But I am confused with how to get Base64URL HTTP body
Any help would be greatly appreciated since there are only a few articles available on this topic.
JWS format is base64url(header).base64url(payload).base64url(signature), note the dot delimiter between 3 components.
Detached JWS still contains 3 components but the payload is removed and provided elsewhere, usually the payload is provided in the HTTP Body.
To verify detached JWS, you need to add base64url encoded payload to the detached JWS. The payload is available from your HTTP Body.
For example;
x-sign-jws = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..UXwjHxU3tFlrzPMupG04zROiEcHFQpCg3l7J4Axr1fE
//split x-sign-jws into array using delimiter .
x-sign-jws-attached = x-sign-jws-split[0] + '.' + base64Url(HTTPRequest.Body) + '.' + x-sign-jws-split[1]
Now you can verify x-sign-jws-attached as shown below;
$decoded = JWT::decode($x-sign-jws-attached, $secret_key, array('JWT','HS256'));```
I am using Akka Http to handle the redirection of a signed url for a text resource stored in GCS (Google Cloud Storage). Basically I have some files in GCS that I want to deliver with my API when requested. Unfortunately, the path to this resource has a subdirectory with a = character in it, something like: https://storage.googleapis.com/path_start/more_path/format=avro/still_more_path/filename.avro.
Google storage's signUrl method percent encodes this = character as %3D in the signed url. I have verified that using this signed url allows access to the files in GCS (hitting it starts a download). The problem is when Akka Http redirects this signed url on request, it decodes it back to the equals sign. This results in a SignatureDoesNotMatch error from GCS:
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message>
I attempt to generate the signed url and redirect it in the following code snippet:
val signedUrl = cloudStorageService.getSignedUrl(bucketId, filePath)
logger.info(s"signedUrl: $signedUrl")
redirect(signedUrl, TemporaryRedirect)
and my cloudStorageService.getSignedUrl method is defined separately here:
def getSignedUrl(bucket: String, path: String, expiration: Option[Int] = None): String = {
val maxLifetime = 60 * 60 * 24 * 7
val lifetime = expiration.getOrElse(maxLifetime)
val cappedExpiration = Math.min(lifetime, maxLifetime)
val blobInfo = BlobInfo.newBuilder(BlobId.of(bucket, path)).build
storage.signUrl(blobInfo, cappedExpiration, TimeUnit.SECONDS, Storage.SignUrlOption.withV4Signature).toString
}
The logging statement in the first snippet shows me that the signed URL is generated with the %3D, but the redirected URL has been percent decoded back to =, resulting in the SignatureDoesNotMatch error.
This behavior is standard for Akka Http. According to the documentation for Uri class, all members represent percent decoded elements. There is an option to construct the uri with a raw query string, but in my case the encoded character happens in the uri path itself, not the query.
So my question is, is there any way to get Akka Http to redirect this signed url without percent decoding the path? Or am I mistaken, and there's another way to approach this problem?
You might want to create the redirect response 'manually' instead of using the 'redirect' directive. The directive implementation is:
HttpResponse(
status = redirectionType,
headers = headers.Location(uri) :: Nil,
entity = redirectionType.htmlTemplate match {
case "" => HttpEntity.Empty
case template => HttpEntity(ContentTypes.`text/html(UTF-8)`, template format uri)
}
Instead of headers.Location(uri) you could introduce your own RawHeader to build up a Location header. You can probably leave the entity empty in your scenario.
(relevant documentation: https://doc.akka.io//docs/akka-http/current/routing-dsl/directives/route-directives/redirect.html)
I am trying to get a little bit familiar with this REST API:
https://docs.gemini.com/rest-api/#private-api-invocation
However, I am trying to figure out how they do authentication, and it seems they don't use OAuth. This is what they say:
Gemini uses API keys to allow access to private APIs. You can obtain these by logging on and creating a key in Settings/API. This will give you both an "API Key" that will serve as your user name, and an "API Secret" that you will use to sign messages.
All requests must contain a nonce, a number that will never be repeated and must increase between requests. This is to prevent an attacker who has captured a previous request from simply replaying that request. We recommend using a timestamp at millisecond or higher precision. The nonce need only be increasing with respect to the session that the message is on.
Now, I don't understand where to place my API Secret key. They don't really specify a parameter name for it. Same thing goes for the nonce. Also, does the nonce need to be randomized? And what size should the nonce be? I am not that familiar with this.
As described in the docs you linked you need to base64-encode the "request", "nonce" and "order_id" for the X_GEMINI_PAYLOAD header and SHA384 that payload with the API Secret for the X-GEMINI-SIGNATURE header.
Here's an example from the site (Python):
import requests
import base64
import hmac
from hashlib import sha384
url = "https://api.gemini.com/v1/order/status"
gemini_api_key = "mykey"
gemini_api_secret = "1234abcd"
# for the purposes of this example, we've shown hand-rolled JSON - please import json and use json.dumps in your real code!
b64 = base64.b64encode("""{
"request": "/v1/order/status",
"nonce": 123456,
"order_id": 18834
}
""")
signature = hmac.new("1234abcd", b64, hashlib.sha384).hexdigest()
headers = {
'Content-Type': "text/plain",
'Content-Length': "0",
'X-GEMINI-APIKEY': gemini_api_key,
'X-GEMINI-PAYLOAD': b64,
'X-GEMINI-SIGNATURE': signature,
'Cache-Control': "no-cache"
}
response = requests.request("POST", url, headers=headers)
print(response.text)
I'm computing the HMAC of the HTTP body request in this way:
payload = {"name":"myvm","os":"gentoo","resources":{"vCPU":"4","RAM":"512","Disk":"1000"},"actions":["start"]}
key = "supersecretkey"
secret = bytes(key, encoding='utf-8')
msg = json.dumps(payload, sort_keys=True)
message = bytes(msg, encoding='utf-8')
print(hmac.new(secret, message, sha1).hexdigest())
After that I encode with b64 the hexdigest and send it with curl like the docs says Authorization: paolo:$hmac_base64_encoded
The problem is that I always get a 500 error. What am I doing wrong?
Since you are using Python 3x make sure that in your custom HMACAuth you are converting to bytes (the code snippet from the official documentation is for Python 2x).
When am trying to request token for tripit oauth, I got the error invalid signature.
My url is:
https://api.tripit.com/oauth/request_token?oauth_consumer_key=c5676701706473430d016ac7dc58a0149333349e&oauth_consumer_secret=90b7567665605fad847815949ce414f7078742d5&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1304072442&oauth_nonce=kllo9940pd9333jh&oauth_version=1.0
Please help me, where I am wrong ???
https://api.tripit.com/oauth/request_token?
oauth_consumer_key = c5676701706473430d016ac7dc58a0149333349e&
oauth_consumer_secret = 90b7567665605fad847815949ce414f7078742d5&
oauth_signature_method = HMAC-SHA1&
oauth_timestamp = 1304072442&
oauth_nonce = kllo9940pd9333jh&
oauth_version = 1.0
I guess you are in the Temporary Credentials step. This looks all kinds of wrong. You shouldn't send oauth_consumer_secret which is not even a spec parameter, you are not sending a oauth_callback, you are not sending an oauth_signature, and you are sending a GET instead a POST (or at least you are not providing your POST data, which you can get from Safari or Firefox+Firebug/liveHttpHeaders), which unless the server says otherwise (which could be the case, I don't know) is wrong. Anyway, the answer is in the RFC, which I spent a few days reading and now it's fading from my memory.
You should try to use a library, or re-read rfc5849.
Only if you want to understand OAuth, I suggest you read my oauth client: https://github.com/j4n0/oauth because it is an implementation easy to follow.