mijndomein/dreamcommerce-sso-client
A Laravel/PHP SSO client for DreamCommerce from MijnDomein. Integrate single sign-on into your application with authentication flow handling and session bridging for DreamCommerce services. Designed for quick setup in Laravel projects.
This is a low-traffic, likely internal package (0 stars, 0 dependents), so treat the source as the documentation — read src/ and config/ before wiring anything up.
Install and pin
composer require mijndomein/dreamcommerce-sso-client
Pin an exact version in composer.json ("mijndomein/dreamcommerce-sso-client": "1.x.x"). With no dependents and no release history worth trusting, a silent patch bump is a real risk.
Publish config (typical Laravel package convention — confirm the tag name in the service provider):
php artisan vendor:publish --provider="Mijndomein\DreamCommerceSsoClient\DreamCommerceSsoClientServiceProvider"
Look at config/dreamcommerce-sso-client.php first. That file tells you more about the contract than any README: which endpoints are configurable, whether the redirect/callback routes are auto-registered, and what the expected env variable names are.
Fill env values — expect something close to:
DREAMCOMMERCE_SSO_BASE_URL=https://your-shop.dreamcommerce.com
DREAMCOMMERCE_SSO_CLIENT_ID=...
DREAMCOMMERCE_SSO_CLIENT_SECRET=...
DREAMCOMMERCE_SSO_REDIRECT_URI=https://yourapp.test/auth/dreamcommerce/callback
First use case — replace the login button. The narrowest useful integration is: a route that kicks off the redirect, a callback route that exchanges the code/token for a customer identity, then Auth::login(). Start there before touching guards, middleware, or user sync.
Verify the callback actually arrives. Register the redirect URI on the DreamCommerce side and hit the callback manually with a logged-in session before building anything on top of it. If the redirect URI whitelist doesn't match byte-for-byte (including trailing slash), you'll get a generic error from the shop, not from PHP.
Redirect + callback controller pair. Keep this thin:
Route::get('/auth/dreamcommerce', [SsoController::class, 'redirect'])->name('sso.redirect');
Route::get('/auth/dreamcommerce/callback', [SsoController::class, 'callback']);
The redirect action should stash state in the session (or use the package's helper if it provides one) and hand off to the package. The callback action should validate, resolve a local User, and call Auth::login($user, remember: true). Never trust the callback payload until it's been verified by the package's client — don't hand-parse the query string.
Custom user provider / resolver binding. The package almost certainly needs a way to map an SSO identity to your App\Models\User. Bind this in a service provider rather than editing vendor config:
$this->app->bind(UserResolver::class, ShopCustomerResolver::class);
Resolution should be idempotent — firstOrCreate on a stable SSO subject ID (not email; customers change email), and log every creation so you can audit who got in.
Guard integration. For a shop-facing app, a dedicated dreamcommerce guard is cleaner than overloading web:
'guards' => [
'dreamcommerce' => ['driver' => 'session', 'provider' => 'dreamcommerce'],
],
Then auth:dreamcommerce on customer routes. Mixing admin and customer auth in one guard is the fastest way to accidentally grant a customer access to a staff route.
Token lifecycle. Store access/refresh tokens on the user record or a sso_tokens table with expires_at. Refresh on a scheduled command or lazily via middleware — not inside the callback, which should stay fast. If the package exposes a refreshToken() method, wrap it in a small DreamCommerceClient service of your own so you can swap it out later; that indirection is cheap insurance for a package with no community.
Multi-shop / multi-tenant. If you run several DreamCommerce shops, the "single" in SSO stops being true. Instantiate a client per shop with per-tenant config rather than relying on the singleton from the container:
$client = new SsoClient(config("shops.{$shopId}.dreamcommerce"));
Check whether the package's service provider registers the client as a singleton — if so, override that binding.
Testing. Mock the outbound HTTP with Http::fake() and assert on the redirect URL and the resolved user, not on the package's internals. Add one integration test that stubs a realistic callback payload (copy a real one from logs, with tokens sanitized) and asserts Auth::check() afterward. That single test catches most regressions when bumping versions.
Events. If the package dispatches anything (SsoLogin, UserProvisioned), listen rather than editing vendor code. Post-login side effects — cart merge, welcome email, segment sync — belong in listeners so they're testable in isolation.
src/ end-to-end (it's probably a few hundred lines) and write down what it does. If it's abandoned, you'll be maintaining a fork — keep your integration behind an interface so the swap is a day's work, not a sprint.state and redirect_uri are the two most common failures. A missing or unverified state is a CSRF hole; a redirect_uri mismatch is the most likely cause of "it worked locally, broken in staging." Compare against the value registered in the DreamCommerce admin character by character.php artisan config:cache after every env edit in staging/prod; a stale cached config produces confusing "wrong client ID" errors that look like credential problems.http:// redirect URIs outside localhost. If you develop over http://shop.test, you may need a tunnel (ngrok/Expose) rather than fighting the provider.expires_at checks with 30–60s of leeway and verify NTP on the box before debugging code.state you stored disappears and validation fails. Pin the session cookie domain deliberately.code, token, access_token, id_token before you ever turn on debug logging for this flow.Cache::lock("sso-refresh:{$userId}") around the refresh call.*ServiceProvider bindings you can re-bind. If none exist, that's the signal to wrap the package rather than call it from controllers directly.Http::withOptions(['debug' => true]) if it's Guzzle-based), confirm the redirect URL is well-formed, then confirm the callback reaches your controller at all. In that order — most failures are in the redirect, not the token exchange.How can I help you explore Laravel packages today?