114 lines
4.3 KiB
Markdown
114 lines
4.3 KiB
Markdown
# Backend — when and how to add server-side logic
|
||
|
||
## When you need a backend
|
||
|
||
You need a backend if your app needs to:
|
||
|
||
- Store data long-term (user preferences, linked accounts, custom records)
|
||
- Call APIs that require server-side secrets (API keys that can’t be in the browser)
|
||
- Run logic when the user isn’t in the Dashboard (webhooks, scheduled jobs)
|
||
- Call third-party services securely (email providers, CRMs, spreadsheet APIs)
|
||
- Perform actions that take longer than the UI can wait for
|
||
|
||
**You don’t need a backend if:**
|
||
|
||
- Your app only reads and displays Stripe data (use the SDK client directly in the UI)
|
||
- You only need to store a small amount of sensitive data — use the Secret Store API instead
|
||
|
||
## Canonical documentation
|
||
|
||
Before writing backend code, read these pages using WebFetch:
|
||
|
||
| Topic | URL |
|
||
| --- | --- |
|
||
| Backend implementation + fetchStripeSignature | https://docs.stripe.com/stripe-apps/build-backend |
|
||
| Authentication types (determines backend pattern) | https://docs.stripe.com/stripe-apps/api-authentication |
|
||
| Events and webhooks | https://docs.stripe.com/stripe-apps/events |
|
||
| Secret Store API | https://docs.stripe.com/stripe-apps/store-secrets |
|
||
|
||
## Backend architecture decisions
|
||
|
||
### Authentication type determines the backend pattern
|
||
|
||
Your app’s `stripe_api_access_type` controls how the backend authenticates. See `authentication.md` for the full breakdown of auth types and when to use each one.
|
||
|
||
### CORS configuration
|
||
|
||
CORS (`Access-Control-Allow-Origin: *`) is needed ONLY on endpoints called by the UI extension. The UI runs in a sandboxed iframe with a `null` origin — specific origin allowlisting will not work.
|
||
|
||
Webhook endpoints do NOT need CORS — they receive requests from Stripe’s servers, not from the browser.
|
||
|
||
### fetchStripeSignature verification
|
||
|
||
`fetchStripeSignature` is how the UI extension authenticates requests to your backend. The signed payload and verification method are documented at https://docs.stripe.com/stripe-apps/build-backend.
|
||
|
||
Key facts:
|
||
|
||
- The signing secret (starts with `absec_...`) is generated on first `stripe apps upload`
|
||
- The default signed payload contains `user_id` and `account_id` (field order matters)
|
||
- Extra data can be included by passing it to `fetchStripeSignature(payload)`
|
||
- Verification uses `stripe.webhooks.signature.verifyHeader()`
|
||
|
||
### Webhook configuration
|
||
|
||
Webhook setup depends on your app’s distribution and auth type:
|
||
|
||
| App type | Webhook setup |
|
||
| --- | --- |
|
||
| Private (your account only) | ONE standard webhook endpoint |
|
||
| Public with platform keys | ONE webhook with “Listen to events on Connected accounts” enabled |
|
||
| Public with restricted API keys | Can’t use Connect webhook fanout — each merchant manages their own webhooks |
|
||
|
||
The `event_read` permission MUST be declared in your manifest, plus read permissions for each event type you want to receive.
|
||
|
||
Read https://docs.stripe.com/stripe-apps/events for the full setup guide.
|
||
|
||
For firewall allowlisting of inbound webhook traffic, see https://docs.stripe.com/ips for Stripe’s IP addresses.
|
||
|
||
## Secret Store API
|
||
|
||
**Plain-language:** “Stripe has a built-in secure place to store passwords, tokens, and API keys for your app — you don’t need to build your own database for secrets.”
|
||
|
||
### Two scopes
|
||
|
||
| Scope | Use for | Example |
|
||
| --- | --- | --- |
|
||
| `account` | Shared across all users of an account | The business’s API key for an email service |
|
||
| `user` | Per-user secrets | An individual user’s OAuth access token |
|
||
|
||
### Limits and restrictions
|
||
|
||
- Maximum **10 secrets per scope** (account and user separately)
|
||
- Always list and delete before adding more if approaching the limit
|
||
- Do **not** store PCI-sensitive data (card numbers, CVVs, bank account numbers)
|
||
|
||
### Declaring the permission
|
||
|
||
In `stripe-app.yaml`:
|
||
|
||
```yaml
|
||
declarations:
|
||
stripe_api_access:
|
||
permissions:
|
||
- permission: secret_write
|
||
purpose: Store third-party credentials for the app
|
||
```
|
||
|
||
### Implementation
|
||
|
||
For the correct code patterns to read, write, and delete secrets, read: https://docs.stripe.com/stripe-apps/store-secrets
|
||
|
||
## Local development with a backend
|
||
|
||
Run your backend locally alongside `stripe apps start`:
|
||
|
||
```bash
|
||
# Terminal 1: start the app preview
|
||
stripe apps start
|
||
|
||
# Terminal 2: start your backend server
|
||
node server.js
|
||
```
|
||
|
||
For webhook forwarding during local development, see `references/webhooks.md`.
|