The ?validationToken=… query param value, when present (the handshake).
The shared secret set on subscription creation (resolved upstream — never inlined).
The clientState of each notification in the POST body (empty for handshake).
The discriminated validation result.
Performs the Graph change-notification gate, pure + exported so the MJAPI router calls it on every
POST /meetings/teams/notificationsrequest (these can't carry an MJ JWT — the handshake +clientStateshared secret are the gate):validationTokenquery param, it's the subscription-validation handshake → return{ Kind: 'validation', ValidationToken }(the router echoes it back astext/plain200). A blank token rejects.clientState; verify each (constant-time) against the secret we set when creating the subscription. Any mismatch rejects the whole batch (an attacker who can't produce the secret must not drive bot behavior).