What is hash field in the BigCommerce webhook? - bigcommerce

How it generate? How I can validate it?
https://developer.bigcommerce.com/api/webhooks-getting-started
{
"store_id": 11111,
"producer": "stores/abcde",
"scope": "store/order/statusUpdated",
"data": {
"type": "order",
"id": 173331
},
"hash": "3f9ea420af83450d7ef9f78b08c8af25b2213637"
}

This was answered by #KarenWhite, their developer evangelist in this thread.
https://support.bigcommerce.com/s/question/0D51B00004G6kJf/incoming-webhook-posts-hash-field-in-payload
It is hashed with SHA-1, but it is not signed with the client secret:
$payload['hash'] = sha1(json_encode($payload));
Additionally, the stance on webhook security is documented in the 2018 townhall
https://support.bigcommerce.com/s/article/BigCommerce-Town-Hall-February-2018
Q. How can I make sure that a webhook callback is initiated by BigCommerce only, and that the data is not altered between BigCommerce and my server endpoint? Can the hash returned in the webhook payload be used to verify the request?
A. Our webhooks today contain very little information -- they only contain an I.D. to go look up additional information. You would need to be authorized to verify that I.D. against the store’s API to determine the actual information being requested. We also secure our webhooks with TLS encryption, and enable developers to add their own headers to events for additional security.

I believe the hash is simply a unique identifier for an event.
One good reason to have this is when you ingest events, if you ever get duplicates from BigCommerce (which I've seen happen recently) you can tell that it's a duplicate based on the hash field.

I'd recommend using a custom header to validate the payload was from BigCommerce as noted in the getting started guide:
A headers object containing one or more name-value pairs, both string values (optional). If you choose to include a headers object, Bigcommerce will include the name-value pair(s) in the HTTP header of its POST requests to your callback URI at runtime. While this feature could be used for any purpose, one is to use it to set a secret authorization key and check it at runtime. This provides an additional level of assurance that the POST request came from Bigcommerce instead of some other party, such as a malicious actor.

Related

How to achieve the Dropbox equivalent of long-lived token now that they're gone (dropbox-sdk-js, Meteor, React)

For a while now I've been using dropbopx-sdk-js in a Meteor application without any trouble.
My Meteor app simply uses Dropbox to fetch images to be used in product cards. These files are synced now and then and that's it. By synced what I mean is they are scanned, shared links created or obtained, and some info is then saved in Mongo (name, extension, path, public link)
End users do not remove nor add files, nor are the files related to an end user specific account.
To achieve this, I created (in the far past) an App in the Dropbox App Console, generated a permanent token, and used that token in my Meteor app to handle all the syncing.
Now I've tried to replicate that very same thing in a new similar project, but found that the permanent tokens have been recently deprecated and are no longer an option.
Now, checking Dropbox's Authentication Types it seems to me like "App Authentication"
"This type only uses the app's own app key and secret, and doesn't
identify a specific user or team".
is what I'm after. I can safely provide app key and secret in the server exclusively, as the client will never need those. The question is how do I achieve such kind of authentication? Or for that matter, how do I achieve an equivalent of the long-lived token for my app, ultimately meaning that end users don't actually need to know Dropbox is behind the scenes in any way (and they surely don't need dropbox accounts to use this app nor should be prompted with any Dropbox authentication page)
In the js-sdk examples repo, I only found this example using app key and secret. Yet afterwards it goes through the oauth process in the browser anyways. If I don't do the oauth part, I get an error
"error": {
"name": "DropboxResponseError",
"status": 409,
"headers": {},
"error": {
"error_summary": "path/unsupported_content_type/...",
"error": {
".tag": "path",
"path": {
".tag": "unsupported_content_type"
}
}
}
}
as a result of calling
dbx.filesListFolders({ path: '', recursive: true }):
If I replace the initialization of the dbx object with a generated token everything works out. However eventually the token expires and I'm back in square one.
Any ideas what may I be missing?
The short answer is:
You need to obtain a refresh-token. You can then use this token for as long as you want. But in order to get it is necessary to go through at least one oauth flow in the browser. Then capturing the generated refresh-token in the backend. Then store it and use it to initialize the API. So it's kind of "hacky" (IMO).
For example, you can use the mentioned example code, and log/store the obtained refresh token in this line (as per Greg's accepted answer in the forum). Then use that value as a constant to immediately call the setRefreshToken method (as done in that very same line) upon initialization.
The long answer is:
ClientId + Client secret are not enough to programmatically generate a refresh token.
Going through the oauth flow at least once is mandatory to obtain a refresh token
If you want to hide such flow from your clients, you'll need to do what the short answer says.
The intended flow of usage according to Dropbox is: each user access his own files. Having several users accessing a single folder is not officially supported.
The longer answer is:
Check out the conversation we had in the dropbox forum
I suggested to replace the "Generate Access Token" button in the console for a "Generate Refresh Token" button instead. At least it made sense to me according to what we discussed. Maybe if it gets some likes... ;).

Why do webhooks use secrets? Why not use just SSL?

Standard practice is for an event-notification-service to give you a secret when you register your endpoint with them, and then the service signs the messages it sends to your endpoint with that shared secret, so that your server can verify the messages are legitimate.
However why is this necessary? Assuming your endpoint and the event-notification-service are both using HTTPS, shouldn't HTTPS take care of everything you need anyway, making this entire secret and signing process redundant? Is the idea to not rely on SSL-certificates, or allow clients to use endpoints that are not HTTPS?
The signing secret is here to ensure the event does come from Stripe. The signature is also associated with a specific timestamp to avoid "replay attacks".
Without the secret, I could figure out or guess the webhook handler that you built that expects for example the checkout.session.completed event and then I would send you a fake event evt_123 making it look like the payment succeeded for you to give me access to the product for example. There are some ways around this (hard to guess endpoint, allow list for Stripe's IP addresses, secret in the URL, etc.) but they all have downsides.
Similarly, if I can find the payload of an event that works, I could re-use the same exact payload (that I know is valid since you accepted it) and replay it say every day to continue getting daily access to some content. With the webhook signature logic that Stripe built, the signature is associated to a specific timestamp and you can for example reject events if the signature is more than 10 minutes old. Stripe covers this in their docs here.

Add instruction 'how' to perform a REST API request by adding header or body param?

Imagine a simple REST API that allows to create a user account, by sending a JSON resource to POST /users as in the following. By default it sends out a confirmation email to the user.
{
"username": "john#appleseed.com",
"password": "secret"
}
However sometimes there are good reasons for not sending out a confirmation based on the use case, e.g. another API client, or admins signing up users on their behalf.
Since it doesn't have any implications on the created resource but is more of an instruction how to create the user, should it be separate from the request body? What's the best way to do this?
Specify a custom header Confirmation: no-confirmation
Add a query param ?confirmation=false
Add a send_confirmation field to the request body
Let's take the options in order:
Adding a header value to indicate some semantic difference should be generally avoided. The API should be "browseable", meaning it should be discoverable following links only.
Adding a query parameter is, from REST perspective completely equal to creating another URI. It does not really matter how you expose it, the point is that the client needs to follow some links from the previous "state" it was in. This is actually ok, as long as the links to these resources indicate the different semantics you described: like creating users by admin, users creating themselves, etc.
Also note, that the API should not necessarily expose whether a confirmation is sent. The API should expose the "purpose", the server then can decide whether the use-case warrants a confirmation email.
Putting a send_confirmation in the JSON representation itself. This is ok, if this is a functionality available for the user. For example I can ask for a confirmation email. If I can't, and it is only used for differentiating different use-cases, then I would rather prefer option 2.
Summary: For the case you are describing I would pick option 2: different resources for admins and normal users.

What is the accepted practice for URL login in API REST?

If I have: users, and I need to log in with api rest. What's the best way to do it?
1 /users/id/password
2 /users?id=id&password=pass
If I use the second option, I will need to validate if there are get parameters. If not, It will return all results.
This is not the answer I want now:
REST API Login Pattern
The link you added is valid, REST APIs are stateless, so they can't login in the traditional way, you MUST store the client session on the client side. If you use HTTPs you won't need login. If you don't, then your API won't be secure, so using password won't have any protection. I think that's all.
If you want to both stay stateless and send tokens, then you have to sign for example the user id on the server. So by the next request you can send both the user id and the signature instead of the email and password. This way the server will know that you have been logged in earlier to the account the user id belongs to. I don't recommend you to use the URI for sending sensitive data. It is better to use the request body with POST. The URI structure depends on your taste, I would use something like this:
POST /users/1/tokens/ {email: "..", password: ".."}
201 {id: 1, expires: "..", signature: ".."}
Be aware that you have to send every variables you signed, so, the id, the expiration time (added by the server), probably the ip address, a random number, etc... You MUST not store anything on the server (including the token), otherwise the communication will be stateful.
I am not a security expert, but I think this solution does not make sense in most of the cases, so you need to justify somehow, why your API needs it. It is used for example for signing each request coming from 3rd party clients. If you cannot justify it, I recommend you to use the default approach, which is using HTTPS, logging in on the client side and sending HTTP Authorization header with email and password by every request.
I would use a POST method with the login / password provided within the payload:
POST /login
Content-Type: application/json
{ username: 'some username', password: 'some password' }
In addition, the following link could give you some hints about authentication within RESTful services:
Implementing authentication with tokens for RESTful applications - https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/
Hope it helps you,
Thierry

Should an API service send the user activation email or the client application?

I'm trying to develop a REST API web service. I have a question about how to handle user activation email. Currently, the API service handles email sending.
Here is the flow I have at the moment:
User registers via the client application
Client application POSTs to API service
API service validates and adds the user to the database
API service sends the User an activation link
User clicks on the activation link, which will take them to the client application activation page
Client application activation page POSTs to API service
Done
Here is where I currently see the issue:
Because the API service is currently sending the email, the client application does not have control over the look and feel of the email. And there may be URLs in the email that should point to the client application.
Another option is instead of the API service sending the activation email, it will return the activation key to the client application. The client application will then be able to send the activation email to the user.
Two issues I see with this strategy:
Security, as the activation key is now exposed to the client application.
Not DRY, as each client could be responsible for email sending.
What do you think is best way to handle this?
I would like to allow the client application to customize their email, as well as include client-specific URLs (activation page).
TL;DR
Create a small service for developers to create templates, let them declare which template they want to use when POSTing to your activation API
Summary of the problem:
e-mail needs to look different for every client app
sending mail should be implemented once
solution should be secure
There is no need for the e-mail to look different every time. So there's no need to send the e-mail format with the POST request.
Instead one of the following can be done:
1 Create a separate API endpoint to define templates and let the client app choose one of them when POSTing the request for activation.
This is not exactly secure, at least poses a challenge to make it safe if you want to accept HTML from the client apps.
Recommended solution:
2 Create a tool for developers (in the same website where they get their API key) that accepts templates and aids creating them. Client app can choose one of them when POSTing the request for activation. Fragment of the request body being something like:
...
"template": "foobar-app",
"fields": {
"title": "Welcome to foobar app",
"username": "jim78"
}
...
No HTML in the fields allowed.
This lets you have pre-defined templates prepared by the developer that can be used by your e-mail sending service and no bug in client app can cause the e-mail to become unsafe. Also, you get a place where the templates can be worked on and tested. (the developer can send them to himself to debug - making e-mail templates is horrible, belive me)
You'll be able to support your developers/clients better in the future and prepare a set of working templates tested in multiple mail clients.
A point about security and trust. Typically you send an activation email that contains a url link that has the activation code. The purpose of the email is to validate that the email is valid and that the user has access to that email. The only way the user could have received the verification link is through the email.
If you pass back the activation link to the client then anyone who has access to your API has access to the activation code. If they have access to the link they can bypass the verification process. This is really easy if you have a web app, as they just need to drop into the browser developer mode to see the link. If you have a fat client then they could snoop the network if you are not using encryption like https. They could also, if they were dedicated, decompile your binary (this is why you d not store keys in your binaries).
A backend should never trust a client to implement a security procedure because it never knows when it has been compromised. The safe and correct way is to do the activation email on the server side.
Another way to look at this, is that it is similar to the client saying "yes the user is authenticated so give me all the data"
As for the templates there are plenty of good answers above. I would suggest having a catalog of templates and a list of arguments that can be replaced.
So the way I achieved this in my opinion is quite a nice way. So I took the methodology of how JSON Web tokens work and applied it to my activation links. I'll explain how it works:
I have 2 web servers, one which handles the REST API, and one which handles the spa.
So the user registers, and the request is sent to the API. The response is then returned to the SPA at which point if successful sends a request to the SPA Backend which signs a token with the user's credentials, the purpose of the token (which is this case is to verify the email address) and it's expiry date.
This token is sent to the user's email address, however on the REST server there is a receiving route that will decode the token and if valid, verifies the email address.
This does mean that technically only 1st party clients can authenticate the email address as they are the only ones that can know your cipher secret. If your secret was freely handed out, then the problem would occur that anyone could verify their email address.
I hope this helps!
EDIT: another way would be to pass a template built in handlebars or something that swaps out variables for actual values. Then have the REST api render it, and email it. (This is probably the best way imo haha)
Your API could have an IEmailBodyFormatter object that is passed as a parameter to your API call....
I'd extend step 2 with additional post-data sent to the server:
"mail":{
"placeholder":"someStringChoosenByClientWhichWillBeReplaceByActivationCode",
"subject":"Hey there, please activate",
"ishtml":false,
"body":"SSdtIHRyeWluZyB0byBkZXZlbG9wIGEgUkVTVCBBUEkgd2ViIHNlcnZpY2UuIEkgaGF2ZSBhIHF1ZXN0aW9uIGFib3V0IGhvdyB0byBoYW5kbGUgdXNlciBhY3RpdmF0aW9uIGVtYWlsLiBDdXJyZW50bHksIHRoZSBBUEkgc2VydmljZSBoYW5kbGVzIGVtYWlsIHNlbmRpbmcu"
"attachments":[
{
"content-type":"image/png",
"filename":"inline_logo.png",
"content":"base64_data_of_image"
}
]
}
This would allow the client full control over sent message, but the activation procedure (mail generation & delivery) is still handled by the service.
Everything except the activation key can be generated for every user by the client (e.g. using "Hello XYZ" as Subject).
I'm not sure whether it's an good idea to allow html-Mails ("ishtml":false,), this depends on your application and the amount of time you want to spent implementing this.
Allow the client to manage their own email template(s). When they post a new user registration, allow them to specify which template to use. Then your application is sending the email message, but clients can control what it looks like.
POST /email-templates
{
"subject": "Complete Your Registration",
"body": "<html>Follow this link to complete your registration: {activationLink}. It is valid for 45 minutes.</html>"
}
POST /registration-requests
{
"name": "John Q. Public",
"emailTemplate": "/email-templates/45"
}
I think the proper way is to expose the activation key for the client to do whatever it wants with.
You could also add another endpoint to send the activation key for the user.
Returns user. (with the url like User/{userid} and other resources url like User/{userid}/ActivationKey)
User (POST)
This can returns the current user and other resources like Email, Activate, etc.
For info about the key (like dates, expiration, etc)
User/{userid}/ActivationKey
from there you can extend it as long as you want with :
Preview activation email:
User/{userid}/ActivationKey/Email (GET)
Update activation email with template, smtp server, etc of the email. :
User/{userid}/ActivationKey/Email (PUT)
Create (and send) activation email, possible with date to send or other send options (text-html versions, etc) :
User/{userid}/ActivationKey/Email (POST)
You could possibly list all email sent and preview them in another endpoint if necessary.
User/{userid}/Emails (GET)
User/{userid}/Emails/{emailid} (GET)
I join nauktur on the idea of letting the client send you a template of his email. (And +1 for talking about a way to test, because I agree on the awfulness of mail "development").
But why so complicated ? Client apps mean developers, so why not let them give them your default template (with HTML), let them play around if they want to, and send you back the version they prefer ?
It's not a lot of work for you (just a new field in the client table and a new route), and it gives them a lot of options.
Here is a basic example where we'll be exposing some parameters so that they can play around with the HTML without even having to know them :
app.name
app.description
activation_code
user.* registering info
Basic template
{
title: "Your activation code for %{app.name}",
body: "<p>Hi, you've been registered on %{app.name}.
<p>%{app.description}</p>
<p>Follow this link to confirm your inscription."
}
Register new template
Then the client says : "I prefer to have a more simple mail, but I want his name in it !".
[PUT] /api/email/templates/client_id
{
title: "Your activation code",
body: "<p>Hi %{user.fullname}, Follow this link to confirm your inscription."
}
And here you go. Let them play with HTML, it allows way more personalization.
There's no harm in it except for their image on their clients if they mess up, but they're their clients.
Security issues
It was pointed out that attackers could get access to the token of the client app could inject malicious content in the template. First of all, the risk is already so high if the token leaks, that this is the last of your concerns. Still, if you're scared of this, disallowing img tags and making the content of a tags match the href attribute should solve your issue.