Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Shopify Laravel Package

kyon147/laravel-shopify

A maintained full-featured Laravel package for Shopify app development, with OAuth, webhooks, billing, and support for expiring offline access tokens. Works with Laravel 8+ and installs via Composer.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. This is an opinionated, batteries-included Shopify app framework for Laravel — it occupies the same architectural slot as shopify_app does in Rails. It owns the OAuth handshake, session-token/App Bridge validation, shop persistence, webhook registration and HMAC verification, billing (recurring/one-time/usage), and now expiring offline token lifecycle. That is a lot of surface area for one dependency, and it is the right call only if we intend to build a standard embedded Shopify app on a Laravel monolith. If our target architecture is a thin API service, a multi-tenant platform with non-Shopify channels, or a serverless/event-driven split, this package becomes a partial fit at best: it assumes a shops table it owns, a User model trait, and its own route/middleware stack.

The package is a maintained community fork of a deprecated original (gnikyt/osiset). It retains the Osiset\ShopifyApp namespace, which is functionally harmless but tells you the codebase's lineage: it is a continuity fork, not a greenfield design. The README's own unchecked Goals list (per-user auth, better SPA/Vue support, Blade templates under Shopify's newer auth flow) is an honest admission that the front-end integration story is behind where Shopify's platform has moved.

Integration feasibility. Straightforward on the happy path: composer require, publish config, run migrations, wire middleware. The friction is in the seams:

  • It ships migrations that alter the shops table (including the new shopify_offline_refresh_token and *_expires_at columns). Schema ownership becomes shared between the package and our app — we need a policy on this before install, not after.
  • It expects a User model trait (ShopModel / initializeShopModel) and uses mergeCasts; apps with custom $casts must merge datetime casts manually — a documented, easy-to-miss footgun.
  • Its HTTP/REST/Graph client comes from gnikyt/basic-shopify-api, which the README itself flags as a candidate for replacement or fork. OAuth/expiring-token logic has been deliberately decoupled from that dependency, but bulk data access has not.

Technical risk. Scored 43.99 overall with 498 stars and 0 listed dependents. The zero-dependents figure is probably a metadata artifact rather than true adoption — most Shopify apps are private codebases and never register as Packagist dependents — but we should not treat it as evidence of a healthy ecosystem either.

Risk Severity Notes
Bus factor / maintainer capacity High Primary maintainer states they work on this in spare time, alongside family and work. Two named maintainers, one dominant.
Deprecated upstream HTTP client Medium–High gnikyt/basic-shopify-api is acknowledged as not actively maintained; the fork has worked around it for OAuth but not for REST/Graph traffic.
Platform churn Medium Shopify's auth, App Bridge, and token models have changed repeatedly (session tokens, expiring offline tokens mandated for new public apps from April 1, 2026). The fork is tracking this, but each change forces a major or minor upgrade on our side.
Incomplete roadmap items Medium Unchecked goals imply known gaps in SPA and per-user auth; we should not assume these are solved.
Security history Low–Medium v27.1.0 shipped redirect-URL escaping and blocks API routes opened in a browser — good responsiveness, but indicates prior exposure.
One-way token migration Medium Migrating legacy non-expiring offline tokens revokes the old token on success. No rollback path.
Docs location Low–Medium Canonical documentation lives in the GitHub wiki, not in-repo. Wiki content is not versioned against releases and cannot be reviewed in PRs.

Key questions.

  1. Are we building a public app (App Store) or a custom/private app? The April 2026 expiring-offline-token mandate applies to new public apps; the answer changes our token architecture and urgency materially.
  2. Which exact Laravel and PHP versions are we on, and which does the current major actually support? The README's "Laravel 8 and up" claim conflicts with the v26.0.0 breaking release that dropped older PHP and Laravel — verify against composer.json, not the README.
  3. Who owns the shops table schema — us or the package? What is our policy when a package migration conflicts with ours?
  4. Is our front end an embedded SPA (React/App Bridge) or Blade-rendered? Given the unchecked SPA goal, an SPA may need more bespoke work outside the package.
  5. What is our exit strategy? If the package stalls, can we own OAuth, webhooks, and token refresh ourselves, and how long would that take?
  6. How many shops, and what is the dormancy profile? Proactive refresh-token renewal must be scheduled by us — the package deliberately does not register a schedule.

Integration Approach

Stack fit. Strong fit for a standard Laravel monolith serving an embedded Shopify app: Eloquent-backed shop records, Laravel queues for token jobs and webhooks, Laravel's encrypter for refresh-token storage, and Artisan commands that are explicitly serverless-aware (no HTTP in the batch commands, designed for Vapor). Weak fit for polyglot or microservice architectures, and for anything where Shopify is one channel among many — the package's models and middleware assume it owns the shop identity.

Migration path. Two distinct migrations to plan:

  1. Source migration — from the deprecated gnikyt/osiset original to this fork. The retained Osiset\ShopifyApp namespace reduces this to a composer swap plus verification, which is the fork's main selling point. Budget for regression testing of the auth flow rather than code changes.
  2. Token model migration — from non-expiring to expiring offline access tokens. The package offers four routes: passive fail-open migration on first apiHelper() call (default, SHOPIFY_AUTO_MIGRATE_LEGACY=true), a batch CLI (shopify-app:migrate-expiring-offline-tokens) with dry-run and per-shop targeting, a per-shop Action class, and a low-level ApiHelper exchange. Choose deliberately:
    • Default to the batch CLI with --dry-run first, then real runs in cohorts. It is idempotent-ish by design, serverless-safe, and gives us observable progress per shop.
    • Do not ship the fail-open default to production as the primary mechanism. It mutates tokens synchronously inside live request paths, logs failures, and continues with the legacy token — a silent partial-migration state that is hard to reason about during an incident.
    • Sequence the migration before enabling the expiring-token flag broadly, not concurrently with it.

Because migration is one-way, take a shop-token inventory and a communication plan before the first real run.

Compatibility. Verify, don't assume: PHP and Laravel version constraints in composer.json, queue driver support (the sync driver had a bug where the migrate command halted on the first failed shop — fixed in v27.0.1, so pin at or above that), and whether our app already has a conflicting /authenticate or webhook route. The APP_KEY dependency is non-negotiable: refresh tokens are stored encrypted, so key rotation without a re-encryption plan forces every shop through re-auth.

Sequencing.

  1. Spike (timeboxed, ~1 week) in a throwaway Laravel app against a Shopify development store: install, OAuth, session token via App Bridge, one webhook, one billing charge, one token refresh. Output is an ADR with a go/no-go and a written exit plan.
  2. Decide the schema-ownership policy and lock it into the ADR.
  3. Base integration: config publish, migrations, middleware wired to a single non-critical route first, webhook verification tested with a signed fixture.
  4. Billing behind a feature flag, exercised in Shopify's test charge mode.
  5. Expiring offline tokens: enable the flag, run --dry-run, then cohort the batch migration.
  6. Proactive renewal: register Schedule::command('shopify-app:refresh-expiring-offline-tokens')->daily() in our own console kernel/routes, targeting a dedicated queue and connection via the config keys.
  7. Observability, then broaden route coverage.

Step 6 is ours to build. The package explicitly does not schedule it, and skipping it means dormant shops silently lose refresh tokens after ~90 days.

Operational Impact

Maintenance. This is a shared-ownership dependency with a single dominant part-time maintainer. We inherit the upgrade treadmill of a fast-moving platform: the 2026 release history alone spans majors for PHP/Laravel support drops and token model changes. Practical posture:

  • Pin to a specific minor; upgrade on a deliberate cadence, not on composer update.
  • Read the release notes for every major — v26.0.0 and v27.0.0 were both breaking.
  • Track upstream PRs and issues; when a Shopify platform change lands, this package's turnaround is measured in weeks, not days. Plan a buffer.
  • Treat gnikyt/basic-shopify-api as a known liability and budget for eventual replacement or vendoring, especially if we do heavy bulk Graph/REST work.

Support. Community-only: GitHub issues with a required template, a wiki, no commercial support, no SLA, no security disclosure policy documented in the sources provided. Escalation for a production auth outage is "file an issue and wait." For anything customer-facing with revenue attached, we should assume we may have to patch a fork ourselves. Two mitigations: (a) fork-and-vendor readiness — confirm we can maintain a private fork, and (b) keep the auth/webhook surface small enough to reimplement in an emergency.

Scaling. Auth, webhook receipt, and billing are per-request and cheap — they scale with the app like any Laravel app. The real scaling concerns are queue-bound:

  • Batch token commands chunk shops and dispatch jobs, so a large shop base produces job bursts. Use the dedicated SHOPIFY_*_JOB_QUEUE / *_JOB_CONNECTION keys so token jobs don't starve webhook or customer-facing workers.
  • Long-running jobs are the sharpest edge. The API client is cached on the shop model; a worker looping for hours will hold a stale access token past expiry. This is documented, and the fix is explicit: enable SHOPIFY_REFRESH_OFFLINE_TOKEN_BEFORE_API_CALL=true (with a per-call cost) or call $shop->offlineAccessTokenIsFresh() / refreshOfflineAccessTokenIfNeeded() / resetApiClient() per iteration. Any bulk-sync job must adopt one of these patterns — this is a code-review checklist item, not an optimization.
  • Multi-worker concurrency on token refresh needs a lock; the package clears the cached client on refresh, but two workers refreshing the same shop concurrently is a race we should guard.

Failure modes.

Failure Symptom Mitigation
Refresh token lapse (dormant shop > ~90 days) Shop silently drops out; API calls fail Scheduled refresh-expiring-offline-tokens daily; alert on shops with refresh expiring inside the window
APP_KEY rotation All refresh tokens undecryptable; mass re-auth Key-rotation runbook with re-encryption; treat APP_KEY as immutable per environment
Stale cached client in long job 401s mid-run after token expiry Per-iteration freshness check or the opt-in before-call refresh flag
Fail-open legacy migration Shop keeps working on a legacy token; migration silently incomplete Prefer batch CLI; alert on migrated=false outcomes and log volume
One-way migration mistake Old token revoked, no rollback Dry-run, cohort rollout, per-shop inventory before execution
Webhook HMAC rejection Missing order/product events, drift in data Signed fixture tests in CI; monitor webhook endpoint 4xx rate
Sync queue driver on batch command Command halts on first failed shop Pin ≥ v27.0.1; use a real queue driver, not sync
Upstream package abandonment No security patches for new Shopify auth changes Private fork readiness; documented reimplementation scope for OAuth/webhooks

Ramp-up. Moderate. A Laravel developer gets a dev-store app running in a day; getting production-safe takes considerably longer because the hard parts are not in the quickstart. Budget for:

  • Reading the wiki (not in-repo, so it must be captured into our internal docs) plus the README's token-lifecycle section, which is the densest and most consequential part.
  • One engineer designated as the Shopify-platform owner — auth, tokens, App Bridge version, and API version upgrades all land on that person.
  • Internal runbooks for: token refresh failure, APP_KEY rotation, webhook verification failure, billing disputes, and re-auth storms.
  • Onboarding checklist covering the $casts merge, the long-job token pattern, and the schema-ownership rule.

Bottom line. Adopt for a standard embedded Laravel Shopify app, contingent on the spike passing and on written acceptance of the maintainer-concentration and upstream-HTTP-client risks. Do not adopt if Shopify is a secondary channel, if the team cannot absorb a platform-churn upgrade cadence, or if the SPA front end is central to the product — the package's own roadmap says that path is unfinished.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package