Skip to content

Commit e3dce26

Browse files
Updated docs to reflect new CSRF and cookie change
Docs are now up to date with what parameters are allowed in each of the Kvasir endpoints.
1 parent 48be7c6 commit e3dce26

File tree

3 files changed

+20
-17
lines changed

3 files changed

+20
-17
lines changed

docs/backend.rst

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ When the front-end makes a request, the back-end is responsible for formatting i
2222

2323
The server is also responsible for :ref:`packaging responses back to the client, including error messages <back-end_sendingdatabacktoclient>`. Every response is sent through the same function to ensure a level of consistency in the way that we report data back to the front-end. Typically, valid data is simply sent to the front-end in the same format in which it was received. The error structure is little more specific, but will also pass along the original, unaltered response as part of it.
2424

25-
Kvasir's node server also manages a small cookie based session for users. We don't want to expose access tokens to the front-end, but we also don't want to have to request the access token from the partner's database on each request. After the server gets an access token, it will set a hashed cookie based on a secret key provided in Kvasir's configuration file. The cookie cannot be accessed by the front-end, and the only the server can unhash it into something readable.
25+
Kvasir's node server also manages cookies on the client's browser. Right now, the only cookie is a CSRF cookie used to manage our CSRF protection. The cookie has the ``secure`` and ``httpOnly`` flags set so that the cookie must be set over HTTPS, and it cannot be accessed by client side JavaScript. Additionally, the CSRF token is placed in the HTML of the page itself via our templating engine.
2626

2727
Endpoints
2828
-----------
2929
Each front-end object has an associated endpoint on the server. An object *could* call another endpoint if it wanted to, but it is more likely to do that indirectly by dispatching that other object's actions.
3030

31-
All endpoints *only* accept POST requests with a JSON structured body.
31+
All endpoints *only* accept POST requests with a JSON structured body and will verify that they contain a CSRF token.
3232

3333
User Endpoint
3434
~~~~~~~~~~~~~~~
@@ -60,8 +60,13 @@ If no account_id is provided, the endpoint will make a request to :wepay:`accoun
6060
6161
Get information about an account
6262

63+
:<json email: *(optional) used to get a merchant's access token from the middleware. If account_id is not passed, then this endpoint will fetch all accounts registered to this user.
6364
:<json account_id: *(optional)* the account_id assoicated with the account that you want more info for.
6465

66+
.. note::
67+
If the account_id is provided, then this endpoint will use the account_id to gather the merchant's access token. You can still pass an email, but it is not required.
68+
69+
6570
Checkout Endpoint
6671
~~~~~~~~~~~~~~~~~~~~
6772
Very similar to the :http:post:`/account`, except it looks at :wepay:`checkout` instead. If no checkout_id is provided, it will gather the 50 most recent checkouts for the given account_id. If a checkout_id is provided, then it will only fetch information regarding that one checkout.
@@ -71,7 +76,7 @@ Very similar to the :http:post:`/account`, except it looks at :wepay:`checkout`
7176
Get a list of checkouts made for a given account_id, or get information about a single checkout_id
7277

7378
:<json checkout_id: *(optional)* the unique id of the checkout you want to search
74-
:<json acccount_id: *(optional)* the unique id of the account that you want a list of checkouts for
79+
:<json acccount_id: used to get a merchant's access token. If the checkout_id is not passed, then this endpoint will fetch all
7580

7681
.. note::
7782
While both parameters are optional, you must provide one or the other.
@@ -84,7 +89,7 @@ We could have built the withdrawal endpoint in the same way that we built the :h
8489
8590
Get withdrawal info for a given account_id
8691

87-
:<json account_id: the unique id of the account you want to gather withdrawals from
92+
:<json account_id: the unique id of the account you want to gather withdrawals from (also used to fetch a merchant's access token from the middleware)
8893

8994
Refund Endpoint
9095
~~~~~~~~~~~~~~~~~
@@ -97,6 +102,7 @@ Refunds are a complicated area. The refund logic changes depending on who the *
97102
Do a full or partial refund for a given checkout
98103

99104
:<json checkout_id: the id of the checkout you want to refund
105+
:<json account_id: the account that we are performing a refund for. Used to fetch a merchant's access token from the middleware
100106
:<json refund_reason: the reason you are refunding the checkout
101107
:<json amount: *(optional)* how much you are refunding the checkout for. If no amount is passed, a full refund is completed
102108

@@ -110,7 +116,7 @@ This endpoint will gather the reserve information about an account from :wepay:`
110116
111117
Get reserve information about a particular account
112118

113-
:<json account_id: the id of the account you want reserve information for.
119+
:<json account_id: the id of the account you want reserve information for (also used to fetch a merchant's access token from the middleware)
114120

115121
Payer Endpoint
116122
~~~~~~~~~~~~~~~~~~
@@ -167,18 +173,13 @@ Each endpoint on Kvasir's server is responsible for creating the call to :func:`
167173

168174
Managing Access Tokens
169175
~~~~~~~~~~~~~~~~~~~~~~~~~
170-
We wanted to avoid a system that had to make a request to the partner's database for a user's access token for each request. While this would certainly work, it increases the overhead of each request unnecessarily.
176+
Access tokens are a very sensitive matter. If someone were to gain access to a merchant's access token, they could do a lot of damage with it.
171177

172-
Kvasir uses Express's `cookie_session <https://github.com/expressjs/cookie-session>`_ library to securely store a user's access token as a cookie in the client's browser. The cookies are hashed with a secret key and set with the *secure* and *httpOnly* flags. These force the cookies to be sent only over an HTTPS connection, and prevent JavaScript functions in the browser from being able to access the cookie information.
173-
174-
From within Kvasir's ExpressJS server, the cookie is accessed via:
175-
>>> req.session.access_token
176-
177-
Most of the endpoints will check if this value is set before making any requests to WePay. If the access token is not present, Kvasir will raise an error back to the client saying that it cannot perform the request because it does not have all of the required info.
178+
In order to prevent this from occurring, we fetch the access token on each request from the partner's database. This has small performance issues, but realistically, it's not terrible. It's really the main function of the middleware, so you should build it with performance in mind.
178179

179180
Getting Data From the Middleware
180181
-------------------------------------
181-
In order to be able to get information such as access tokens and a list of all checkouts a payer has completed on a given platform, Kvasir uses the idea of a platform generated middleware that allows it to communicate with a platform's database.
182+
In order to be able to get information such as access tokens and a list of all checkouts a payer has completed on a given platform, Kvasir uses the idea of a :ref:`platform generated middleware <kvasirmiddleware>` that allows it to communicate with a platform's database.
182183

183184
The ExpressJS server has two functions for communicating with the middleware.
184185

@@ -207,7 +208,7 @@ The ExpressJS server has two functions for communicating with the middleware.
207208
:param wepay_package: The package to send to the wepay_endpoint
208209

209210

210-
First Kvasir will call :func:`getDataFromMiddleware` where necessary. This will send a associated POST request to the platform's middleware to get the information we need. Once it receives the response it will pass the information to the callback function provided.
211+
First Kvasir will call :func:`getDataFromMiddleware` for every endpoint that requires a merchant's access token (which is almost all of them). This will send a associated POST request to the platform's middleware to get the information we need. Once it receives the response it will pass the information to the callback function provided.
211212

212213
Most of Kvasir's endpoints will use :func:`parseMiddlewareResponse` to do that. When we go to the middlware it is likely because we want a user's access token and then be able to do an associated call to the WePay API. :func:`parseMiddlewareResponse` will do that for us. It will pull the access token out of the response and format a request to :func:`getWePayData` (which will subsequently send the data to the client).
213214

@@ -328,3 +329,6 @@ The config file allows you to specify where the certificate and key are stored.
328329
If you need help creating a self-signed SSL certificate, you can follow this tutorial:
329330
https://devcenter.heroku.com/articles/ssl-certificate-self
330331

332+
Templating Engine
333+
~~~~~~~~~~~~~~~~~~~~
334+
Kvasir uses `EJS <https://www.npmjs.com/package/ejs>`_ for our templating engine. The main purpose of the templating engine is to allow us to embed the server side generated CSRF token in the HTML.

index.ejs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<!-- application script -->
3636
<script src="/static/bundle.js"></script>
3737
<script>
38+
/*make all ajax calls pass the CSRF token via a header back to the client*/
3839
$.ajaxSetup({
3940
headers: {"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr('content')}
4041
})

server.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,7 @@ app.set("view engine", "ejs");
7575
* So refreshing the page effectively kills all session information.
7676
*/
7777
app.get("/", csrfProtection, function(req, res) {
78-
// make sure the session is null each time we reload the page
79-
// dont want things persisting when people come back
80-
req.session = null
78+
// render the main page with the csrf token
8179
res.render((__dirname + '/index.ejs'), {csrfToken: req.csrfToken()});
8280
})
8381

0 commit comments

Comments
 (0)