v0.2.0 — six languages, one payment
The same Hosted Fields payment, now written six times. v0.1.2 had one example; this release has
one per language, and the point of having more than one is that the interesting half — the card
iframes, the tokenization, the 3DS return — happens in the page, and the server behind it is
interchangeable.
| Server | Runs with | |
|---|---|---|
| Go | standard library only | one static binary, no runtime |
| Node.js | express only | Node 20+, no node_modules |
| PHP | no Composer at all | PHP 8.4+, php -S or PHP-FPM |
| Python | Flask + cryptography | Python 3.12+, python app.py or gunicorn |
| Ruby | Sinatra + puma | Ruby 3.1+, ruby app.rb or puma |
| Next.js | React 19, TypeScript | Node 20+, the page is a React tree |
What is new since v0.1.2
Four more examples. Next.js and React first, then PHP, Python on Flask and Ruby on Sinatra.
Each implements exactly the same seven routes and nothing else, and each documents the traps its
own language sets — PHP's $_POST renaming parameters, Python's urlopen raising on the 4xx that
carries a decline, Sinatra's http_origin protection rejecting the gateway's own 3DS callback.
The browser half lives once. shared/ is the source of truth for the stylesheet, the three
client scripts and the two pages, and scripts/sync-shared.sh copies it into every app. The
copies stay committed, so each directory still runs on its own with no pre-step, and CI fails a
copy that has drifted. Nothing in views/ is templated any more: the only thing any of these
servers generates is config.js, which is what lets the same HTML serve from all six.
Security work across every example. A Content-Security-Policy with no 'unsafe-inline',
naming the SDK origin in script-src, frame-src and connect-src; the 3DS return verified
twice over the same checksum, so a hand-edited URL gets a 403 instead of somebody else's order;
the POST /pay body filtered against a fixed list of eight customer_browser_* keys, so a caller
cannot choose what to charge; a CSPRNG client_orderid; loopback binding by default; and gateway
reply bodies kept out of the logs, which had been carrying the card's last four digits and the
holder's name.
An end-to-end suite. e2e-tests/ starts a fake gateway on one origin — both the API the
servers call and the SDK the browser loads — points every app at it through the environment, and
drives a real browser through the payment: the happy path, the SDK's field-state classes,
validation before tokenizing, a missing ticket, a refused Sale, a decline, the 3DS hop out to the
issuer and back through the signed callback, and forged signatures. Sixty tests, ten per app. The
OAuth signature is verified against a generated public key and the Sale's amount is checked
against the server's own, so a green run means the handshake works rather than that a page
rendered. It is local only — it needs every toolchain and a browser.
Which archive to take
Example integrations of Hosted Fields: the same payment, one server per language.
hosted-fields-examples-go_*_linux_*.tar.gz— one static binary with the pages
embedded, plusdeploy/. Needs no runtime.hosted-fields-examples-go_*_darwin_arm64.tar.gz,
hosted-fields-examples-go_*_windows_amd64.zip— the same binary for trying the
example on a laptop. Nodeploy/: the systemd unit and the nginx snippet are for
a Linux server.hosted-fields-examples-nodejs-express-js_*.tar.gz— bundledserver.jswith
public/,views/anddeploy/. Needs Node 20+, nonode_modules.hosted-fields-examples-php.tar.gz— the sources withpublic/,views/and
deploy/. Needs PHP 8.4 with curl and openssl, no Composer:php -Sfor a look,
PHP-FPM behind nginx for anything else.hosted-fields-examples-python.tar.gz— the sources withtests/,public/,
views/anddeploy/. Needs Python 3.12+ and, unlike the others, a
pip install -r requirements.txtinto a venv on the target; then gunicorn.hosted-fields-examples-ruby.tar.gz— the sources withtest/,public/,
views/anddeploy/. Needs Ruby 3.1+ and abundle installon the target, then
puma. Note that macOS's system Ruby 2.6 will not run it.hosted-fields-examples-nextjs.tar.gz— the standalone Next.js server with
public/,.next/anddeploy/. Needs Node 20+,node server.js. The URL
prefix is compiled in: rebuild from source to change it.
Settings and the RSA key are supplied through the environment, see the README.
What's Changed
- Add a Hosted Fields example on Next.js and React by @evsinev in #1
- Share the browser half from shared/, and drop templated views by @evsinev in #2
- Act on the review of eca9448: 3DS return, browser-field allowlist, and the rest by @evsinev in #3
- test: add a local e2e suite for all three examples by @evsinev in #4
- Add a PHP example by @evsinev in #5
- Add a Python (Flask) example by @evsinev in #6
- Add a Ruby (Sinatra) example by @evsinev in #7
New Contributors
Full Changelog: v0.1.2...v0.2.0