rap2hpoutre/laravel-stripe-connect
A Laravel package for integrating Stripe Connect. It helps create and manage connected accounts, generate onboarding links, and handle Stripe Connect flows with simple configuration and Laravel-friendly APIs.
Architecture fit
The package is thin glue rather than a platform: it registers routes, a controller, a config file, and a small persistence path for the Stripe Connect OAuth handshake. It sits at the edge of the application (onboarding entry point + callback), so it does not constrain domain architecture — it does not own payment intent creation, charges, transfers, or webhook handling. That means the blast radius of adopting or rejecting it is small, but so is the value delivered: the work it saves is on the order of a few hundred lines. It assumes a single connected account per user (or per configured model) and a Standard-account OAuth model with client_id + stripe_user_id, which is the 2017-era Connect pattern, not Stripe's current recommended Connect Onboarding / Account Links flow for Express and Custom accounts.
Integration feasibility
Low as a dependency, moderate as a copy-and-adapt. Last release 2018-01-25 and the repository is archived, so Composer constraints almost certainly pin illuminate/*/laravel/framework to 5.x and PHP to 7.0–7.2. On Laravel 9+ (PHP 8.1+) installation will fail dependency resolution; forcing it with --ignore-platform-reqs buys an unmaintained code path running on runtime-incompatible assumptions. Package auto-discovery (Laravel 5.5+) means no manual provider registration, but any use of removed helpers, str_*/array_* shims, or the pre-7.x Stripe SDK (stripe/stripe-php 5.x/6.x) will need remediation. Net: treat it as a reference implementation to vendor into app/, not as a Composer dependency.
Technical risk
state parameter. Stripe added the state parameter to the Connect OAuth authorize URL well after this package's last release. If the package builds the authorize URL without a per-session, validated state value, the callback is exposed to CSRF/login-fixation style account-linking attacks (an attacker binds their Stripe account to a victim's app account, or vice versa). This is the single highest-severity item and must be verified in source, not assumed.Stripe-Account header and does not need to persist a connected-account token at all. Persisting tokens where none are required widens the secret-handling surface.account.application.deauthorized / account.updated webhook handling, no disconnect/re-onboard path, no re-auth after revocation, no handling of access_denied on the callback.Key questions
state that is generated per-attempt, session-bound, single-use, and validated on callback?Stack fit
Fits only Laravel 5.x-era applications cleanly. On Laravel 9/10/11/12 it fits as source material, not as a package: copy the routes, controller, config, and migration into the host application's namespace, then rewrite against the current stripe/stripe-php SDK. Modern Laravel's HTTP client, Http facade, and typed config make the OAuth exchange roughly 40 lines — meaning the build path is genuinely cheap and the vendoring path is mostly about not re-deriving Stripe's parameter names.
Migration path
state question, the token persistence model, and the Stripe SDK version pinned. Decide Standard-via-OAuth vs Express/Custom-via-Account-Links.app/ (or a first-party app/Support/StripeConnect), keeping the MIT attribution. If a dependency is mandated by policy, use a Composer VCS repository pointing at an internal fork with widened constraints — but budget for permanent ownership either way.state generation/validation, error=access_denied handling, and explicit redirect allow-listing.stripe_account_id, onboarding status, and timestamps on the owning model; drop token storage unless a specific flow requires it. Encrypt anything sensitive; add column-level access discipline.web CSRF where needed (or use a GET), make it idempotent, rate-limit it, and log structured events without account identifiers in plaintext./v1/accounts + /v1/account_links) plus account.updated webhook reconciliation. The package contributes nothing here beyond inspiration.Compatibility
Publish (or re-publish) the config and migration; verify route names do not collide with host routes; confirm middleware (web, auth) is applied explicitly rather than inherited from a 2018 assumption. Pin the Stripe API version in the SDK client so behavior does not shift under you.
Sequencing
Security review of the OAuth flow → account-type decision → inline/fork → rewrite handshake and persistence → automated tests with a mocked Stripe (authorize URL shape, state mismatch rejection, callback success, access_denied, duplicate callback) → staging smoke test against Stripe test mode → production rollout behind a feature flag with a single internal pilot account before opening onboarding broadly.
Maintenance Effectively 100% internal ownership from day one; upstream is archived and will not respond to issues, PRs, or advisories. The realistic ongoing cost is low and spiky: near-zero between Stripe API version bumps, then a half-day review when Stripe changes Connect onboarding or deprecates an endpoint. Budget a recurring line item for "review Connect flow against Stripe changelog" at each Stripe API version bump, and add the vendored files to the standard dependency-review checklist so they are not mistaken for framework code.
Support Support load is concentrated in onboarding failures, which are user-visible and high-friction: redirect URI mismatch, stale or reused authorization codes, users abandoning mid-flow, users connecting the wrong Stripe account and needing a reset. Because the package provides no disconnect/reset path, the support team will need a documented manual runbook (and ideally an admin action) for unlinking an account. Expect the finance/support boundary — who owns "my payouts aren't showing" — to need explicit definition; that question lands on the platform team even though Stripe owns the account.
Scaling
Negligible compute cost: the OAuth handshake is one-time per account and O(accounts) in total, not O(transactions). The real scale questions are elsewhere — webhook throughput for account.updated, payout/transfer reconciliation, and per-account rate limits when onboarding many accounts in a burst (e.g., a merchant-acquisition campaign). If the platform later supports multiple connected accounts per tenant or per region, the package's single-account assumption is the first thing to break, and that data-model change is the most likely forced refactor.
Failure modes
state absent or unvalidated → account-linking CSRF (highest severity, silent).stripe_user_id.account.application.deauthorized) unhandled → app believes a dead account is live; downstream charges/transfers fail with confusing errors.--ignore-platform-reqs masking a genuine PHP 8 incompatibility in the callback path, failing only in production.Ramp-up Low for a mid-level Laravel engineer: the flow is a redirect, a code exchange, and a row write — hours to understand, a day to reimplement well. The non-obvious cost is Stripe Connect domain literacy, not Laravel: charge types (direct vs destination), who bears disputes and negative balances, KYC responsibility, and the Standard/Express/Custom tradeoffs. Assign one engineer as the Connect owner and require them to read Stripe's current Connect docs rather than the package's README, since the README encodes 2018 assumptions. Estimated total effort for the recommended inline approach: 2–4 engineer-days including tests, plus a security review pass.
How can I help you explore Laravel packages today?