geekcodev/laravel-max-client
A Laravel client for the MAX messaging platform that simplifies bot integration: configure credentials, send messages, alerts, and notifications, and call the MAX API through a clean, framework-friendly PHP wrapper for Laravel services, jobs, and apps. Built to keep MAX bot calls simple inside Larav...
WebApp\WebAppContactService verifies contacts returned by window.WebApp.requestContact() (signed authDate/phone/userId, constant-time comparison, replay window via webapp.max_age). This directly enables onboarding/account-linking flows, step-up verification before sensitive actions (orders, payouts, listings), duplicate-account and fraud reduction, and “verified” trust badges.+/separator formats), replay protection, session-fixation defense (session id regeneration in WebAppSession::confirm()) and PII-safe logging (no phone/hash on failure, OWASP A09) are commodity security work. The release makes the buy-side concrete: use WebAppContactService / WebAppSession instead of app-local App\Services\WebAppContactVerifier / App\Support\WebAppSession. The adapter is a thin wrapper over the core verifier, so there is one algorithm to audit, not two.max:subscribe default moves from 6 to 13 update types, adding message_edited, message_removed, dialog_cleared, dialog_removed, chat_title_changed, user_added, user_removed. Previously these were never delivered — a “silent desync” with no errors. This unlocks or repairs product features: edit history/state sync, delete/cleanup handling for moderation and retention, correct chat titles, and membership-driven permissions or notifications.user_added/user_removed are subscribed now but currently ignored (PersistMaxChatListener → default => null → return), pre-wired for the chat member sync plan 2026-10-02-laravel-max-client-chat-member-sync.md. A PM can sequence member-sync dependent features knowing the delivery plumbing is already in place and the listener is a deliberate no-op today.webhook.update_types is configurable (env MAX_WEBHOOK_UPDATE_TYPES, comma-list or array; empty values degrade to the default so “subscribe to nothing” is impossible; whitespace and duplicates cleaned). This is a per-environment lever for noise and webhook load — but note it filters webhook delivery only; max:listen (Long Polling) is unaffected, so an architecture choice between webhook and polling determines whether this lever exists at all.user_id (warning), never phone or hash, which narrows PII scope in logging/retention reviews. Session id regeneration on confirm is an explicit anti-session-fixation control to cite in the threat model.contact_confirmed (was, in at least one integrator, max.webapp.contact_confirmed). Without MAX_WEBAPP_SESSION_CONTACT_CONFIRMED override, previously confirmed sessions must re-verify — acceptable in some apps, a conversion hit in others. This is a product call, not just a config detail.php artisan max:subscribe <url> must be run again (a POST to an existing URL updates the subscription; verified 6 → 13 types on a live subscription). Without it, the package is updated but edits/deletes still never arrive — and it will present as a release bug. Schedule this in the rollout runbook and confirm with php artisan max:subscriptions.max_users.phone; only the chat request_contact attachment is (via PersistMaxUserPhoneListener). Product specs that assume “we have the phone now” after bridge verification are wrong until a persistence path is designed.Adopt when:
geekcodev/max-php-client ^1.1.8 or later and can run composer update geekcodev/max-php-client to reach ^1.1.10; the core bump is public-API compatible and the adapter adds classes rather than changing signatures.Look elsewhere or defer when:
max_users.phone — that flow does not exist; only the chat request_contact path persists a phone.update_types does not apply there.max:subscribe step, or your handlers cannot tolerate the newly delivered event types (edits, deletes, clears, renames, membership).comment_* and bot_admin_permissions_changed are deliberately excluded from the default, so you would be maintaining an override.^1.1.10, since WebAppContactVerifier lives in the core.WebAppContext::verifyContact(...) was intentionally not added; calls go directly to WebAppContactService, which is fine but means one more explicit dependency in your application code.Executives (one paragraph). This release closes a silent data-loss gap: the webhook subscription previously delivered only 6 of the 13 event types the adapter consumes, so message edits, deletions, dialog clears, chat renames and membership changes never arrived and produced no error. It also adds a vetted mini-app phone-verification path, so we can gate high-value actions on a confirmed number without building and auditing our own signature and replay-protection code. Public APIs are unchanged, there are no migrations, and the risk is mostly operational: one required re-subscription command after deploy. If we skip it, the upgrade will look broken even though it is not.
Engineering. WebAppContactService and WebAppSession are thin, final/read-only wrappers over core Security\WebAppContactVerifier; the algorithm is not duplicated. Both are registered as singletons alongside WebAppDataValidator/WebAppContext. Configuration is additive: webapp.session.contact_confirmed and webhook.update_types, both with safe defaults — empty or malformed values fall back to the 13-type default, so an accidental “subscribe to nothing” is impossible. Test coverage is credible where it matters: synthetic valid signatures, hex/base64/URL-safe base64 encodings, wrong hash, swapped userId, swapped phone, formatted-number normalization, expired authDate and the max_age=0 case, empty inputs, non-numeric user_id, log-content assertions proving no phone or hash leaks, session id regeneration, per-user_id flag matching, custom keys, and subscribe-command coverage for 13 types plus overrides and the empty-override regression.
Risks to state plainly. First, this is a behavioral change shipped in a patch release: the default subscription list changes, and user_added/user_removed are currently a deliberate no-op in PersistMaxChatListener, so no immediate processing load, but hosts must confirm their handlers tolerate the rest. Second, the mandatory max:subscribe re-run is the single most likely source of “we upgraded and edits still don’t arrive” tickets; put it in the runbook, then verify with max:subscriptions. Third, the session flag key rename can force re-verification of already-confirmed users unless we set MAX_WEBAPP_SESSION_CONTACT_CONFIRMED to the old key; decide this before rollout rather than after. Fourth, do not promise stakeholders that bridge-verified phones become stored phone numbers — that remains a separate, unbuilt flow.
How can I help you explore Laravel packages today?