From the Archives: 2016: Setting Up Braintree Token Web Service
This is a quick guide to show you how to get a tokenizer webservice running on linux with Nginx/Flask/Python
I came across this just as we started rounding the payment corner of our first iOS app build. We’re using braintree as our payment gateway, and for newcomers it can be a bit confusing piecing together documentation.
So with that in mind here is a full guide to get the necessary token piece working with BrainTree!
I originally assumed that clients used an api key to talk to braintree on our behalf, send credit card info and process transactions all in one shot. Wrong!
Braintree requires that each client request and generate a current ‘token’ before talking to Braintree servers to process a payment transaction. This is kind of like requesting a current session. Makes sense to me! How do we do it?
Spin up a server if you have one. I use Digital Ocean mostly and fstservers for virtual machines.
The architecture:
If you look at Braintree’s documentation, they give you several server side SDKs to use. And it’s one simple method call to ‘generate a token’ using your gateway api keys as identification for your app.
**Note at this point if you haven’t signed up for a sandbox account on Braintree you need to do this in order to get your API keys.***
The flow is simple, from WHATEVER you’re processing payments on (web browser, iphone, spaceship etc.) you need to send an http GET request to your server asking for a token. Your server then will work it’s magic and provide you with a response that is your token. Simple!
For the unitiated, an http GET is what you do anytime you go to a url/link in your browser. When you type in “google.com” into your web browser, the browser is sending a GET request to a google server saying “please give me the google home page”
So to acheive this same behavior we need two things
A web server that we can access from our client
Python code to actually generate the token
First let’s get the python code up and running:
The Braintree SDK:
Braintree actually provides this for you, first install their python package
**From Braintree***
wget pypi.python.org/packages/source/r/requests/requests-2.2.1.tar.gz
tar zxf requests-2.2.1.tar.gz
cd requests-2.2.1
python setup.py install
Nice! Now let’s start our script that will be generating the tokens
##################################################
import braintree
braintree.Configuration.configure(braintree.Environment.Sandbox,
merchant_id="use_your_merchant_id",
public_key="use_your_public_key",
private_key="use_your_private_key")
##############################################
Configuration complete! That’s all you need to do upfront. Now the next step is to set up a web service to:
Accept an http GET request
Generate a token
Return the token to the requestor
To do this we need a web server! I chose to use Flask, a python web framework that is designed to be tiny and simple. Because of this we can get up and running in under a minute! Read more here http://flask.pocoo.org/
Flask
Install flask with pip
$pip install flask
Now in the same file as our braintree python code define what’s called a ‘Route’
If you’re unfamiliar with a route, it refers to what comes after the slash in a url. so google.com/myroute the route there on google’s server is ‘myroute’
For this example we want to generate a token when the request is sent with ourserverIPaddress/client_token
So we write:
################################################################
@app.route("/client_token", methods=["GET"])
def client_token():
return braintree.ClientToken.generate()
###############################################################
This will accept that http GET request we talked about earlier, and calls a braintree function called generate() which will respond to the request with a shiny new token!
Make sure you import flask in the file too! The whole code for flask looks like this.
##########################################
from flask import Flask
app = Flask(__name__)
@app.route("/client_token", methods=["GET"])
def client_token():
return braintree.ClientToken.generate()
if __name__ == "__main__":
app.run()
########################################################
Great! Now we can fire up our new flask web server! You should get something like this…
root@web1:~# python mybrain.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Success! You have a web server that will generate tokens running locally on port 5000.
As of now we have a working implementation, but right now our little server is only accessible locally; that is it only accepts requests that originate on the same server. Not very helpful.
Let’s use Nginx to open this up to the world!
Nginx is a great web server that can handle lots of requests all at once, and it’s quite useful to use especially if you’re planning on running other apps/websites on this token server.
If you know how to setup Nginx to proxy requests to a local port, do so! If not I’ll walk through the steps:
Install Nginx
Redhat/CentOS etc.
$yum install nginx
Ubuntu/Debian
$sudo apt-get install nginx
Create a new file called braintree (any name is fine) this will be the config file that Nginx uses to properly handle requests meant for our token generator flask server
Here is mine:
root@web1:~# vi /etc/nginx/sites-available/braintree
######################################################
#server_tokens off;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
#http
server {
listen 5050; # if this is not a default server, remove "default_server"
listen [::]:5050 ipv6only=on;
root /usr/share/nginx/html; # root is irrelevant
index index.html index.htm; # this is also irrelevant
# server_name boramash.com; # the domain on which we want to host the application. Since we set "default_server" previously, nginx will answer all hosts anyway.
# redirect non-SSL to SSL
# location / {
# rewrite ^ https://$server_name$request_uri? permanent;
# }
location / {
proxy_pass http://127.0.0.1:5000; # local python token flask server
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; # allow websockets
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-For $remote_addr; # preserve client IP
# this setting allows the browser to cache the application in a way compatible with Meteor
# on every applicaiton update the name of CSS and JS file is different, so they can be cache infinitely (here: 30 days)
# the root path (/) MUST NOT be cached
if ($uri != '/') {
expires 30d;
}
}
}
What this config does is it tells Nginx to wait for incoming GET requests on port 5050, then pass those requests on to 127.0.0.1:5000 which if you recall is where our local flask server is running. Simple enough? Let’s active the site.
Nginx assumes that all files located in the /etc/nginx/sites-enabled directory are ready to be live and tries to run them.
This is why we put our file in /etc/nginx/sites-available first. When it’s ready we create what’s called a symbolic link to that file we wrote. A symbolic link is just a reference in linux.
root@web1:~# cd /etc/nginx/sites-enabled
root@web1:~# ln -s /etc/nginx/sites-available/braintree braintree
You should see a new file called ‘braintree’ created in the /sites-enabled folder. This is our link to /etc/nginx/sites-enabled/braintree
Restart nginx and our config will be live!
root@web1:/etc/nginx/sites-enabled# service nginx restart
* Restarting nginx nginx [ OK ]
root@web1:/etc/nginx/sites-enabled#
Now from another server you can test by using wget to send an http GET request.
Make sure that your flask server is still running, and go to a web browser to request a new token!
Success! We now have a fully functioning web server running Flask/Python with a Nginx front end proxy.
I will post more tutorials on end to end Braintree payment configuration as our app development progresses. Stay tuned!
Bonus for ubuntu users!
This is great you may say, but now each time I reboot my server I have to logon and manually start the Flask server. Annoying.
Let’s use Ubuntu’s Upstart to run our Flask server as a service.
Read about upstart here http://upstart.ubuntu.com/
Create a new file in the init directory:
root@web1:/root# vim /etc/init/braintree.conf
##############################################
description "Braintree token server"
author "Ethan Drower <ethandrower@gmail.com>"
start on started nginx and runlevel [2345]
stop on shutdown
respawn
respawn limit 10 5
#setuid braintree
#setgid braintree
script
export PATH=/opt/local/bin:/opt/local/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
exec python /opt/mybrain.py >> /opt/brainlog.log
end script
########################################
Save the file and start the service!
root@web1:/opt # start braintree
Any questions? Comment or email me!