I am trying to send a simple post request to the bybit api and I keep getting the 10004 sign error.
Here is the response:
{"ret_code":10004,"ret_msg":"error sign! origin_string[api_key=(my api key)\u0026symbol=BTCUSDT\u0026timestamp=1635967650768]","ext_code":"","ext_info":"","result":null,"time_now":"1635967651.397800"}
This is the code I am using to send the request.
public async static Task<string> cancelAllOrders()
{
string ts = await GenerateTimeStamp();
string paramString = "api_key=" + apiKey + "&symbol=BTCUSDT" + "timestamp=" + ts;
string sign = CreateSignature(secretKey, paramString);
CancelOrderContent co = new CancelOrderContent(apiKey, "BTCUSDT", ts, sign);
var client = new RestClient(ApiUrl + "/v2/private/order/cancelAll");
var request = new RestRequest();
request.AddJsonBody(co);
var response = client.Post(request);
Trace.WriteLine(response.StatusCode.ToString() + " " + response);
return "";
}
Here is the class I am Serializing to JSON for the body of the request.
public class CancelOrderContent
{
public string api_key;
public string sign;
public string symbol;
public string timestamp;
public CancelOrderContent(string api_key, string symbol, string timestamp,string sign)
{
this.api_key = api_key;
this.symbol = symbol;
this.timestamp = timestamp;
this.sign = sign;
}
}
Here is the code I am using to create signatures:
public static string CreateSignature(string secret, string message)
{
var signatureBytes = Hmacsha256(Encoding.UTF8.GetBytes(secret), Encoding.UTF8.GetBytes(message));
return ByteArrayToString(signatureBytes);
}
private static byte[] Hmacsha256(byte[] keyByte, byte[] messageBytes)
{
using (var hash = new HMACSHA256(keyByte))
{
return hash.ComputeHash(messageBytes);
}
}
I've tried al kinds of methods to fix this but I can't seem to get rid of it.I've tried mutliple endpoints and I still get the same error.
2022/01/17 this still works.
Hey #Vexatious I ran into a similar issue with the bybit-api trying to submit orders and I kept receiving a Key denied, insufficient permissions error even though I knew I was setting up my keys properly.
Maybe ByBit changed something? Lib outdated? Who Knows.
One major thing that I noticed is that they require you to Order the params alphabetically before appending the signature to the body of the request.
Edit: Updated because I recognized GET Requests can be equally as confusing. Scroll down to view the example POST Request.
GET and POST requests are handled differently
axios(https://api-testnet.bybit.com/GET?aParam=foo&bParam=bar&sign=sign)
axios(https://api-testnet.bybit.com/POST, {data: queryString})
SIGNATURE
For Both: You must alphabetically arrange the params before generating the signature.
get your query param's on a single object [Including 'api_key', Excluding the API Secret].
Sort the query param's alphabetically.
Iterate over the objects sorted keys, building a QueryString like in the ex below
use hmac sha256 with a hex digest to create the sign (look at ./sign.ts at the bottom)
ex: "aParam=foo&bParam=bar",
That's your sign parameter dealt with.
GET REQUESTS: Append the sign parameter to the end of the QueryString
and send'er, might need to use a header
// Might still need {'Content-Type': 'application/x-www-form-urlencoded'}
// header depending on what request lib you're using.
const url = "https://api-testnet.bybit.com/GET?aParam=foo&bParam=bar&sign=" + sign
POST REQUESTS: it is required that the object is sent as request data (still, in the form of a QueryString like above) and not a fully built out Http string similar to the GET Request. Add the sign parameter to the end of the QueryString you generated the signature with, assign that to your request handlers data parameter and fire away!
I did come up with a minimal working version that successfully posted a Spot Order on their testnet, here is the jest test.
./bybit.test.ts
test("WORKING BYBIT TRADE.", async () => {
const serverTime:number = (await axios.get(`https://api-testnet.bybit.com/spot/v1/time`)).data
// These need to be within 1000ms of eachother (I'm pree sure, their formula is kinda confusing)
console.log(`Their Timestamp`, serverTime)
console.log(`Our Timestamp`, Date.now())
const queryParams = {
// Alphabetically ordered
// (Sign generation function should deal with unordered params using .sort())
'api_key': bybitApiKey,
qty:10,
recvWindow: 10000,
side:"BUY",
symbol:"ETHUSDT",
timestamp: Date.now(),
type:"MARKET",
}
const queryString = querystring.stringify(queryParams)
const sign = "&sign=" + getSignature(queryParams, bybitSecret)
const fullQuery = queryString + sign
console.log(`FullQuery example`, fullQuery)
// api_key=...&qty=10&recvWindow=10000&side=BUY&symbol=ETHUSDT×tamp=1638371037593&type=MARKET&sign=...
let result = await axios(`https://api-testnet.bybit.com/spot/v1/order`, {
withCredentials: true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: "POST",
data: fullQuery,
})
console.log(`Post Status`, result.status)
console.log(`Post Body`, result.data)
})
/**
Post Status 200
Post Body {
ret_code: 0,
ret_msg: '',
ext_code: null,
ext_info: null,
result: {
accountId: '...',
symbol: 'ETHUSDT',
symbolName: 'ETHUSDT',
orderLinkId: '...',
orderId: '...',
transactTime: '...',
price: '0',
origQty: '10',
executedQty: '0',
status: 'FILLED',
timeInForce: 'GTC',
type: 'MARKET',
side: 'BUY'
}
*/
}
./sign.ts
import crypto from 'crypto'
export function getSignature(parameters: any, secret: string) {
var orderedParams = "";
Object.keys(parameters).sort().forEach(function(key) {
orderedParams += key + "=" + parameters[key] + "&";
});
orderedParams = orderedParams.substring(0, orderedParams.length - 1);
return crypto.createHmac('sha256', secret).update(orderedParams).digest('hex');
}
Hopefully this helps!
I have just figured this out for the ByBit api, but using Javascript instead of C#. However i do know C#, so hopefully this will work for you.
The ByBit API endpoints which use POST require the same HMAC encryption of the data as in GET request. Instead of signing the parameters in the query string (and appending &sign=xxxx to it), you:
sign the serialized to JSON object,
then add the [object].sign = "xxxx" to the object before the POST.
This is where it gets tricky for your C# class. You have CancelOrderContent with a sign property. This will serialize the key 'sign' with the blank value. However, the ByBit API won't accept that because the data signed will be different.
Either you must
serialize an object without the 'sign' key (CancelOrderContentNosignkey),
copy the properties from CancelOrderContentNosignkey to a new CancelOrderContent
add the signature hash string to the CancelOrderContent object.sign prop
then post the serialized object with the sign key/value pair,
or...
serialize the object as you are now,
but then munge the serialized string to remove the ,"sign":'' part.
Then sign that string,
then add the sign value to the object,
serialise it to JSON again, and
POST that as the data.
I believe this will work, since i had to to that to get it working in JS. However, adding the sign key/value is easier since there's no classes.
A variation of this would be to make CancelOrderContent a dynamic type, where you don't add the 'sign' key/value until after serializing/signing it.
Note, when you manually serialize the object to JSON (do not use paramString), in theory the serializer should be the same one used or configured in RestRequest.AddJsonBody()
Sorry i don't have C# code, but this should work.
Thank you #Kwuasimoto for the detailed answer, it steered me in the right direction, however, it didn't quite work for me as is. When passing the fullQuery string as the axios data I was getting the error "missing required parameter 'sign'", but when I replaced the string with URLSearchParams like this
const postData = new URLSearchParams(queryParams);
postData.append("sign", signature);
it worked. Here's the full code I ended up using. It's mostly #Kwuasimoto 's answer with a few of my tweaks.
import crypto from 'crypto'
import axios from 'axios';
const getSignature(parameters: any, secret: string) => {
let orderedParams = "";
Object.keys(parameters).sort().forEach(function(key) {
orderedParams += key + "=" + parameters[key] + "&";
});
orderedParams = orderedParams.substring(0, orderedParams.length - 1);
return crypto.createHmac('sha256', secret).update(orderedParams).digest('hex');
}
const postSpotOrder = async () => {
const queryParams = {
api_key: bybitApiKey,
qty: 10,
recvWindow: 10000,
side: "BUY",
symbol: "ETHUSDT",
timestamp: Date.now(),
type: "MARKET",
};
const signature = getSignature(queryParams, bybitSecret);
const postData = new URLSearchParams(queryParams);
postData.append("sign", signature);
let result = await axios(`https://api-testnet.bybit.com/spot/v1/order`, {
withCredentials: true,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
method: "POST",
data: postData,
});
console.log(`Post Status`, result.status);
console.log(`Post Body`, result.data);
};
Related
I am currently using Forge Webhooks API to handle different events that might occur on a project. Everything works fine, except the payload signature check.
The reason why I want to check the payload is because the callback will end up on my API and I want to reject all requests that do not come from Forge's webhook service.
Steps I followed:
Add (register) secret key (token) on Forge. API Reference
Trigger an event that will eventually call my API for handling it.
Validating signature header. Followed this tutorial.
PROBLEM!!! My computedSignature is different from the signature received from Forge.
My C# code looks like this:
private const string SHA_HASH = "sha1hash";
var secretKeyBytes = Encoding.UTF8.GetBytes(ForgeAuthConfiguration.AntiForgeryToken);
using var hmac = new HMACSHA1(secretKeyBytes);
var computedHash = hmac.ComputeHash(request.Body.ReadAsBytes());
var computedSignature = $"{SHA_HASH}={computedHash.Aggregate("", (s, e) => s + $"{e:x2}", s => s)}";
For one example, Forge's request has this signature header: sha1hash=303c4e7d2a94ccfa559560dc2421cee8496d2d83
My C# code computes this signature: sha1hash=3bb8d41c3c1cb6c9652745f5996b4e7f832ca8d5
The same AntiForgeryToken was sent to Forge at step 1
Ok, I thought my C# code is broken, then I tried this online HMAC generator and for the given input, result is: 3bb8d41c3c1cb6c9652745f5996b4e7f832ca8d5 (same as C#)
Ok, maybe the online generator is broken, I tried their own code in node js and this is the result:
I have 3 ways of encrypting the SAME body using the SAME key and I get the SAME result every time. BUT those results are DIFFERENT from the signature provided by Forge, resulting in failing the check and rejecting a valid request...
Does anyone know what is happening with that signature?
Why is it different from my result if I follow their tutorial?
How are you validating your requests?
The code below is working at my side. Could you give it a try if it helps?
[HttpPost]
[Route("api/forge/callback/webhookbysig")]
public async Task<IActionResult> WebhookCallbackBySig()
{
try
{
var encoding = Encoding.UTF8;
byte[] rawBody = null;
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
rawBody = encoding.GetBytes(reader.ReadToEnd());
}
var requestSignature = Request.Headers["x-adsk-signature"];
string myPrivateToken = Credentials.GetAppSetting("FORGE_WEBHOOK_PRIVATE_TOKEN");
var tokenBytes = encoding.GetBytes(myPrivateToken);
var hmacSha1 = new HMACSHA1(tokenBytes);
byte[] hashmessage = hmacSha1.ComputeHash(rawBody);
var calculatedSignature = "sha1hash=" + BitConverter.ToString(hashmessage).ToLower().Replace("-", "");
if (requestSignature.Equals(calculatedSignature))
{
System.Diagnostics.Debug.Write("Same!");
}
else
{
System.Diagnostics.Debug.Write("diff!");
}
}
catch(Exception ex)
{
}
// ALWAYS return ok (200)
return Ok();
}
If this does not help, please share with your webhook ID (better send email at forge.help#autodesk.com). We will ask engineer team to check it.
Good Evening Community,
I am having problems to post data to a C# Api from Angular 2 POST methods. Practically I need to send a JSON object to the API. Below is the API POST method that is the endpoint.
[HttpPost]
public Boolean Update(BoRole role, Guid accessToken)
{
CheckUserSuperadmin(accessToken);
string JsonContent = Request.Content.ReadAsStringAsync().Result;
var roleEntity = BaseDependencies.RoleManager.GetRoleById(role.Id);
roleEntity.Name = role.Name;
roleEntity.AuthorizedThreshold = role.AuthorizedThreshold;
BaseDependencies.RoleManager.UpdateRole(roleEntity);
return true;
}
The following is my Angular 2 service, with the POST method.
// Update the Role
updateRole(role: Role, accessToken: string): any {
const body: any = JSON.stringify(role);
const headers = new Headers({'Content-Type': 'application/json'});
const options = new RequestOptions({ headers: headers });
const url = this.serverUrl + '/api/Role/Update?role=' + body + '&accessToken=' + accessToken;
return this.http.post(url, body, options).map((res: Response) => res.json());
}
To explain better, I am trying to send a JSON object to this API, but whenever I try to POST to the API the role object remains null, never tried to POST data this way. Is it possible?
Thanks
Change the Api to get only one get one body
[HttpPost("Add")]
public async Task<IActionResult> Post([FromBody]AddRequest value)
In my case the class
AddRequest
Have all the body structure that I need, in your case create one class that C# can automap (same names) and the rest is history in C#
At Angular
const url = this.serverUrl + '/api/Role/Update?role=' + body +
'&accessToken=' + accessToken;
change it for
const url = this.serverUrl + '/api/CONTROLLERNAME';
C# will detect that is a Post Request and map it to the right Http Call
I would like to convert the authenticated REST request of JS (below) to C# code - using RestSharp lib (as shown) I seems not building the signature correctly. Please help..
Rest response keep response with "Invalid API Key" (which the key/secret are confirmed correct)
// sample code using the crypto lib to build the RESTFUL request
const crypto = require('crypto')
const request = require('request')
const apiKey = 'test'
const apiSecret = 'test'
const url = 'version/auth/abc'
const nonce = Date.now().toString()
const body = {}
const rBody = JSON.stringify(body)
// try build the RESTFUL signature here using crypto lib and use sha384
// Not quite sure what's the update does here though.
let signature = `/api/${url}${nonce}${rBody}`
signature = crypto
.createHmac('sha384', apiSecret)
**.update(signature)**
.digest('hex')
// all code above is fine. And this is the sample code only, and trying to do something same in C# and have tried the following. I believe is the way create the "signature" issue.
I have written the C# code below, but not working, please kindly point out, I guess is the signature building is incorrect somehow.
private uint64 _nonce = UnixTimestamp.CurrentTimeInMillis;
public uint64 MyNonce()
{
return ++_nonce;
}
private string MySignature(string jsonData)
{
byte[] data = Encoding.UTF8.GetBytes(jsonData);
_hasher = _hasher ?? new HMACSHA384(Encoding.UTF8.GetBytes(PrivateApiSecret));
byte[] hash = _hasher.ComputeHash(data);
return GetHexString(hash);
}
// try to build the request below in a method.
// only show method body below:
// using the RestSharp client to build Restful req.
var client = new RestClient(new Uri("the API address goes here"));
var request = new RestRequest(string.Format("auth/abc"), Method.POST);
// try do something similar and serialize to json in order to build the signature.
Dictionary emptyBody= new Dictionary();
string url = "version/auth/abc";
string rawBody = JsonConvert.SerializeObject(emptyBody);
string sign = $"/api/{url}{MyNonce()}{rawBody}";
string sign64= Convert.ToBase64String(Encoding.UTF8.GetBytes(sign));
string signature = MySignature(sign64);
// add the key and signature above to the header of reqest.
request.AddHeader("nonce", GetNonce());
request.AddHeader("apikey", PrivateApiKey);
request.AddHeader("signature", signature);
// well, you don't need me to explain this line don't you?
var response = request.Execute(....);
Hope this is clear enough. Thanks in advance.
I'm trying to figure out how to pass a parameter in my .NET application. The URL request looks like:
http://webservices.amazon.com/onca/xml?
Service=AWSECommerceService
&Operation=ItemLookup
&ResponseGroup=Large
&SearchIndex=All
&IdType=UPC
&ItemId=635753490879
&AWSAccessKeyId=[Your_AWSAccessKeyID]
&AssociateTag=[Your_AssociateTag]
&Timestamp=[YYYY-MM-DDThh:mm:ssZ]
&Signature=[Request_Signature]
The part that I'm confused about are these:
&Timestamp=[YYYY-MM-DDThh:mm:ssZ]
&Signature=[Request_Signature]
I'm not sure whether I can Just simply do it something like this for timestamp part:
var TimeStamp = DateTime.Now; // without any special datetime formating?
So my question is how do I actually generate this signature URL in the request URL ?
I have all of these parameters above but I'm not sure how to generate this last one ?
Can someone help me out ?
AWS utilizes HMAC request-signing. Generally speaking, the way this works is that you create a "message", which is composed of things like your access key(s), request headers, request body and a timestamp. You then HMAC this "message" and that becomes your "signature" for the request. This prevents replay-attacks as each request must have a unique signature.
It looks like the timestamp simply needs to be in ISO format (YYYY-MM-DDThh:mm:ssZ), so, no you can't just use DateTime.Now. The default format utilized by ToString will not be ISO. Instead, you'd need to use something like:
DateTime.Now.ToString("yyyy-MM-ddThh:mm:sszzz");
Or it would actually probably be better to use UTC time and simply append a Z:
DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ");
As for creating the signature, see the AWS documentation, where they provide some sample code:
static byte[] HmacSHA256(String data, byte[] key)
{
String algorithm = "HmacSHA256";
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm);
kha.Key = key;
return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}
static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName)
{
byte[] kSecret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray());
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256("aws4_request", kService);
return kSigning;
}
/*
DOCUMENTATION: https://docs.aws.amazon.com/AWSECommerceService/latest/DG/rest-signature.html#rest_detailedexample
*/
var itemID = "0679722769";
var accessKeyID = "AKIAIOSFODNN7EXAMPLE";
var timeStamp = DateTime.UtcNow.ToString("o");
var req = $"Service=AWSECommerceService&AWSAccessKeyId={accessKeyID}&Operation=ItemLookup&IdType=UPC&ItemId={itemID}&Version=2013-08-01&Timestamp={timeStamp}";
req = req.Replace(":", "%3A").Replace(",", "%2C"); //UrlDecode certain characters
var reqlist = req.Split('&').ToArray(); //we need to sort our key/value pairs
Array.Sort(reqlist);
req = String.Join("&", reqlist); //join everything back
var reqToSign = $#"GET
webservices.amazon.com
/onca/xml
{req}".Replace("\r", ""); //create the request for signing. We need to replace microsofts's crlf with just a lf; Make sure there are no leading spaces after the linefeeds.
var signage = getSignatureKey("1234567890",reqToSign);
req = $"http://webservices.amazon.com/onca/xml?{req}&Signature={signage}"; //create our request with the signature appended.
return req;
}
private static byte[] HmacSHA256(String data, byte[] key)
{
String algorithm = "HmacSHA256";
KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm);
kha.Key = key;
return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}
private static string getSignatureKey(string key, string stringToSign)
{
byte[] kSecret = Encoding.UTF8.GetBytes(key.ToCharArray());
byte[] kSigning = HmacSHA256(stringToSign, kSecret);
return WebUtility.UrlEncode(Convert.ToBase64String(kSigning));
}
Contrary to most of the answers found here and elsewhere, this is the only way that works. The entire request has to be hashed, not just particular parameters. I can't speak to other Amazon services, but the Commerce Service has to be done like this.
Quite a few answers here and elsewhere referenced this: https://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
This is most certainly not correct. If you're not passing a region parameter, how can Amazon create the same signature since it doesn't have all the information.
I am trying to communicate with Instagram API and wish to use Signed Request for secure communication with API as per the link given below
https://instagram.com/developer/secure-api-requests/
At the default page, i simply fetch the details like Client Key, Client Secret Code and Redirect URL and get authenticated by Instagram.
Once authenticated, At redirect URL, Following is my code
//To Get Access Token
var json = "";
NameValueCollection parameters = new NameValueCollection();
parameters.Add("client_id", ConfigurationManager.AppSettings["instagram.clientid"].ToString());
parameters.Add("client_secret", ConfigurationManager.AppSettings["instagram.clientsecret"].ToString());
parameters.Add("grant_type", "authorization_code");
parameters.Add("redirect_uri", ConfigurationManager.AppSettings["instagram.redirecturi"].ToString());
parameters.Add("code", code);
WebClient client = new WebClient();
var result = client.UploadValues("https://api.instagram.com/oauth/access_token", "POST", parameters);
var response = System.Text.Encoding.Default.GetString(result);
// deserializing nested JSON string to object
var jsResult = (JObject)JsonConvert.DeserializeObject(response);
string accessToken = (string)jsResult["access_token"];
int id = (int)jsResult["user"]["id"];
Page.ClientScript.RegisterStartupScript(this.GetType(), "GetToken", "<script>var instagramaccessid=\"" + #"" + id + "" + "\"; var instagramaccesstoken=\"" + #"" + accessToken + "" + "\";</script>");
After getting Access Token, Let us say I get the Popular photos from instagram. Following is a div to hold the popular photos
<div style="clear:both;"></div>
<div>
<h1>
Popular Pictures</h1>
<div id="PopularPhotosDiv">
<ul id="photosUL1">
</ul>
</div>
</div>
Then i use the following function to fill the div of popular photos
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
GetPopularPhotos();
});
function GetPopularPhotos() {
$("#photosUL1").html("");
$.ajax({
type: "GET",
async: true,
contentType: "application/json; charset=utf-8",
//Most popular photos
url: "https://api.instagram.com/v1/media/popular?access_token=" + instagramaccesstoken,
dataType: "jsonp",
cache: false,
beforeSend: function () {
$("#loading").show();
},
success: function (data)
{
$("#loading").hide();
if (data == "") {
$("#PopularPhotosDiv").hide();
} else {
$("#PopularPhotosDiv").show();
for (var i = 0; i < data["data"].length; i++) {
$("#photosUL1").append("<li style='float:left;list-style:none;'><a target='_blank' href='" + data.data[i].link + "'><img src='" + data.data[i].images.thumbnail.url + "'></img></a></li>");
}
}
}
});
}
This code is working fine, I just want to send it as a signed request.
Any help will be truly appreciated.
The Enforced Signed Requests option for the Instagram API ensures that only the applications with the client secret can create requests to the API, even if the access token has been leaked. The signature you generate for every request is in theory an unforgeable token that only your application and Instagram API can create and verify.
The method for creating signatures for the Instagram API is by using the "keyed-hash message authentication code" (HMAC) algorithm HMAC-SHA256. In .NET, you can create HMAC-SHA256 signatures using the HMACSHA256 class. The function requires a message that will be authenticated and a secret key used for this authentication.
Using the examples on the page you linked to, here's what I came up with in C# to generate these signatures:
static string GenerateSignature(string endpoint, Dictionary<string,string> parameters, string secret)
{
// Build the message to be authenticated
StringBuilder message = new StringBuilder(endpoint);
foreach (var param in parameters.OrderBy(p => p.Key))
{
message.AppendFormat("|{0}={1}", param.Key, param.Value);
}
// Create a HMAC-SHA256 digest of the message using the secret key
HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
byte[] digest = hmac.ComputeHash(Encoding.UTF8.GetBytes(message.ToString()));
// Return the digest as a hexstring to be used as a signature for the request
return ByteArrayToString(digest);
}
static string ByteArrayToString(byte[] array)
{
// Convert the bytes in the array to a lower-case hexstring
return array.Aggregate(new StringBuilder(), (sb, b) => sb.Append(b.ToString("x2"))).ToString();
}
static void Main(string[] args)
{
string secret = "6dc1787668c64c939929c17683d7cb74";
string endpoint;
Dictionary<string, string> parameters;
string signature;
// Example 1
endpoint = "/users/self";
parameters = new Dictionary<string, string>
{
{ "access_token", "fb2e77d.47a0479900504cb3ab4a1f626d174d2d" },
};
signature = GenerateSignature(endpoint, parameters, secret);
Console.WriteLine("sig={0}", signature);
// Example 2
endpoint = "/media/657988443280050001_25025320";
parameters = new Dictionary<string, string>
{
{ "access_token", "fb2e77d.47a0479900504cb3ab4a1f626d174d2d" },
{ "count", "10" },
};
signature = GenerateSignature(endpoint, parameters, secret);
Console.WriteLine("sig={0}", signature);
Console.ReadKey(true);
}
The generated signatures should match the ones given in the documentation examples.
As Instagram's documentation warns, never make this client secret key publically available. In other words, make sure the client secret won't be distributed on mobile devices, website JavaScript, desktop applications, etc. The key should always be kept secret between you and Instagram.