@kodice.one/stripefirebase-client
v1.2.0
Published
React client library for Firebase + Stripe payment integration
Readme
Firebase + Stripe Payments — Monorepo
End-to-end payment integration using Firebase Functions v2, Firestore, and Stripe Checkout, structured as an npm workspaces monorepo.
Project structure
firebase-stripe-payments/
├── package.json ← workspace root
├── tsconfig.base.json ← shared TS compiler base
├── firebase.json ← Firebase project config
├── firebase/
│ ├── firestore.rules ← Firestore security rules
│ └── firestore.indexes.json
└── packages/
├── shared/ ← @kodice.one/stripefirebase-shared
│ ├── package.json
│ ├── tsconfig.json
│ └── src/index.ts ← all shared TypeScript types
│
├── functions/ ← @kodice.one/stripefirebase-functions
│ ├── package.json
│ ├── tsconfig.json
│ └── src/index.ts ← createCheckout + stripeWebhook (Functions v2)
│
└── client/ ← @kodice.one/stripefirebase-client (publishable npm lib)
├── package.json
├── tsconfig.json
├── tsconfig.esm.json
└── src/
├── index.ts ← createCheckoutUrl, onPaymentStatusChange, onUserCheckouts
├── react.ts ← useStripeCheckout, usePaymentStatus, useUserCheckouts
└── example.tsx ← reference React componentsArchitecture
React App
│
├─ @kodice.one/stripefirebase-client
│ ├─ createCheckoutUrl() → calls Firebase Function (onCall v2)
│ ├─ onPaymentStatusChange() → real-time Firestore listener
│ └─ /react hooks
│
Firebase Functions (v2)
├─ createCheckout (onCall)
│ ├─ Validates auth + input
│ ├─ Creates Stripe Checkout Session
│ └─ Writes checkouts/{uid}/sessions/{sid} status: "pending"
│
└─ stripeWebhook (onRequest)
├─ Verifies Stripe signature
└─ Updates Firestore status on each event:
checkout.session.completed → "succeeded"
checkout.session.expired → "expired"
payment_intent.payment_failed → "failed"
customer.subscription.deleted → "canceled"
Firestore
└─ checkouts/{userId}/sessions/{sessionId}Getting started
1. Install dependencies
npm installThis installs all workspace packages in one shot.
2. Set Stripe secrets (stored in Google Cloud Secret Manager)
firebase functions:secrets:set STRIPE_SECRET_KEY
# paste sk_live_... or sk_test_...
firebase functions:secrets:set STRIPE_WEBHOOK_SECRET
# paste whsec_... (from the Stripe Dashboard after step 4)3. Build & deploy
# Build everything (shared → functions → client)
npm run build
# Deploy Functions + Firestore rules/indexes
firebase deploy4. Register the Stripe webhook
In Stripe Dashboard → Webhooks add:
- URL:
https://<region>-<project-id>.cloudfunctions.net/stripeWebhook - Events:
checkout.session.completedcheckout.session.expiredpayment_intent.payment_failedcustomer.subscription.deleted
Copy the Signing secret and save it: firebase functions:secrets:set STRIPE_WEBHOOK_SECRET.
5. Use the client in your React app
npm install @kodice.one/stripefirebase-client// main.tsx
import { initializeApp } from "firebase/app";
import { getFunctions } from "firebase/functions";
import { getFirestore } from "firebase/firestore";
import { initStripeFirebase } from "@kodice.one/stripefirebase-client";
const app = initializeApp({ /* your firebase config */ });
initStripeFirebase({
functions: getFunctions(app),
firestore: getFirestore(app),
});// PricingPage.tsx
import { useStripeCheckout } from "@kodice.one/stripefirebase-client/react";
export function SubscribeButton({ priceId }: { priceId: string }) {
const { startCheckout, loading, error } = useStripeCheckout();
return (
<button
disabled={loading}
onClick={() => startCheckout({
lineItems: [{ priceId, quantity: 1 }],
mode: "subscription",
successUrl: `${location.origin}/welcome?session_id={CHECKOUT_SESSION_ID}`,
cancelUrl: `${location.origin}/pricing`,
})}
>
{loading ? "Loading…" : "Subscribe"}
</button>
);
}// SuccessPage.tsx — mounted at your successUrl route
import { usePaymentStatus } from "@kodice.one/stripefirebase-client/react";
export function SuccessPage({ userId }: { userId: string }) {
const sessionId = new URLSearchParams(location.search).get("session_id");
const { status, session } = usePaymentStatus({ userId, sessionId });
if (status === "succeeded") return <h1>Welcome! 🎉</h1>;
if (status === "failed") return <p>Payment failed — please retry.</p>;
return <p>Confirming payment…</p>;
}Local development
# Start Firebase emulators (Functions + Firestore)
npm run emulate
# In a separate terminal — forward live Stripe events to the local webhook
stripe listen --forward-to http://localhost:5001/<project-id>/us-central1/stripeWebhookFunctions v2 highlights
| Feature | v1 | v2 (this project) |
|---|---|---|
| Import path | firebase-functions | firebase-functions/v2/https |
| Secrets | functions.config() | defineSecret() → Secret Manager |
| Config | functions.config().stripe.key | process.env / secret.value() |
| Logging | functions.logger | import { logger } from "firebase-functions/v2" |
| onCall data | (data, context) | (request) → request.data, request.auth |
| Concurrency | 1 req / instance | Up to 1000 req / instance |
Security notes
- Firestore rules deny all client writes; only the Admin SDK (Functions) may write.
- Auth guard in
createCheckoutblocks unauthenticated callers. - Webhook signature verification prevents spoofed Stripe events.
client_reference_idandmetadata.userIdare set server-side — clients cannot impersonate another user's session.- Stripe secrets are stored in Google Cloud Secret Manager, never in source code or
firebase.json.
