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

Ouath2 Merchant Laravel Package

salla/ouath2-merchant

A Laravel/PHP package for Salla merchant OAuth2 authentication, helping apps authorize merchants, handle OAuth2 flows, and connect securely to Salla APIs with streamlined token management and onboarding.

View on GitHub
Deep Wiki
Context7

Getting Started

Install (mind the typo). The Composer package is salla/ouath2-merchant — ouath2, not oauth2. Typing the obvious spelling will 404:

composer require salla/ouath2-merchant

Requires PHP ^8.1 and league/oauth2-client ^2. The illuminate/support constraint spans ^9–^13, so verify it resolves against your Laravel version before assuming compatibility.

Configure credentials. Publish the package config (typically a salla-oauth.php-style file under config/ after php artisan vendor:publish) and set the client credentials in .env. Never commit the secret; the repo explicitly forbids it.

SALLA_CLIENT_ID=...
SALLA_CLIENT_SECRET=...
SALLA_REDIRECT_URI=https://your-app.test/oauth/salla/callback

Wire up the guard. Register the salla-oauth guard in config/auth.php for the merchant-facing surface. The names are load-bearing — salla-oauth, salla.oauth, and the salla.oauth.user request attribute are contract-level names (see Gotchas). Don't "clean them up."

Where to look first

  • Salla\OAuth2\Client\ — PSR-4 root, the provider class extends league/oauth2-client's AbstractProvider.
  • The middleware behind the salla.oauth alias (validates bearer tokens against accounts.salla.sa/oauth2/user/info, cached).
  • The SallaOauth facade — thin wrapper over the provider.
  • Repo docs: CLAUDE.md (full guide) and AGENTS.md (quick facts + consumer list). Read these before opening a PR; they encode hard rules.

First use case — merchant connect + API call. Build the smallest loop: an authorization-redirect route → a callback route that exchanges the code for a token → persist token → call a Salla endpoint. Then protect any merchant-scoped API with salla.oauth[:scopes] and read the caller from salla.oauth.user.

Implementation Patterns

Pick the right layer. There are three, and you should choose the lowest one that solves your problem:

Layer Use when
league/oauth2-client provider directly Background jobs, console commands, custom flows, multi-tenant token stores
SallaOauth facade Quick controller-level calls where DI overhead isn't worth it
salla.oauth middleware / salla-oauth guard Inbound requests from Salla-authenticated callers

Because it's a standard league provider, the generic docs apply verbatim:

$provider = new SallaProvider([
    'clientId'     => config('salla-oauth.client_id'),
    'clientSecret' => config('salla-oauth.client_secret'),
    'redirectUri'  => config('salla-oauth.redirect_uri'),
]);

$url   = $provider->getAuthorizationUrl(['scope' => ['orders.read']]);
$token = $provider->getAccessToken('authorization_code', ['code' => $request->code]);

Persist tokens per merchant, not per user. A Salla merchant store is the tenant boundary. Store access_token, refresh_token, expires_at, and the merchant/store identifier in a table keyed by store. Assume refresh tokens may rotate — always persist the token returned by a refresh, don't reuse the old one.

Refresh lazily, not eagerly. Wrap outbound calls in a small client that catches 401 and performs getAccessToken('refresh_token', [...]) once, then retries. A scheduled refresh job is fine as a belt-and-braces measure, but lazy refresh handles the "token expired mid-request" case that schedulers miss.

Scope declaration syntax. The middleware alias accepts scopes inline: ->middleware('salla.oauth:orders.read,products.read'). Request only what you need — merchants see the consent screen, and over-broad scopes suppress installs.

Read the authenticated caller consistently. Whatever the middleware sets, expose it through the guard so $request->user('salla-oauth') and Auth::guard('salla-oauth')->user() behave the same way as the request attribute. Wrap this in a helper if you're consuming it in many controllers; it keeps the coupling to one file if the attribute name ever changes.

For endpoints the provider doesn't wrap, pull the token and use Laravel's HTTP client. This is often cleaner than extending the provider:

Http::withToken($token->getToken())
    ->baseUrl('https://api.salla.dev/admin/v2')
    ->get('/orders');

Testing. Per AGENTS.md, mock Salla by stubbing fetchResourceOwnerDetails on the provider — do not hit the live API. Combine with Http::fake() for downstream calls, and use Orchestra Testbench if you need the full Laravel container (the package's own suite uses it). Note the CI matrix uses Redis; reproduce that locally or you'll chase phantom cache failures.

Multi-app integration. If you're exposing merchant identity to other first-party services (the consumer list includes apps-marketplace-api, PartnerMarketing, DevelopersPortal, and others), don't invent a parallel identity format — the salla.oauth.user attribute and the cached payload shape are already the de facto internal contract.

Gotchas and Tips

The typo is permanent. ouath2 in the package name is intentional and renaming it is explicitly forbidden. Add a comment or an onboarding note so the next developer doesn't waste 10 minutes on a 404 from Packagist.

Do not log cache keys. The token-validation cache key embeds the raw bearer token. That means: no Log::debug($key), no dumping the cache store, no exception handlers that serialize cache metadata, and ideally a log scrubber for Authorization headers. Check your APM/proxy access logs too — a proxy that logs request headers leaks tokens regardless of what your app does.

Cache invalidation on revocation. The middleware caches successful /oauth2/user/info lookups. When a merchant uninstalls or revokes your app, that cached entry is now a false positive. Hook the Salla uninstall/revocation webhook to explicitly forget the cache entry, and set a TTL short enough that a missed webhook is a nuisance rather than a security hole.

Names are frozen. salla-oauth (guard), salla.oauth (middleware alias), salla.oauth.user (request attribute), and the cache payload shape all have downstream consumers listed in AGENTS.md. If you maintain a fork or contribute upstream, changing any of these is a breaking change across multiple Salla services. Propose additions, not renames.

Branch and PR conventions are enforced socially. Default branch is master, not main. Branch as feature/PROJ-123-desc, title PRs feat(scope): desc, and include the Jira link in the PR body. Pushing to master is prohibited. Releases are manual semver tags (currently 3.0.x) — there is no automated release pipeline, so pin versions and expect to tag yourself if you need a fix shipped.

composer check is not in CI. PSR-2 lint runs manually. Run composer check locally before opening a PR or review will bounce on style. CI itself is PHP 8.1/8.2/8.3 with Redis via Testbench.

Extension points, in rough order of least-to-most invasive:

  1. Pass scope, state, and other options per-call.
  2. Override getDefaultScopes(), getBaseAuthorizationUrl(), getBaseAccessTokenUrl(), getResourceOwnerDetailsUrl() in a subclass.
  3. Override createResourceOwner() to return your own resource-owner class if you need typed accessors over the raw array.
  4. Swap the container binding for the provider if you need a completely different HTTP client or retry middleware.

Version constraint reality check. illuminate/support ^9–^13 is a wide window. Run composer why-not if resolution fails on an older app; don't assume the package is broken when it's actually a PHP 8.0 or Laravel 8 app in disguise.

Octane. If you run under Octane or any long-lived worker, verify the guard and middleware don't hold per-request state on the singleton. The token-validation cache helps here, but a leaked salla.oauth.user across requests would be a cross-tenant data leak — add a test that hits two different tokens sequentially on the same worker.

Low stars, high coupling. 25 stars and 0 public dependents makes this look like a hobby package; it isn't. It's an internal-first Salla library with a stable-by-policy API and a documented consumer list. Treat the API surface as frozen and the maintenance risk as "vendor-owned," not "abandoned." The flip side: issues and PRs are unlikely to get community traction, so plan for self-service debugging against the source.

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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core