Why the webhook signature sent by slack in the request header is not matching with the calculated webhook signature at our server? - hash

The problem that we are facing is:
The webhook signature sent by slack in the request header is not matching with the calculated webhook signature at our server, but only for the first request that is made when the Zervise app for Slack is opened and any of the tab is accessed. From the next requests the signatures are matching.
Our back-end server supports both the following type of request body that slack is using:
application/json
application/x-www-form-urlencoded
Following is the back-end code for checking the slack webhook signature:
const slack = (req, res, next) => {
if (
!req.headers['x-slack-request-timestamp'] ||
Math.abs(
Math.floor(new Date().getTime() / 1000) -
+req.headers['x-slack-request-timestamp']
) > 300
)
return res.status(400).send('Request too old!');
const baseStr = `v0:${
req.headers['x-slack-request-timestamp']
}:${qs.stringify(req.body, {
format: 'RFC1738',
})}`;
const receivedSignature = req.headers['x-slack-signature'];
const expectedSignature = `v0=${crypto
.createHmac('sha256', env.SLACK_SIGNING_SECRET)
.update(baseStr, 'utf8')
.digest('hex')}`;
if (expectedSignature !== receivedSignature) {
console.log('WEBHOOK SIGNATURE MISMATCH');
return res.status(400).send('Error: Signature mismatch security error');
}
console.log('WEBHOOK VERIFIED');
next();
};
The screenshots of the console logs are added below. Each screenshot includes the request headers, the received signature from slack (receivedSignature) and the calculated signature at our server (expectedSignature). I have also tried to use the raw body of request to calculate the signature, but it is still not matching from the first request only.
Following are the screenshot list:
Screenshot of the console logs for the first request where the signatures are not matching: app opened and the first request from slack
Screenshot of the console logs for the subsequent request where the signatures are matching: subsequent requests from slack

The issue is resolved. I needed to use the request body in raw form instead of the encoded formats. Doing that solved the signature mismatch problem.
Please check the following article written by me, where I have described the process in detail: Verifying requests from Slack - The CORRECT method for Node.js

Related

Chrome DevTools Protocol Fetch Domain - getResponseBody - apparently fails with HTTP redirects

I am wishing to collect the body of an HTTP request, including when the page redirects to elsewhere. Clearly, I can use non-Fetch domain mechanisms such as Network.getResponseBody. That works fine for the "final" page in a chain of redirections, but cannot be used for the intermediate pages because Chrome appears to dump the content when going to the next redirection target.
So, I implemented Fetch.enable( { patterns: [ { requestStage: Response } ] } ) (using PHP, but the details of that are irrelevant, as you will see). No error is returned from this method call. After then doing a Page.navigate, I wait for a Fetch.requestPaused event which contains members requestId, responseStatusCode and responseHeaders and then send a Fetch.getResponseBody (using the requestId from the Fetch.requestPaused) and the response I get depends on what the actual response to the page itself was. So, for a 200, I get a response body (hurray), but for a 30x (301, 302 etc), I always get error code -32000 with the message "Can only get response body on requests captured after headers received". Now, issuing that error message is inconsistent (in my view) with the Fetch.requestPaused event data, even if Chrome DevTools Protocol (CDP) was not intended to capture the bodies of HTTP redirected pages. By the way, pages with content triggered redirection (via a META element or JavaScript) are captured okay, I assume because they return a 200 status code.
So, is the issue in the sequence of calls I'm following or in the error message returned by Fetch.getResponseBody and am I correctly assuming CDP was not intended to capture the bodies of documents in a redirection chain (apart from the last one, obviously)?
You need to continue the request on a 301/302 and let the browser follow it (there is no body in a redirect):
if (
params.responseStatusCode === 301 || params.responseStatusCode === 302
) {
await this.#client.send('Fetch.continueRequest', {
requestId,
});
} else {
// get body here
const responseCdp = await this.#client.send('Fetch.getResponseBody', {
requestId,
});
await this.#client.send('Fetch.fulfillRequest', {
requestId,
responseCode: params.responseStatusCode,
responseHeaders: params.responseHeaders,
body: responseCdp.body,
});
}

PayPal Checkout Buttons - client/server communication

I am integrating the smart checkout of Paypal. I do not understand what the javascript portion expects back from the server. This is what I have got in JS
...
...
createOrder: function(data, actions) {
return fetch('/paypal/sandbox/createOrder', {
method: 'post',
headers: {
'content-type': 'application/json'
}
}).then(function(res) {
return res.json();
}).then(function(data) {
return data.orderID;
});
},
...
...
And this is what the server side does when /paypal/sandbox/createOrder' is called …
$request = new OrdersCreateRequest();
$request->prefer('return=representation');
$request->body = $this->buildRequestBody();
$response = $this->PayPalClient->execute($request);
What I can not find anywhere: What am I supposed to do with the response? I tried to echo it plain, echo it as JSON, but I always get errors like "Expected order id"
What do I need to respond to the client request?
The structure of the communication between your createOrder frontend JS and your backend server route (which in turn calls the PayPal API) is something you define. It can be is simple or as complex as you need it to be. You can send as many parameters back and forth as you want. You can use JSON, XML, Morse code, RFC 1149, or whatever you want for this transmission between your client and server.
The only required bit of information is the Order ID, which your server-side code in turn gets from the PayPal API v2/checkout/orders call (as id in the response), and which your createOrder function must then propagate back to its caller once obtained, which in the sample code happens here:
...
return data.orderID;
One very simple implementation would be to echo the whole v2/checkout/orders API response , not just id, and change the above client-side code to be return data.id so it reads that key name

Correct uri for DeleteAgentUser (Google Homegraph)

I'm trying to use the DeleteAgentUser of Homegraph to unlink a user with Google. I already implemented the ReportState and the correct uri for this is: https://homegraph.googleapis.com/v1/devices:reportStateAndNotification. So I thought the DeleteAgentUser has to be: https://homegraph.googleapis.com/v1/devices:deleteAgentUser but I'm getting a '404 Not Found' Error.
I tried it with:
https://homegraph.googleapis.com/v1/devices:deleteAgentUser
https://homegraph.googleapis.com/v1/deleteAgentUser
https://homegraph.googleapis.com/v1/devices:DeleteAgentUser
https://homegraph.googleapis.com/v1/DeleteAgentUser
everything with post and delete request and always getting the error.
What is the correct Homegraph uri to delete a user from Google?
Looking at the RPC defined in the public protobuf, it seems that the implementation is defined as:
rpc DeleteAgentUser(DeleteAgentUserRequest) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/v1/{agent_user_id=agentUsers/**}"
};
}
So, it seems like you'd send a DELETE request to https://homegraph.googleapis.com/v1/{agent_user_id} or maybe https://homegraph.googleapis.com/v1/agentUsers/{agent_user_id} with your agent user id, and signed with your authorization token similar to Report state.

Atlassian Jira - 401 only when using query parameters

Currently working on a JIRA addon using the ACE framework. Executing a request using the integrated httpClient.
When I make a request such as this
https://instance.atlassian.net/rest/api/3/search
it works fine using the header Authorization: JWT <token> but when I run the same request with a query parameter like this
https://instance.atlassian.net/rest/api/3/search?maxResults=1
the request fails with a 401. I have confirmed that the JWT is not expired due to reverting the query parameters and seeing success again.
My atlassian-connect.json has scope READ as requested by the endpoint.
Any suggestions?
I was surprised that the rest call "rest/api/2/search?maxResults=1" worked. But it did when I was logged into my instance.
If I try that as JQL in Issue Search (maxResults=1), I get an invalid or unauthorized error message.
My instance is on premise (API V2). Yours appears to be in the cloud (V3). So it may be that the REST search works more like the Issue Search in V3 and is therefore returning the 401
It's a guess that should be easy to test... replace your maxResults=1 with some actual JQL or a filter ID and see if your results change
Since you're using ACE and utilizing httpClient, you might want to try the checkValidToken() route instead. The snippet below worked for me.
app.get('/mySearch', addon.checkValidToken(), function(req, res) {
var httpClient = addon.httpClient(req);
httpClient.get({
url: '/rest/api/3/search?maxResults=1',
headers: {
'X-Atlassian-Token': 'nocheck',
'Content-Type': 'application/json'
}
},
function (err, httpResponse, body) {
if (err) {
return console.error('Search failed:', err);
}
console.log('Search successful:', body);
});
});

OpenTok Rest Service Invalid JWT Error on Fiddler Request

I'm trying to create OpenTok session by Rest services with JWT object as suggested. I tried to generate session with Fiddler.
Here is my fiddler request (JWT string has been changed with *** partially for security reasons)
POST https: //api.opentok.com/session/create HTTP/1.1
Host: api.opentok.com
X-OPENTOK-AUTH: json_web_token
Accept: application/json
Content-Length: 172
eyJ0eXAiOiJKV1QiL******iOiJIUzI1NiJ9.eyJpc3MiOjQ1NzM******OiJkZW5l******XQiOjE0ODI3OTIzO***SOMESIGNEDKEYHERE***.izvhwYcgwkGCyNjV*****2HRqiyBIYi9M
I got 403 {"code":-1,"message":"Invalid token format"} error probably means my JWT object is not correct. I tried creating it using http://jwt.io (as opentok suggests) and other sites and all seems correct and very similar to the one on tokbox (opentok) site.
I need an explanation to fix it and create a session.
May it be because I am using opentok trial?
JWT creation Parameters
I had the same problem. I resolved the error by setting the correct key-value pairs for the payload part.
Example of my payload is as follows in C#:
var payload = new Dictionary<string, object>()
{
{ "iss", "45728332" },
{ "ist", "project" },
{ "iat", ToUnixTime(issued) },
{ "exp", ToUnixTime(expire) }
};
The value of the "ist" should be set to "project", not the actual name of your project.
Update: Looking at your screenshot, I can say you have not set the secret key (here, it's your ApiKeySecret from TokBox account > project) at the very bottom right.
OK I have found the answer at last,
Your Opentok API Secret key should not be used directly as Sign parameter. In java as shown below, it should be encoded first.
Base64.encodeToString("db4******b51a4032a83*******5d19a*****e01".getBytes(),0)
I haven't tried it on http://jwt.io and fiddler but it seems it will work on it too. Thanks. Full code is below;
payload = Jwts.builder()
.setIssuedAt(currentTime)
.setIssuer("YOUR_OPENTOK_KEY")
.setExpiration(fiveMinutesAdded)
.claim("ist", "project")
.setHeaderParam("typ","JWT")
.signWith(SignatureAlgorithm.HS256, Base64.encodeToString("YOUR_OPENTOK_SECRET".getBytes(),0))
.compact();
return payload;