For this examples we assume values for the respective tokens:
bfaD9xOU0SXBhtBP
pChvrpp6AEOEwxBIIUBOvWcRG3X9xL4Y
lBY1xptUJ7ZJSK01x4fNwzw8kAe5b10Q
(either it comes from the /access
request or is set for a dedicated app; widget apps use an empty string)hc1wJAOX02pGGJK2uAv1ZOiwS7I9Tpoe
(either it comes from the /access
request or is set for a dedicated app; widget apps use an empty string)Every request to MKM's API need to include an Authorization
header with an OAuth signature which looks like the following:
Authorization: OAuth realm="https://api.cardmarket.com/ws/v1.1/account", oauth_consumer_key="bfaD9xOU0SXBhtBP", oauth_token="lBY1xptUJ7ZJSK01x4fNwzw8kAe5b10Q", oauth_nonce="53eb1f44909d6", oauth_timestamp="1407917892", oauth_signature_method="HMAC-SHA1", oauth_version="1.0", oauth_signature="DLGHHYV9OsbB/ARf73psEYaNWkI="
Attention: The realm
parameter must be part of the Authorization
header, although it is optional as per RFC.
As you see, you need to provide some (mandatory) parameters with the Authorization
header:
realm
- The request URI (without query parameters)oauth_version
- We use OAuth v1.0oauth_timestamp
- The actual UNIX timestamp of your requestoauth_nonce
- A random string you need to generate for each requestoauth_consumer_key
- This is your App Tokenoauth_token
- This is the Access Token you got for the useroauth_signature_method
- We use HMAC-SHA1oauth_signature
- The signature to verify the authenticity of the requestThe combination of oauth_timestamp
and oauth_nonce
must be unique for all your app's requests.
Authorization: OAuth realm="https://api.cardmarket.com/ws/v2.0/users/karmacrow/articles", oauth_consumer_key="bfaD9xOU0SXBhtBP", oauth_token="lBY1xptUJ7ZJSK01x4fNwzw8kAe5b10Q", oauth_nonce="59689e9cf4091", oauth_timestamp="1500028572", oauth_signature_method="HMAC-SHA1", oauth_version="1.0", oauth_signature="r5g+nFelmTMffrrW+Y4se1u7Q/E="
Now on to generating the signature for the header. Generally you need to:
&
.&
.Common Pitfall: If your request contains query string parameters (as in https://api.cardmarket.com/ws/v2.0/users/karmacrow/articles?start=0&maxResults=2), they must not be part of the value for the Authorization
header's realm
parameter, and must not be part of the request URI here while start building the base string for signature calculation.
// Attention: Don't include possible query parameters here! $baseString = "GET&" . rawurlencode("https://api.cardmarket.com/ws/v1.1/account") . "&"; /* * Results in: * GET&https%3A%2F%2Fapi.cardmarket.com%2Fws%2Fv1.1%2Faccount& */
You need to collect all parameters. Generally none of the MKM API's requests have designated parameters. But you need to include all parameters from the Authorization
header except realm
and oauth_signature
.
Attention: With the API 2.0 we introduced query parameters, all of these need to be collected and used for the base string for signature calculation.
Common Pitfall: If your request contains query string parameters (as in https://api.cardmarket.com/ws/v2.0/users/karmacrow/articles?start=0&maxResults=2), they must be collected here in addition to all parameters from the Authorization
header.
Percent encode all parameter names and values and sort them alphabetically:
Important: If the parameters are not sorted alphabetically, authorization will fail
=
&
$parameters = array(); // Attention: $encodedAndSortedParameters must include all possible query parameters! foreach ($encodedAndSortedParameters as $name => $value) { $parameters[] = $name . "=" . $value; } $parametersString = implode("&", $parameters); /* * Results in: * oauth_consumer_key%3DbfaD9xOU0SXBhtBP%26oauth_nonce%3D53eb1f44909d6%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1407917892%26oauth_token%3DlBY1xptUJ7ZJSK01x4fNwzw8kAe5b10Q%26oauth_version%3D1.0 */ $baseString .= rawurlencode($parametersString); /* * Results in: * GET&https%3A%2F%2Fapi.cardmarket.com%2Fws%2Fv1.1%2Faccount&oauth_consumer_key%3DbfaD9xOU0SXBhtBP%26oauth_nonce%3D53eb1f44909d6%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1407917892%26oauth_token%3DlBY1xptUJ7ZJSK01x4fNwzw8kAe5b10Q%26oauth_version%3D1.0 */
You now have the base string you need to encrypt.
Common Pitfall: If the request contains query parameters, they have to be part of this string and have been sorted alphabetically together with the rest of the parameters:
GET&https%3A%2F%2Fapi.cardmarket.com%2Fws%2Fv2.0%2Fusers%2Fkarmacrow%2Farticles&maxResults%3D2%26oauth_consumer_key%3DbfaD9xOU0SXBhtBP%26oauth_nonce%3D59689e9cf4091%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1500028572%26oauth_token%3DlBY1xptUJ7ZJSK01x4fNwzw8kAe5b10Q%26oauth_version%3D1.0%26start%3D0
The signing key to later encrypt the base string is the combination of your App Secret and the Access Token Secret (for the user).
&
$signingKey = rawurlencode($appSecret) . "&" . rawurlencode($accessTokenSecret); /* * Results in: * pChvrpp6AEOEwxBIIUBOvWcRG3X9xL4Y&hc1wJAOX02pGGJK2uAv1ZOiwS7I9Tpoe */
Attention: There are use cases where you still don't have a Access Token Secret, or you simply don't need any.
You don't have an Access Token and Secret, but you have a Request Token
After successful login of your user at the /authenticate
site you only have the Request Token to exchange it into Access Token and Secret. Your signing key doesn't include an Access Token Secret. In this case the signing key is only your percent encoded App Secret appended by the &
. Only applicable for 3rd party apps!
You don't have both an Access Token and Secret
There are several public (non-protected) resources (mainly Marketplace
requests). All these request are marked as public within this documentation. Also Widget Apps never have both an access token and secret.
In this case:
&
oauth_token
parameter in the Authorization
header is emptyAttention: Dedicated apps always need both the Access Token and Secret, even for public resources.
At the end, the base string needs to be encrypted with the signature key and finally Base64 encoded.
$rawSignature = hash_hmac("sha1", $baseString, $signingKey, true); $signature = base64_encode($rawSignature); /* * Results in: * 163qUUcPtGFLxUzqeCIChErTbKU= */
Attention: Make sure the $rawSignature
contains binary data (and not converted to a string). For that, the 4th parameter of the hash_hmac
function must be set to true
.