← Alle Beiträge

Shopware: WebhookEventMessage scheitert mit 401 Unauthorized an swag-analytics.apps.shopware.io

Shopware: WebhookEventMessage scheitert mit 401 Unauthorized an swag-analytics.apps.shopware.io

Im Log steht seit Wochen derselbe CRITICAL-Eintrag aus dem Messenger, mehrmals am Tag, und im Shop selbst merkt man nichts davon. Bestellungen laufen, der Checkout geht. Kaputt ist nur die Verbindung zur App Shopware Analytics, und zwar so gründlich, dass jeder einzelne Webhook drei Mal zugestellt wird, drei Mal abgelehnt wird und dann im Nichts verschwindet.

In einem Shop, den wir überwachen, kam die Meldung in vier Wochen über hundert Mal. Ausgelöst hatte das eine Datenbankkopie, die jemand Monate vorher für eine Staging-Umgebung gezogen hatte.

Die Fehlermeldung

messenger.CRITICAL: Error thrown while handling message
Shopware\Core\Framework\Webhook\Message\WebhookEventMessage.
Removing from transport after 3 retries.
Error: "Handling "Shopware\Core\Framework\Webhook\Message\WebhookEventMessage" failed:
Webhook "018f2c3d4e5f6a7b8c9d0e1f2a3b4c5d" from "018f2c3d4e5f6a7b8c9d0e1f2a3b4c5e"
failed with error: Client error: `POST https://swag-analytics.apps.shopware.io/api/webhook`
resulted in a `401 Unauthorized` response:
{"errors":[{"code":401,"status":"401","title":"Unauthorized", ...

Die erste ID ist der Webhook, die zweite die App. swag-analytics.apps.shopware.io ist der App-Server von Shopware Analytics. Die Meldung kann genauso gut eine andere App-URL enthalten, das Muster bleibt dasselbe.

Was dahintersteckt

Wenn Shopware ein Event an eine App schickt, signiert es den Request. Im Header shopware-shop-signature steht ein HMAC, berechnet mit einem Secret, das bei der Registrierung der App zwischen Shop und App-Server ausgehandelt wurde. Der App-Server prüft diese Signatur. Passt sie nicht zu dem Secret, das er für diese Shop-ID gespeichert hat, antwortet er mit 401.

Ein 401 an dieser Stelle heißt also: Der App-Server kennt die Shop-ID, hat für sie aber ein anderes Secret gespeichert als das, mit dem dein Shop signiert.

Der häufigste Weg dorthin ist eine Staging- oder Testumgebung, die als Kopie der Live-Datenbank entstanden ist. In der Kopie steckt dieselbe Shop-ID (core.app.shopId in system_config) wie im Live-Shop. Weil Staging eine andere APP_URL hat, erkennt Shopware dort die URL-Änderung und will wissen, wie es damit umgehen soll. Wählt jemand dort MoveShopPermanently, registriert sich die Staging-Kopie mit der alten Shop-ID neu beim App-Server und handelt dabei ein neues Secret aus. Die Shopware-Doku sagt dazu ausdrücklich, dass die alte Installation danach nicht mehr funktioniert, weil die Apps ihr Secret nicht mehr anerkennen. Die alte Installation ist in diesem Fall dein Live-Shop.

Ab dann schickt der Live-Shop jeden Webhook mit dem alten Secret, der App-Server lehnt ab, der Messenger versucht es drei Mal und wirft die Nachricht weg. Die Analytics-Daten im Live-Shop bleiben stehen.

Weitere Wege zum selben Zustand, seltener: Die App wurde auf einer zweiten Installation mit derselben Shop-ID neu installiert, oder die Datenbank wurde aus einem Backup zurückgespielt, das älter ist als die letzte Registrierung.

Prüfen, ob es wirklich das ist

Zuerst die Frage, die man sich ungern stellt: Gibt es eine Staging-, Test- oder Entwicklerkopie dieses Shops, die irgendwann aus der Live-Datenbank gezogen wurde? Und wurde dort beim ersten Öffnen der Administration ein Dialog zur geänderten App-URL weggeklickt?

Dann die Shop-ID in beiden Umgebungen vergleichen:

SELECT configuration_value
FROM system_config
WHERE configuration_key = 'core.app.shopId';

Stehen auf Live und Staging dieselben Werte, hast du die Ursache so gut wie sicher gefunden.

Welche Webhooks betroffen sind und wie oft sie schon fehlgeschlagen sind, zeigt die Tabelle webhook:

SELECT name, event_name, url, error_count, active
FROM webhook
WHERE url LIKE '%swag-analytics%';

Ein hoher error_count bei allen Webhooks einer App, während andere Apps sauber laufen, passt genau zu diesem Bild. Fällt der 401 dagegen für alle Apps gleichzeitig an, lohnt sich zuerst ein Blick auf die APP_URL des Live-Shops selbst.

Die Lösung

Die Reihenfolge ist wichtig, sonst reparierst du Live und machst es beim nächsten Staging-Refresh wieder kaputt.

Erstens Staging von der Live-Shop-ID trennen. Auf der Staging-Kopie die Apps neu installieren lassen, damit sie eine eigene Shop-ID bekommt:

bin/console app:shop-id:change

Dort die Strategie ReinstallApps wählen. Staging bekommt eine neue Shop-ID und registriert sich mit seiner eigenen Domain neu. Willst du auf Staging gar keine Apps, ist UninstallApps die sauberere Wahl. Auf älteren Versionen heißt der Befehl app:url-change:resolve, er funktioniert in aktuellen Versionen noch als Alias und soll mit 6.8.0 entfallen.

Zweitens den Live-Shop neu registrieren. Die Shopware-Doku zu Shopware Analytics beschreibt für genau den Staging-Fall diesen Befehl auf dem Live-System:

bin/console app:url-change:resolve reinstall-apps

Er erzeugt für den Live-Shop eine neue Shop-ID. Danach richtest du Shopware Analytics neu ein. Das betrifft alle installierten Apps, nicht nur Analytics, und die App-seitigen Daten zur alten Shop-ID sind danach nicht mehr erreichbar. Apps, die etwas an die Shop-ID knüpfen, etwa Zahlungsanbieter oder ERP-Connectoren, können deshalb eine neue Einrichtung brauchen. Geh vor dem Lauf auf Live die Liste der installierten Apps durch.

Ob es bei einem reinen 401 von Analytics reicht, nur diese eine App zu deinstallieren und neu zu installieren, steht nirgends in der Doku. Als gesicherten Weg kann ich es deshalb nicht empfehlen. Die Registrierung bleibt an die Shop-ID gebunden, und die ist der Kern des Problems.

Drittens den Refresh-Prozess anpassen. Wenn eure Staging-Umgebung regelmäßig aus Live gezogen wird, gehört app:shop-id:change mit ReinstallApps oder UninstallApps fest in das Skript, das den Dump einspielt. Sonst steht die nächste Kopie wieder mit der Live-Shop-ID im Netz.

Wenn das nicht hilft

Die Nachrichten, die schon aus der Queue geflogen sind, kommen nicht zurück. Shopware wirft sie nach dem dritten Versuch weg, die Analytics-Daten für diesen Zeitraum fehlen also auf dem App-Server. Das ist ärgerlich, lässt sich aber nicht nachträglich reparieren.

Kommt nach dem Neu-Registrieren weiter 401, prüfe, ob die APP_URL in der .env des Live-Shops zur tatsächlich erreichbaren Domain passt, ob ein Proxy oder WAF den Header shopware-shop-signature entfernt, und ob die Kopie wirklich die einzige war. Ein vergessener zweiter Klon auf einem Entwicklerrechner reicht.

Hilfreich bei der Fehlersuche: die Shopware-Doku zur App-Registrierung und den Strategien bei URL-Änderungen und die Hinweise zu Shopware Analytics.

Dieser Fehler hat wochenlang im Hintergrund gearbeitet, ohne dass im Shop etwas ausfiel, und genau so bleiben solche Fälle liegen. Wer nicht jeden Morgen durch die Logs scrollen will: ShopSignal ist dafür gedacht, Shopware-6-Shops im Blick zu behalten und zu melden, wenn im Hintergrund etwas stehenbleibt.