REST-Service für Amazon-Alexa-Cookies auf Basis von alexa-cookie2.
Der Service stellt einen browsergestützten Login-/Proxy-Flow bereit,
speichert den kompletten Registrierungszustand persistent unter /data,
liefert bei Bedarf eine zu 37_echodevice.pm kompatible JSON-Cachedatei
und kann bestehende Cookies zyklisch oder per API refreshen.
- Node.js REST-Service
- Dockerfile
- docker-compose.yml
.env.example- Hilfsskripte für FHEM
GET /healthz– HealthcheckGET /api/status– Status ohne GeheimnisseGET /api/state– gespeicherter Zustand, standardmäßig maskiertGET /api/state?raw=1– kompletter gespeicherter ZustandPOST /api/cookie/login/start– startet den Login-/Proxy-FlowGET /api/cookie/login/url– startet den Login-/Proxy-Flow und liefert die Proxy-URLPOST /api/cookie/refresh– Refresh mitformerRegistrationData, optionalsave=<filename>GET /api/cookie– JSON-Cachedatei imechodevice-Schema, optionalsave=<filename>GET /api/cookie/text– nur der Cookie als Text
Die bisherigen Pfade /api/login/start, /api/login/url, /api/refresh und /api/cookie.txt
sind abgekündigt.
cp .env.example .envSicheren AUTH_TOKEN erzeugen und in .env eintragen:
openssl rand -hex 32Wichtig:
PROXY_PUBLIC_HOSTmuss die Adresse oder den Hostnamen enthalten, unter dem du den Login-Proxy im Browser wirklich aufrufstAUTH_TOKENsetzen, wenn die API nicht offen im LAN stehen soll
| Variable | Status | Standardwert | Bedeutung |
|---|---|---|---|
HOST |
Optional | 0.0.0.0 |
Bind-Adresse der REST-API im Container |
PORT |
Optional | 58080 |
Port der REST-API im Container |
AUTH_TOKEN |
Empfohlen | leer | Shared Secret fuer x-auth-token; im produktiven Betrieb praktisch Pflicht |
DATA_DIR |
Optional | /data |
Basisverzeichnis fuer persistente Servicedaten |
STATE_FILE |
Optional | ${DATA_DIR}/alexa-registration.json |
Persistierter Alexa-Registrierungszustand |
METADATA_FILE |
Optional | ${DATA_DIR}/service-metadata.json |
Metadaten zur letzten Aktualisierung |
COOKIE_EXPORT_DIR |
Optional | ${DATA_DIR}/cookie-export |
Exportverzeichnis fuer per save=<filename> erzeugte Cookie-Dateien |
DEBUG_HTML_DIR |
Optional | ${DATA_DIR}/debug-html |
Ablageort fuer Debug-Artefakte aus dem Login-Flow |
AMAZON_PAGE |
Optional | amazon.de |
Ziel-Region fuer den Amazon-Login |
BASE_AMAZON_PAGE |
Optional | amazon.com |
Basis-Domain fuer den Login-Flow; fuer westliche Regionen in der Regel amazon.com, fuer Japan amazon.co.jp |
ACCEPT_LANGUAGE |
Optional | de-DE |
Sprach-Header fuer den Login-Flow |
PROXY_PUBLIC_HOST |
Pflicht | leer | Von Browsern erreichbare Adresse oder DNS-Name des Docker-Hosts fuer den Login-Proxy |
PROXY_LISTEN_BIND |
Optional | 0.0.0.0 |
Bind-Adresse des Login-Proxys im Container |
PROXY_PORT |
Optional | 58090 |
Port des Login-Proxys im Container |
PROXY_ONLY |
Optional | true |
Startet den Login standardmaessig im Proxy-Modus |
SETUP_PROXY |
Optional | true |
Aktiviert die Proxy-Initialisierung fuer den Login-Flow |
APP_NAME |
Optional | FHEM EchoDevice Cookie Service |
Anzeigename des virtuellen Geraets bei Amazon |
USE_HERMES |
Optional | false |
Aktiviert Hermes-spezifisches Verhalten von alexa-cookie2 |
REFRESH_SCHEDULE_HOURS |
Optional | 24 |
Intervall fuer den automatischen Refresh |
REFRESH_MIN_AGE_HOURS |
Optional | 6 |
Mindestalter des Zustands vor einem automatischen Refresh |
REQUEST_TIMEOUT_MS |
Optional | 30000 |
Timeout fuer Netzwerkoperationen in Millisekunden |
LOG_LEVEL |
Optional | combined |
Format/Level fuer HTTP-Request-Logging |
AMAZON_PAGE und BASE_AMAZON_PAGE haben unterschiedliche Aufgaben:
AMAZON_PAGEist die eigentliche Ziel-Region fuer das Amazon-Konto, z.B.amazon.de.BASE_AMAZON_PAGEist die Basis-Domain des Login-Flows.
Empfehlung:
- Fuer Deutschland und die meisten westlichen Laender
AMAZON_PAGE=amazon.de|amazon.fr|amazon.it|amazon.es|amazon.co.ukpassend zur Region setzen, aberBASE_AMAZON_PAGE=amazon.combelassen. - Nur fuer Japan
BASE_AMAZON_PAGE=amazon.co.jpsetzen. BASE_AMAZON_PAGEnur dann vonamazon.comabweichend setzen, wenn der Login-Flow mit dem Standardwert nicht funktioniert oderalexa-cookie2dies fuer die jeweilige Region verlangt.
docker pull ghcr.io/fhem/alexa-cookie-service:0.3.0
docker compose up -dcurl -H "x-auth-token: change-me" http://127.0.0.1:58080/api/statuscurl -X POST -H "x-auth-token: change-me" http://127.0.0.1:58080/api/cookie/login/startDanach den Proxy im Browser aufrufen:
http://<PROXY_PUBLIC_HOST>:58090/
Der komplette Persistenzzustand wird unter STATE_FILE gespeichert.
Dieser Zustand ist die Grundlage für spätere Refreshes.
Zusätzlich schreibt der Service:
METADATA_FILE– Metadaten zum letzten Update
Wichtig:
Wenn save=<filename> fuer POST /api/cookie/refresh oder GET /api/cookie verwendet wird,
wird die JSON-Datei absichtlich kompakt in einer einzelnen Zeile geschrieben,
weil 37_echodevice.pm den JSON-Import zeilenbasiert implementiert und mit mehrzeiligem
Pretty-Print nicht korrekt arbeitet.
save ist dabei nur ein Dateiname, kein Pfad.
Die Datei wird immer unterhalb von COOKIE_EXPORT_DIR gespeichert.
COOKIE_EXPORT_FILE wird aus Kompatibilitaetsgruenden vorerst noch als Legacy-Name akzeptiert.
Das exportierte JSON hat dieses Schema:
{
"localCookie": "...",
"csrf": "...",
"refreshToken": "...",
"macDms": "...",
"formerRegistrationData": { "...": "..." }
}Verhalten der Endpunkte:
- Login schreibt nur
STATE_FILEundMETADATA_FILE POST /api/cookie/refreshschreibt keine Exportdatei ohnesave=<filename>GET /api/cookieliefert das JSON im Response und speichert es nur mitsave=<filename>GET /api/cookie/textliefert den Cookie als eine Zeile Text- alle JSON-Ausgaben/-Dateien fuer das
echodevice-Schema sind kompakt und ohne Zeilenumbrueche save=696result.jsonspeichert beiCOOKIE_EXPORT_DIR=/opt/fhem/cache/alexa-cookienach/opt/fhem/cache/alexa-cookie/696result.json
Beispiele:
curl -X POST -H "x-auth-token: change-me" \
"http://127.0.0.1:58080/api/cookie/refresh?save=696result.json"curl -H "x-auth-token: change-me" \
"http://127.0.0.1:58080/api/cookie?save=696result.json"Der Service ist bewusst als separater Node.js-Container aufgebaut und nicht als Erweiterung innerhalb des FHEM-Docker-Containers.
Der Hauptgrund ist die klare Trennung der Laufzeitumgebungen:
- der FHEM-Container ist primaer fuer Perl und eine moeglichst klassische, gut wartbare FHEM-Umgebung gedacht
alexa-cookie2bringt eine eigene Node.js-Runtime, eigene Abhaengigkeiten und einen eigenen Update-Zyklus mit- ein gemeinsames Image wuerde zwei technisch unterschiedliche Aufgabenbereiche vermischen und dadurch Wartung, Debugging und Updates unnoetig verkomplizieren
Seit Version 5 des FHEM-Images ist zudem kein Node Package Manager mehr im FHEM-(Perl-)Container enthalten. Fuer Node-basierte Helfer musste deshalb bislang meist ein eigenes, angepasstes FHEM-Image gebaut werden.
Dieses Projekt verfolgt stattdessen bewusst ein Service-Muster:
FHEM / echodevice -> HTTP/REST -> alexa-cookie-service -> Amazon
Das bedeutet:
37_echodevice.pmbleibt im normalen FHEM-Container- der Node.js-Dienst kapselt Login-, Refresh- und Cookie-Export-Funktionen
- die Kopplung erfolgt ueber eine klar definierte HTTP-Schnittstelle
- beide Container koennen getrennt gebaut, aktualisiert, neu gestartet und debuggt werden
Die Trennung ist damit keine unnoetige Zusatzkomplexitaet, sondern eine bewusste Designentscheidung zugunsten von Stabilitaet, Wartbarkeit und klaren Zustaendigkeiten.
Das Repository enthält generische FHEM-Helfer.
Die konkrete Einbindung von 37_echodevice.pm bleibt installationsabhängig.
Ein typisches Setup ist ein gemeinsamer Docker-Stack mit FHEM.
Dabei teilen sich beide Container ein dediziertes Exportverzeichnis,
in das der Service JSON nur dann schreibt, wenn save=<filename> mitgegeben wird.
Wenn der Cookie-Service mit derselben UID/GID wie FHEM läuft,
bleiben Besitzrechte und Schreibzugriffe konsistent.
Funktionsfähiges Beispiel für einen gemeinsamen Compose-Stack:
services:
alexa-cookie-service:
image: ghcr.io/fhem/alexa-cookie-service:0.3.0
volumes:
- ./alexa-cookie-data:/data
- ./fhem/cache/alexa-cookie:/opt/fhem/cache/alexa-cookie
environment:
AUTH_TOKEN: change-me
COOKIE_EXPORT_DIR: /opt/fhem/cache/alexa-cookie
PROXY_PUBLIC_HOST: 192.168.178.10
ports:
- "58090:58090"
networks:
- fhem_cookie_net
restart: unless-stopped
user: "6061:6061"
fhem:
image: ghcr.io/fhem/fhem-minimal-docker:5.2.7-bookworm
volumes:
- "./fhem/:/opt/fhem/"
- "./fhem/cache/alexa-cookie:/opt/fhem/cache/alexa-cookie"
environment:
FHEM_UID: 6061
FHEM_GID: 6061
TIMEOUT: 10
RESTART: 1
TZ: Europe/Berlin
ports:
- "8083:8083"
networks:
- fhem_cookie_net
restart: always
networks:
fhem_cookie_net:
driver: bridgeIn diesem Setup:
- FHEM erreicht die API intern unter
http://alexa-cookie-service:58080 - der Login-Proxy bleibt über
http://<PROXY_PUBLIC_HOST>:58090/vom Browser erreichbar - das gemeinsam genutzte Exportverzeichnis liegt bei
./fhem/cache/alexa-cookie - der konkrete Exportname wird per
save=<filename>an den API-Aufruf uebergeben - das AUTH Token "change-me" sollte durch eine zufällige Zeichenkette ersetzt werden:
openssl rand -hex 32liefert eine solche Zeichenkette.
Das Beispiel verwendet ghcr.io/fhem/fhem-minimal-docker:5.2.7-bookworm,
das veröffentlichte Image ghcr.io/fhem/alexa-cookie-service:0.3.0
und ein dediziertes Docker-Netz.
Wichtig:
PROXY_PUBLIC_HOST ist in diesem Szenario die Adresse oder der DNS-Name des Docker-Hosts,
also des Rechners, auf dem die Container laufen.
Gemeint ist nicht der Containername alexa-cookie-service
und auch nicht die interne Docker-IP,
weil der Login-Proxy vom Browser außerhalb des Docker-Netzes erreichbar sein muss.
Wichtig für Dateirechte:
Der Cookie-Service läuft hier mit user: "6061:6061"
und damit passend zu FHEM_UID/FHEM_GID.
So werden neu geschriebene Dateien in ./fhem/cache/alexa-cookie
mit kompatiblen Besitzrechten angelegt,
statt als root.
Wenn 37_echodevice.pm im FHEM-Container läuft, liegt das gemeinsame Exportverzeichnis
typischerweise unter /opt/fhem/cache/alexa-cookie.
37_echodevice.pm importiert externe Cookie-Daten nicht automatisch beim
Start.
Das Modul liest die Datei nur ueber die interne Routine
echodevice_NPMWaitForCookie().
Ausserdem erwartet es keinen festen Standardnamen wie result.json, sondern
einen expliziten Dateinamen im Format <NR>result.json, also die interne
FHEM-Nummer des echodevice-Devices vorangestellt.
Die eigentliche Integration besteht daher aus vier Bausteinen:
-
echodevicein FHEM zuerst normal anlegen. Erst dadurch existiert das Device und bekommt eine interneNR. Im folgenden Beispiel heisst das DeviceAlexaAccountund wurde so erzeugt:defmod AlexaAccount echodevice xxx@xxx.xx xxx attr AlexaAccount room Amazon -
Ein FHEM-Device anlegen, das den Service anspricht. In der Praxis ist das meist ein
HTTPMOD, das den Refresh-Endpunkt aufruft und dabei das Token fuerx-auth-tokenmitliefert. Diese API-Ansteuerung ist die Grundlage fuer den externen Refresh, aber fuer sich allein noch keineechodevice-Integration. -
Einen periodischen Trigger fuer den Refresh anlegen. Dafuer eignet sich typischerweise ein
at, das z.B. regelmaessigset AlexaCookieService refreshaufruft. -
Ein
notifyanlegen, das nach dem Schreiben einer neuen Cookie-Dateiechodevice_NPMWaitForCookie()fuer das betroffeneechodeviceaufruft. Erst dieser Schritt uebergibt die extern erzeugte Datei an37_echodevice.pm.
Die NR des betroffenen echodevice wird inzwischen beim API-Aufruf
uebergeben.
Der Service kann damit Dateiname und Pfad fuer den externen
Cookie-Import direkt korrekt erzeugen.
Das Modul erwartet weiterhin:
<fhem_home>/cache/alexa-cookie/<NR>result.json
Beispiel fuer NR = 696 und fhem_home = /opt/fhem:
/opt/fhem/cache/alexa-cookie/696result.json
Der Dateiname 696result.json wird spaeter als save-Parameter benoetigt.
Optional, kann mittels attr <echodevice> fhem_home der tatsaechliche Pfad angepasst werden.
Beispiel:
attr AlexaAccount fhem_home /opt/fhem
AlexaAccount ist dabei nur ein Beispielname und muss durch den Namen
deines eigenen echodevice-Account-Devices ersetzt werden.
-
Den
alexa-cookie-service-Container so einrichten, dassCOOKIE_EXPORT_DIRauf das gemeinsame cache Verzeichnis von alexa-cookie zeigt. Beispiel:environment: COOKIE_EXPORT_DIR: /opt/fhem/cache/alexa-cookie
Das bloße Vorhandensein des Verzeichnisses reicht noch nicht fuer den Import; entscheidend ist der passende
save=<filename>-Aufruf. -
Um
alexa-cookie-serviceaus FHEM heraus steuern zu können, nutzen wir HTTPMOD. Das steuerndeHTTPMODfuer denalexa-cookie-serviceanlegen. Im Beispiel heisst esAlexaCookieService. Beispiel:define AlexaCookieService HTTPMOD http://alexa-cookie-service:58080/api/status 300 attr AlexaCookieService room Amazon attr AlexaCookieService replacement01Mode key attr AlexaCookieService replacement01Regex %%ACS_TOKEN%% attr AlexaCookieService replacement01Value alexa_cookie_service_token attr AlexaCookieService replacement02Mode key attr AlexaCookieService replacement02Regex %%ACS_EXPORT_NAME%% attr AlexaCookieService replacement02Value alexa_cookie_service_export_name attr AlexaCookieService reading01JSON ok attr AlexaCookieService reading02JSON updatedAt attr AlexaCookieService reading03JSON ageHours attr AlexaCookieService reading04JSON hasCookie attr AlexaCookieService reading05JSON hasRefreshToken attr AlexaCookieService reading06JSON proxyUrl attr AlexaCookieService reading07JSON message attr AlexaCookieService reading08JSON error attr AlexaCookieService set01Name loginStart attr AlexaCookieService set01NoArg 1 attr AlexaCookieService set01Method POST attr AlexaCookieService set01URL http://alexa-cookie-service:58080/api/cookie/login/start attr AlexaCookieService set01Header1 x-auth-token: %%ACS_TOKEN%% attr AlexaCookieService set01Header2 Content-Type: application/json attr AlexaCookieService set01Data {} attr AlexaCookieService set01ParseResponse 1 attr AlexaCookieService set02Name refresh attr AlexaCookieService set02NoArg 1 attr AlexaCookieService set02Method POST attr AlexaCookieService set02URL http://alexa-cookie-service:58080/api/cookie/refresh?save=%%ACS_EXPORT_NAME%% attr AlexaCookieService set02Header1 x-auth-token: %%ACS_TOKEN%% attr AlexaCookieService set02Header2 Content-Type: application/json attr AlexaCookieService set02Data {} attr AlexaCookieService set02ParseResponse 1 attr AlexaCookieService get01Name loginUrl attr AlexaCookieService get01URL http://alexa-cookie-service:58080/api/cookie/login/url attr AlexaCookieService get01Header1 x-auth-token: %%ACS_TOKEN%% attr AlexaCookieService showMatched 1 attr AlexaCookieService showError 1 attr AlexaCookieService room Amazon attr AlexaCookieService timeout 8 -
Das AUTH-Shared-Secret und den Exportnamen hinterlegen. Dafuer muss
set AlexaCookieService storeKeyValue ...verwendet werden. An dieser Stelle werden das zuvor peropenssl rand -hex 32erzeugte Secret und der aus derNRabgeleitete Exportname anstelle vonchange-meeingesetzt. Beispiel:set AlexaCookieService storeKeyValue alexa_cookie_service_token change-me set AlexaCookieService storeKeyValue alexa_cookie_service_export_name 696result.json -
Einen periodischen Trigger anlegen, der den Refresh des Cookies ueber dieses
HTTPMODausloest. Beispiel:define at_AlexaCookieServiceRefresh at +*16:00:00 set AlexaCookieService refresh attr at_AlexaCookieServiceRefresh room Amazon -
Das Attribut
intervallogindesechodevice-Account-Devices auf einen Wert in Sekunden setzen, der groesser als das Intervall desatist, damit der externe Refresh vorher greift. Beispiel beiat +*16:00:00:attr AlexaAccount intervallogin 57660 -
Ein
notifyanlegen, dessen Regex auf den Namen desHTTPMODAlexaCookieServiceverweist und das den Import in37_echodevice.pmanstoesst. Beispiel:define n_AlexaAccountCookieImport notify AlexaCookieService:refresh { $main::NPMLoginTyp = 'NPM Login Refresh external';; echodevice_NPMWaitForCookie($defs{'AlexaAccount'});; } attr n_AlexaAccountCookieImport room Amazon -
Jetzt einmalig den Login starten Dazu per
get AlexaCookieService loginUrldie Login-URL abrufen und die in der Antwort enthaltene Proxy-URL im Browser oeffnen. Dort den Amazon-Login inklusive eventueller MFA komplett abschliessen, bis der Service die RueckgabeAmazon Alexa Cookie successfully retrieved. You can close the browser.anzeigt. Damit wird die Anmeldung initial eingerichtet. -
Nachdem alle beteiligten Devices eingerichtet sind, den Import fuer das Account-Device einmalig manuell ausfuehren, damit echodevice das Initalcookie akzeptiert. Beispiel:
set at_AlexaCookieServiceRefresh execNow
Das Zusammenspiel sieht dann so aus:
```mermaid
flowchart LR
ED["echodevice-Account: AlexaAccount"] --> NR["NR ermitteln"]
NR --> PATH["Zielpfad ableiten: <fhem_home>/cache/alexa-cookie/<NR>result.json"]
PATH --> ENV["COOKIE_EXPORT_DIR als Exportverzeichnis setzen"]
ENV --> SVC["alexa-cookie-service"]
HTTPMOD["HTTPMOD: AlexaCookieService"] -->|set refresh -> POST /api/cookie/refresh?save=<NR>result.json| SVC
HTTPMOD -->|get exportCookie -> GET /api/cookie?save=<NR>result.json| SVC
AT["at: AlexaCookieServiceRefresh"] --> HTTPMOD
INIT["notify: global:INITIALIZED"] --> TMP1["-temporary at: exportCookie"]
INIT --> TMP2["-temporary at: echodevice_NPMWaitForCookie"]
TMP1 --> HTTPMOD
SVC --> FILE["Cookie-Datei <NR>result.json"]
FILE --> NOTIFY["notify: AlexaCookieService:refresh"]
NOTIFY --> IMPORT["echodevice_NPMWaitForCookie fuer AlexaAccount"]
TMP2 --> IMPORT
IMPORT --> ED
Der Name AlexaAccount im Beispiel bezieht sich auf dieses Define:
defmod AlexaAccount echodevice xxx@xxx.xx xxx
attr AlexaAccount room Amazon
Erst nach dem Trigger des notify uebernimmt 37_echodevice.pm die exportierte
Datei in seine internen Werte.
Danach sollten im Device unter anderem COOKIE_TYPE = NPM_Login und ein
gesetztes .COOKIE sichtbar werden.
Hilfsskripte:
scripts/fhem_fetch_cookie.shscripts/fhem_dump_cookie_json.shscripts/example_fhem_notify.txt
Typische Varianten:
SERVICE_URL=http://127.0.0.1:58080 AUTH_TOKEN=change-me OUT_FILE=/opt/fhem/cache/alexa-cookie-external-cookie.txt ./scripts/fhem_fetch_cookie.shSERVICE_URL=http://127.0.0.1:58080 AUTH_TOKEN=change-me OUT_FILE=/opt/fhem/cache/alexa-cookie-external-state.json ./scripts/fhem_dump_cookie_json.sh- Die REST-API liefert Geheimnisse. Setze
AUTH_TOKEN. - Stelle den Service idealerweise nur im internen Netz bereit.
- Nutze bei Remote-Zugriff einen Reverse Proxy mit TLS und zusätzlicher Authentifizierung.
- Lege
/dataauf ein persistentes Volume.
- Amazon kann Login-Flows jederzeit ändern.
- MFA, Captcha und Regionseffekte bleiben möglich.
- Der initiale Login ist absichtlich browsergestützt; das ist robuster als ein erzwungener Headless-Flow.
37_echodevice.pm liest die Cookie-Daten anstatt aus einer lokalen Datei direkt von diesem Service.
Das echomodul FHEM triggert bei Bedarf den Refresh per REST API und verwendet die vorhandenen Werte aus dem Service:
- den
AUTH_TOKENaus der.envin FHEM hinterlegen - aus FHEM
POST /api/cookie/refresh?save=<filename>aufrufen - danach den aktuellen Cookie mit
GET /api/cookieabrufen und inechodeviceverwenden.
Wenn FHEM und alexa-cookie-service in Containern im selben Docker-Netz laufen, muss der Service-Name verwendet werden.
http://alexa-cookie-service:58080
Wichtig:
- der API-Port des Services ist standardmaessig
58080 - der Browser-Login selbst laeuft ueber den Proxy-Port
58090 - fuer die Auswertung von
set-Antworten istsetXXParseResponse 1noetig
Ein minimales Shell-Beispiel liegt zusaetzlich in scripts/example_fhem_notify.txt.