trianity/laravel-mautic
A Laravel package that integrates Mautic marketing automation into your app, offering a config-driven wrapper for the Mautic API so you can manage contacts, segments, emails, forms, and campaigns from familiar Laravel code.
This package is the Laravel-side client for the Mautic API. v1.1.0 is a meaningful step up if you want the package to own the OAuth dance: browser authorization/callback routes are now available (opt-in, disabled by default), credential lookup is more flexible, and there are two commands that answer the two questions you will always have — what callback URL do I register in Mautic? and why is my connection failing?
Minimal path:
composer require the package, then publish its config and confirm config/mautic.php exists. If you already have a published config, merge the new oauth.routes block by hand — do not vendor:publish --force.config/mautic.php, with credentials coming from the environment:'connections' => [
'main' => [
'base_url' => env('MAUTIC_BASE_URL'),
'client_id' => env('MAUTIC_CLIENT_ID'),
'client_secret' => env('MAUTIC_CLIENT_SECRET'),
// 'redirect_uri' => 'https://app.example.com/mautic/oauth/callback',
],
],
php artisan mautic:diagnose. It reports credential availability (sanitized — no secrets in output), which immediately tells you whether the secret is visible to the current runtime before you go debugging HTTP.php artisan mautic:oauth:callback-url to get the canonical URL, and register it on the Mautic side against your API client credentials. It is read-only and safe to run anywhere.main connection, then decide whether you need the package's browser OAuth routes or will keep host-owned routes.Where to look first: the published config/mautic.php (it is the whole contract), docs/oauth-host-adoption.md (new in this release), and the output of the two artisan commands. Skip the docs at your peril — the OAuth section is the part that bites.
Host-owned OAuth remains the default posture. v1.1.0 preserves existing host-owned routes; package routes require both oauth.routes.enabled and a host binding. The pragmatic split:
Bind OAuthBrowserAuthorizer deliberately. It denies by default. That is the correct security default and the most common "why does the callback 403?" cause. Implement it against your gate/policy — typically "user is authenticated and belongs to the tenant that owns this connection" — and register it in a service provider.
Allowlist connections for the browser flow. The allowlist is your blast radius control: only connections in that list can be driven through the public authorization route. Never allowlist a connection whose tokens reach data the current user shouldn't see.
Route shaping is configuration, not code. Route names, prefix, middleware, and the post-flow result route are all configurable under oauth.routes. Practical settings:
'oauth' => [
'routes' => [
'enabled' => env('MAUTIC_OAUTH_ROUTES', false),
'prefix' => 'integrations/mautic',
'middleware' => ['web', 'auth'], // add your auth stack here, not in the controller
'connections'=> ['main'],
],
],
Put authorization middleware in the route config so the package routes are protected identically to the rest of your app.
Prefer app.url over the request host for callback URLs. Resolution is canonical and driven by trusted app.url; per-connection redirect_uri takes precedence when you need an override. Use the override for genuinely different origins (separate admin domain, custom callback host), not as a workaround for a misconfigured APP_URL.
Credential resolution order to design around: explicit per-connection value → Laravel environment repository → process environment → custom credential provider. The environment-repository layer means secrets stay in env and out of the cached config file; a custom provider is the right extension point for Vault/SSM/secrets managers, not a config() hack.
Deployment routine that actually works:
MAUTIC_CLIENT_SECRET (and friends) in every runtime that touches the package: PHP-FPM pool env, CLI, scheduler, queue workers.php artisan config:cache.php artisan mautic:diagnose — verify credential availability per environment.queue:work, Octane) after any config/env change.mautic:oauth:callback-url).Testing. Fake the HTTP layer rather than the package internals; keep a distinct sandbox/testing connection so a mis-set MAUTIC_ENV can never point tests at production tokens.
vendor:publish --force on an existing app. It will overwrite host config. Diff the published stub against yours and merge oauth.routes manually.php artisan tinker but fails under FPM or a queue worker is almost always this.APP_URL must be truthful. Behind a load balancer or proxy, set trusted proxies and a correct APP_URL/redirect_uri; otherwise the generated callback won't match what Mautic has registered and you'll get a redirect-URI mismatch from Mautic, not from Laravel.Host — that closes a host-header injection vector. If you were relying on absolute redirects from the flow, adjust your expectations rather than patching around it.APP_KEY. Rotating APP_KEY invalidates encrypted tokens and forces every connection to re-authorize.oauth.routes, restart workers. mautic:diagnose run from a stale worker will lie to you.mautic:diagnose (credential availability, sanitized) → mautic:oauth:callback-url (URL correctness) → Mautic-side client credentials (registered redirect) → token expiry/refresh logs. Start there before reading HTTP traces.OAuthBrowserAuthorizer binding for access policy, and host-owned routes for full UI control. Those three cover nearly every customization request without forking.How can I help you explore Laravel packages today?