From 2487d8a2f95bdc0dd59c5f717a4e901dfdd8d456 Mon Sep 17 00:00:00 2001 From: jeanGaston Date: Mon, 13 Apr 2026 10:34:52 +0200 Subject: [PATCH] docs: README with full setup guide Covers: Enable Banking signup, RSA key generation, running setup script, docker-compose wiring, OAuth redirect flow diagram, supported French banks, and troubleshooting. Co-Authored-By: Claude Sonnet 4.6 --- README.md | 227 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c64079e --- /dev/null +++ b/README.md @@ -0,0 +1,227 @@ +# actual-gocardless-proxy + +A drop-in [GoCardless Bank Account Data API](https://developer.gocardless.com/bank-account-data/quick-start-guide/) proxy server that lets [Actual Budget](https://actualbudget.org/) sync with French (and other European) bank accounts via [Enable Banking](https://enablebanking.com/) — a **free** PSD2 aggregator. + +**Zero modifications to actual-server.** The only change is setting one environment variable: + +``` +GOCARDLESS_BASE_URL=http://gocardless-proxy:3456 +``` + +## How it works + +``` +Actual Budget (browser) + │ GoCardless API calls + ▼ +actual-server + │ GOCARDLESS_BASE_URL → http://gocardless-proxy:3456 + ▼ +gocardless-proxy ◄── this repo + │ Enable Banking PSD2 API + ▼ +Enable Banking → French banks (BNP, SG, CA, LCL, BP, …) +``` + +The proxy translates GoCardless API shapes ↔ Enable Banking shapes on the fly and persists all state (tokens, requisitions, account mappings) in `./data/store.json` so Docker restarts don't break existing account links. + +--- + +## Setup + +### 1. Sign up for Enable Banking + +Go to [enablebanking.com](https://enablebanking.com) and create a **free personal account**. Under your app settings, note your **Application ID**. + +### 2. Generate an RSA key pair + +Enable Banking uses RS256 JWT auth. You need to provide your **public key** in the Enable Banking dashboard and keep the **private key** on your server. + +```bash +# Generate a 2048-bit RSA private key in PKCS8 format +openssl genpkey -algorithm RSA -pkcs8 -out private_key.pem -pkeyopt rsa_keygen_bits:2048 + +# Extract the public key (upload this to Enable Banking) +openssl pkey -in private_key.pem -pubout -out public_key.pem +``` + +Upload `public_key.pem` in the Enable Banking dashboard under your application's API settings. + +Keep `private_key.pem` somewhere safe — you'll need it in the next step. + +### 3. Run the setup script + +Clone this repo and install dependencies: + +```bash +git clone https://github.com/yourname/actual-gocardless-proxy +cd actual-gocardless-proxy +npm install +``` + +Run the interactive setup: + +```bash +npm run setup +``` + +The script will ask for: +- Your Enable Banking **Application ID** +- Path to your **private key PEM** file +- The **proxy base URL** (the URL that Enable Banking will redirect to after OAuth — must be reachable from your browser; e.g. `http://localhost:3456` for local dev or `https://yourserver.example.com` for production) + +It will generate a random `secret_id` and `secret_key` pair and print them: + +``` +────────────────────────────────────────────────────────── +Enter these values in Actual Budget → Settings → GoCardless: + + Secret ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + Secret Key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +And set this environment variable on actual-server: + + GOCARDLESS_BASE_URL=http://gocardless-proxy:3456 +────────────────────────────────────────────────────────── +``` + +All credentials are stored in `./data/store.json`. + +### 4. Add the proxy to your docker-compose.yml + +In your existing `actual-server` `docker-compose.yml`, add the proxy service and wire it to actual-server: + +```yaml +services: + actual-server: + image: actualbudget/actual-server:latest + # ... your existing config ... + environment: + GOCARDLESS_BASE_URL: http://gocardless-proxy:3456 + # ... your other env vars ... + depends_on: + - gocardless-proxy + + gocardless-proxy: + build: /path/to/actual-gocardless-proxy + # or: image: ghcr.io/yourname/actual-gocardless-proxy:latest + container_name: gocardless-proxy + restart: unless-stopped + volumes: + - /path/to/actual-gocardless-proxy/data:/app/data + environment: + PORT: 3456 +``` + +> **Note on PROXY_BASE_URL:** The proxy base URL is saved in `data/store.json` during setup. If you need to change it later (e.g. you added a reverse proxy), re-run `npm run setup` or edit `data/store.json` directly and update `config.proxy_base_url`. + +### 5. Start the services + +```bash +docker compose up -d +``` + +Verify the proxy is running: + +```bash +curl http://localhost:3456/health +# → {"status":"ok","configured":true} +``` + +### 6. Configure Actual Budget + +In Actual Budget, go to **Settings → GoCardless** and enter the `secret_id` and `secret_key` printed in step 3. + +You can now go to **Accounts → Link account** and search for your French bank. + +--- + +## OAuth redirect flow + +``` +1. actual-server POST /api/v2/requisitions/ { redirect: "http://actual:5006/..." } + ↓ +2. proxy POST https://api.enablebanking.com/auth + { aspsp: { name, country }, redirect_url: "http://proxy/callback", + state: } + ← { url: "https://tilisy.enablebanking.com/..." } + ↓ +3. proxy returns requisition with link = EB auth URL + ↓ +4. User visits the link, authenticates at their bank + ↓ +5. Enable Banking redirects → http://proxy/callback?code=xxx&state= + ↓ +6. proxy POST https://api.enablebanking.com/sessions { code } + ← { session_id, accounts: [uid, ...] } + → fetches account details, stores GC account IDs + → marks requisition status "LN" (linked) + → redirects → http://actual:5006/...?requisition_id= + ↓ +7. actual-server GET /api/v2/requisitions// + ← { status: "LN", accounts: ["gc-acc-id-1", ...] } + ↓ +8. actual-server GET /api/v2/accounts//details/ + GET /api/v2/accounts//balances/ + GET /api/v2/accounts//transactions/ +``` + +--- + +## Supported banks + +All French banks supported by Enable Banking, including: + +| Bank | BIC | +|------|-----| +| BNP Paribas | BNPAFRPP | +| Société Générale | SOGEFRPP | +| Crédit Agricole | AGRIFRPP | +| LCL | CRLYFRPP | +| Banque Populaire | various | +| Caisse d'Épargne | various | +| La Banque Postale | PSSTFRPPPAR | +| Crédit Mutuel | CMCIFRPP | +| CIC | CMCIFRPP | +| Boursorama | BOUSFRPPXXX | +| Fortuneo | FTNOFRP1 | +| Hello bank! | BNPAFRPP | + +See [enablebanking.com/docs/markets/fr/](https://enablebanking.com/docs/markets/fr/) for the full list. + +--- + +## Troubleshooting + +### "Proxy not configured" error +Run `npm run setup` and restart the container. + +### "Unknown institution_id" when creating a requisition +actual-server caches institutions. Go to **Settings → GoCardless → Reset** and re-fetch banks. + +### OAuth callback fails with "Enable Banking error" +- Make sure `proxy_base_url` in `data/store.json` is reachable from your browser (not just from Docker). +- Check that the redirect URL is whitelisted in your Enable Banking application settings. + +### Transactions not appearing +Enable Banking may return an empty `transactions` array for accounts with no activity in the requested date range. Try widening the date range. + +### Private key errors +Make sure the key is **PKCS8** format. To convert from traditional RSA format: +```bash +openssl pkcs8 -topk8 -nocrypt -in old_key.pem -out private_key.pem +``` + +--- + +## Data & privacy + +All bank credentials and tokens stay on your server inside `./data/store.json`. Nothing is sent to any third party except Enable Banking (which is the PSD2 provider) and your bank. + +The `data/` directory is git-ignored and should not be committed. + +--- + +## License + +MIT