| Secret | Lives in | Never in |
|---|---|---|
| GlassHive API key | Worker secret | extension, repo, browser |
| OIT API key | Worker secret | extension, repo, browser |
| Rep identity | Entra access token, verified per request | request body |
The extension holds no shared secret. Its only credential is the signed Entra token belonging to the rep using it.
A call is only written to GlassHive if all three agree:
- Entra issues a token. The app registration has Assignment required enabled, so only members of the dialer access group can obtain one.
- The Worker validates it — RS256 signature against tenant JWKS, plus
tid,iss,aud,exp/nbf, and theDialer.Callscope. App-only tokens are refused; a leaked client credential cannot dial. - The rep exists in D1 and is active. This maps them to a GlassHive user id and an OIT extension.
Rep email comes from the verified token. A rep cannot log activity as a colleague, which the previous shared-token design allowed.
The Entra object id is pinned to the rep row on first sign-in. If a mailbox is later reassigned, the oid no longer matches and the dial is refused rather than attributed to the wrong GlassHive user.
Five routes, two of them authenticated and state-changing. This table is the
complete list — if a route exists in index.js and is not here, one of the two
is wrong:
| Route | Auth | Effect |
|---|---|---|
GET /health |
none | liveness only, discloses nothing |
GET /ext/update.xml |
none | extension version manifest; public by design |
GET /api/me |
Entra | reads the caller's own provisioning state |
POST /api/dial-intents |
Entra | creates one GlassHive activity |
POST /api/dial-intents/:id/notes |
Entra | writes notes on the caller's own call |
Both authenticated routes require an active reps row, not merely a valid
token: a deactivated rep holds a working Entra token until it expires, and
must not be able to keep writing into GlassHive through their old calls.
There are no diagnostic routes. /api/diag/oit, /api/diag/enrich and
/api/diag/originate existed to bring up the OIT integration and are gone.
They were gated on a single static header token, and behind it
/api/diag/originate placed real calls to an arbitrary number from an
arbitrary extension and /api/diag/enrich returned transcript text from
real customer calls. Bring-up is over; the equivalent probes are in
scripts/oit-*.ps1 and run against OIT directly under an operator's own
credentials. Do not reintroduce them into the Worker.
There are no inbound webhooks. Enrichment is an outbound poll triggered by
the dial. This is the single largest change from the pilot design, which
exposed unauthenticated /webhooks/oit and /webhooks/plaud endpoints that
would have accepted arbitrary text into any prospect's CRM record from any
source on the internet.
There is no admin page. Vendor credentials are set with wrangler secret put; rep provisioning is a D1 statement run by an operator. The pilot's
password-protected settings page — which accepted and stored every vendor key
over whatever transport the host happened to have — is gone.
The extension is registered as a public client ("Mobile and desktop
applications"), not a SPA. Entra caps refresh tokens issued to the SPA platform
at 24 hours and single use, which on a tool reps use all day means a forced
interactive sign-in every morning, surfacing as "the dialer stopped logging
calls". CORS is not a reason to prefer SPA here: the extension holds
host_permissions for login.microsoftonline.com, so its token request is not
a CORS request at all.
A failed silent refresh only clears the session when Entra actually refuses the
credential (invalid_grant and friends, or a non-429 4xx). A network failure or
a 5xx keeps the refresh token — throwing away a working credential over a blip
costs the rep a sign-in for a problem that fixes itself.
- Bodies capped at 8 KB, checked before and after read, returning 400 — not 500, which the extension's offline queue would treat as retryable and replay forever.
- 30 dials per rep per minute; 20 note saves per rep per minute.
destinationnormalised to E.164 and rejected if it is not a valid NANP number;glassHiveContactIdmust be a positive integer.- Client-supplied
occurredAt(used when replaying a queued offline dial) is clamped: no future-dating beyond clock skew, no backdating beyond 24h. - Internal errors return an opaque 500. Upstream vendor error bodies are logged, never echoed — they can carry key fragments and internal URLs.
Call records are matched to a dial intent by the UUID we minted, scoped to the rep's own extension and a time window around the click. Forging enrichment requires guessing a server-generated UUID, not knowing a colleague's email.
oit_call_id is UNIQUE, so a redelivered queue message or repeated CDR cannot
double-write. If two calls fit a window, the nearest in time wins; if none fit,
nothing is attached. An unattached call beats a call attached to the wrong
prospect.
Every dial, match, skip and abandonment is appended to audit_log with the
authenticated principal and a timestamp, so a disputed CRM activity can be
traced back to a person and a moment.
Call recordings are transcribed with Workers AI, inside Cloudflare. Audio is not sent to a third-party transcription vendor. Transcripts are stored in D1 and written into the GlassHive activity.
- Extension distribution. Load-unpacked installs can be modified locally by the rep. The manifest key pins the extension id, but managed deployment via Chrome/Edge policy is what actually enforces integrity. See ADMIN_SETUP.
- OIT payload shape is unverified. See VENDOR_REQUESTS.md.
- Transcription size cap. Recordings over 24 MB are linked but not transcribed. Long-call behaviour needs validating against a real recording.