Authenticating into a REST API in parameters - rest

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)

Related

"Missing Authentication Token" Error when calling DVLA MOT history API with Postman

Note - I am very much new to all this. Apologies if anything is unclear.
My overriding aim is to pull out MOT history data for a large batch of vehicles from the DVLA API. I understand that this can be done using Postman, which I am using (on a 64-bit Windows laptop if at all relevant).
The DVLA provide the following instructions
====================================================
Getting started
All API interfaces are implemented as restful APIs and accessed over https.
To access API you will need an API key that uniquely identifies the source of the request. DVSA will give you an API key if it approves your application.
You should keep your API key secure, as DVSA manages throttling and quotas at an API key level.
Each request must have the following mandatory fields in the header:
Accept: application/json+v6
x-api-key:
Content-type field confirms that the response type is in JSON format, and the x-api-key field serves your API key to identify the source of the request.
Technical resources
Access the API at https://beta.check-mot.service.gov.uk/
This root URL will change when the service moves from beta to live.
These 4 endpoints equate to the 4 methods of using the API:
/trade/vehicles/mot-tests?registration={registration}
‘Registration’ is the vehicle registration number.
===================================================
In order to test that this is possible, I am entering the following single request into the bar in Postman, selecting "POST" and hitting "SEND"
https://beta.check-mot.service.gov.uk/trade/vehicles/mot-tests?Content-type=application/json&x-api-key=ABCDEFGH&registration=MYREG
n.b. no inverted commas or other punctuation surrounds the actual values for ABCDEFH or MYREG
Expected result: Some sort of JSON with MOT history for this vehicle
Actual result: {"message": "Missing Authentication Token"}{"message": "Missing Authentication Token"}
I am unclear on:
- whether I should be using POST
what the +v6 after the application is necessary (other documentation leaves it out)
Why "Accept" and "Content-type" appear to be used interchangeably in the documentation
Whether the ordering of the parameters matters
Whether this can be equally tested by simply pasting the url into a browser
Thanks for any help
Reading through the Documentation found here:
https://dvsa.github.io/mot-history-api-documentation/
It mentions that those fields should be added as Headers:
Each request must have the following mandatory fields in
the header:
- Accept: application/json+v6
- x-api-key: <your api key>
There are example cURL requests on the site to help you with creating the request.
If you use Postman's Import feature within the app (found in the top right), you can add this cURL request in the Paste Raw Text tab.
curl -H "Accept: application/json+v6" -H "x-api-key: <your_api_key>" https://beta.check-mot.service.gov.uk/trade/vehicles/mot-tests\?registration=ZZ99ABC
This will give you an example request of what it should look like. From here, you will be able to add in your own API Token and send the request.
If you are using Postman, you can use the Authorization tab right under the request to give the required mandatory header fields. Select Header from Add to drop down. You can also add additional headers information using the next tab named Headers. (for example, the accept-headers).
Edit:
Authorization:
Headers Tab
Normally, you should be getting the authorization token when you register to the site in question(x-api-key here).You need to figure out the value of that token from the initial call's response headers. According to the document which Danny shared, you will be getting x-api-key from them once they approve your request.
Edit:
Alternatively, you can use import feature as Danny suggested in his answer. At the end of the day, you need to add the values as headers instead of query parameters.
For anyone using Python with the MOT history api and getting the same error message, try GET:
import requests
url = f'https://beta.check-mot.service.gov.uk/trade/vehicles/mot-tests?registration={plate_number}'
payload = {}
headers = {
'Accept': 'application/json+v6',
'x-api-key': 'your-api-key'}
response = requests.get(url, headers=headers, data=payload)
data = response.json()
model = data[0]['model'] # get the vehicle model for example
print(model)

Generate API signature in request header from parameters in the request body

I'm using OWASP ZAP to test our API. We have a couple of POST endpoints which use an API Token and a shared secret for authentication and validating the request.
Some parameters of the request body are concatenated and hashed using the shared secret. This value is inserted into the request header.
How can I programatically generate this signature using OWASP ZAP?
Request Header
Content-Type: "application/json"
Accept: "application/json"
API-Key: {API_KEY}
Signature: {hash(field_one + field_two + field_three + SHARED_SECRET)}
Request Body
{
"field_one": "abc",
"field_two": "123",
"field_three": "xyz"
}
The SHARED_SECRET is the password that is stored locally by the client and used to hash the three fields from the request.
It is stored on the server along with the API-Key so that requests can be identified and validated.
Use an HTTP Sender Script. Create it in the ZAP UI so that you can test it as you're writing it. First make sure you are just detecting the requests you want to change, then extract the field values you need and finally generate the hash. Keep testing at each stage to make sure its doing what you need. And if you need specific help theres always the zaproxy-scripts group.

Use matlab connunicate to bittrex api error (APISIGN_NOT_PROVIDED)

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.

Twitter Oauth possible cause for 400 Bad Request response using a simple REST client

I've generated Access Tokens in the Settings/..../ Keys and Access Tokens page and now have a
Consumer Key
Consumer Secret Key
Owner ID (even though this was probably already generated)
Access Token
Access Token Secret
and am using a rest client to test being able to pull the latest 3 statuses using this api end point
https://api.twitter.com/1.1/statuses/user_timeline.json?user_id=userIdHere&count=3
as well as the following headers
Accept: /
Connection: close
User-Agent: OAuth gem v0.4.4
Content-Type: application/x-www-form-urlencoded
Content-Length: 76
Host: api.twitter.com
Authorization: OAuth
oauth_consumer_key=
oauth_signature=
oauth_signature_method=
oauth_timestamp=
oauth_token=
oauth_version=
obviously the 'userIdHere' in the end point address (above) is substituted with my username (i know i can also use my user_id, but that's beside the point) as well as the 'Authorization' values being substituted for real values. That's where my question lies...
What is the mapping for each of the 'oauth...' authorization parameters to their associated Twitter generated and provided Token or key(s) (which were mention near the top of the post)?
I keep getting a '400 Bad Request' response and feel that it is the authorization that is failing in that the permutations of key placements is incorrect. I do not know which value goes to which 'oauth...' value
finally, the structure of the 'Authorization' parameter header is as follows (as per instruction here from the Twitter EXAMPLE) as one line string value
OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog", oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1318622958", oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb", oauth_version="1.0"
)
I am just trying to use a GET to get the last 3 statuses and have not been able to. Also, i plan to switch the values to Environmental Variables, but that doesn't matter yet..
UPDATE
using Postman now, and it's better at mapping, but now am getting
{
"errors": [
{
"code": 32,
"message": "Could not authenticate you."
}
]
}
For the Postman part make sure that you leave Timestamp and nonce empty and hit "update request" before you hit send. That will generate timestamp and nonce - otherwise you will get authorization failures every time. I just tried it with my twitter API credentials and it works.
For Oauth gem code, I find it strange that you have a Content-Type and a Content-Length header for a GET request. Looks like the 400 Bad request could be because you are attempting to do a POST to an endpoint that only supports GET. Indeed when I try to do a POST to that endpoint it tells me.
{
"errors": [
{
"code": 86,
"message": "This method requires a GET or HEAD."
}
]
}
So the 400 is actually good news - it means that authorization works, you are just calling the API in the wrong way.

Accepting api keys in HTTP headers or JSON POST data

I have an HTTP JSON endpoint localhost:8000/resource/ that takes JSON data as input and returns JSON as output. I am now adding API Key based authorization to the endpoint. There are 2 ways to accept the API Key at this endpoint:
Method A: In the request headers
Example python code:
import requests
headers = {
'API-Key': '<my-api-key>',
}
r = requests.post('http://localhost:8000/resource/',
json={'input': <value>},
headers=headers)
Method B: In the JSON data itself
Example python code:
import requests
r = requests.post('http://localhost:8000/resource/',
json={'input': <value>, 'API-Key': '<my-api-key>'},)
I usually notice Method A being adopted. Is there anything wrong with latter approach in which the API key is passed along with the other json data?
I think it has to do with clarity, the API Key isn't really relevant to the input, it's just a form of authorization.
Large frameworks that deal with routing and such are able to filter based on specific headers, and it would be cumbersome to filter based off of a specific form of input in the request body that would require user to intervene and obtain that value for it. Headers are simpler, and suffice for simple data that would fit in a hash-table.