Skip to main content
Copy-ready implementations of the routes from the BitRobot Connect guide.

Backend implementations

Each example implements GET /bitrobot/connect and POST /bitrobot/connect/confirm, stores request_id and nonce in the server-side session, and reads BITROBOT_API_KEY, BITROBOT_SUBNET_ID, and BITROBOT_API_BASE from the environment. Replace the login guard (requireLogin, current_user, and so on) with your own. If your API is stateless, use the stateless hold instead of the session. The confirm route must reject any request without a valid CSRF token. The Sinatra, Laravel, Spring Boot, and ASP.NET examples use their framework’s own guard. In the Express, FastAPI, and Go examples, replace the CSRF guard placeholder with your own, the same way you replace the login guard.

Stateless hold

If your API is stateless, store request_id and nonce in a table instead of the session. Keep one row per user, replace it on each new start, and check expiry on read.

Pages you render

Two pages: the connect page the user lands on, and an error page.

Connect page

Show the wallet address in full and one button that POSTs to your confirm handler. Include your framework’s CSRF token in the form. HTML-escape {{WALLET_ADDRESS}} wherever you substitute it.
In the React version, pass csrfToken in from your server: render it into the page, or serve it from a GET endpoint the page fetches before it posts. It sends the token as X-CSRF-Token — send whatever header your guard reads instead if it differs. The ASP.NET example above reads the __RequestVerificationToken form field, not a header.

Error page

HTML-escape {{ERROR}} and {{REASON}} wherever you substitute them.
Plain HTML

Returning from login

Store the destination, query string included, before redirecting to login, and return the user to it after sign-in.
For server-rendered apps, store request.fullpath before the login redirect and redirect to it afterwards. Accept an in-app path only:

Tests

RSpec examples against the connect page and a confirm handler that returns JSON. park_attempt stores a hold for user; confirm_url, success_body, callback_url, and auth_code are fixtures. Translate the assertions to your framework. 1. The handler ignores a request_id and nonce supplied by the caller.
2. One user’s hold is unusable by another.
3. A lapsed hold is treated as no hold.
4. return_url passes through byte for byte, fragment included.
5. The connect page escapes the wallet address.
6. The authorization code appears only inside return_url, and never in logs.
Also cover:
  • A confirm POST without a valid CSRF token is refused.
  • An error or reason containing HTML is escaped on the error page.
  • A 409 already_confirmed with auth_code is treated as success.
  • A 200 without auth_code is treated as a failure.
  • A non-http(s) return_url is refused.
  • The hold is cleared after a successful confirm and kept after a failed one.