Start here →
AGENTS.md·SPEC_INDEX.md·SECURITY.md.
| Field | Value |
|---|---|
| Module id | integrations-and-webhooks |
| Source path(s) | src/pages/integration/, src/pages/api/my-integrations.ts, src/pages/api/my-webhooks.ts, src/pages/api/webhooks.ts, src/pages/api/remove-authorization.ts, related components/stores |
| Doc kind | Module spec |
| Coverage score | 100% assessed 2026-07-24; 14/14 mandatory fields PRESENT, OAuth/API/store evidence routed |
| Generated from | module-spec @ 0.2.1 |
| generated_by / approved_by / updated_at | codex (gpt-5.6) / repository owner scope approval / 2026-07-24 |
| Validation status | pass-with-warnings; validator claude-opus-4-8-1m (runtime independent of codex), target HEAD b9c7321ee3642bdb0137734e187a102a7f5de9be, assessed 2026-07-24; 0 Blocking, 0 Important, 0 Medium, 2 Minor; full suite environment-blocked (Node 24 + registry pending) |
Current routes, shared adapters, stores/components, and tests define behavior. Prior OAuth/my-integrations/webhook specs were mapped to current operations, state, validation, and failure paths.
| Source material | Scope | Decision | Disposition |
|---|---|---|---|
| Integration OAuth specification | connect/callback | verified/corrected | Current cookie/state/navigation/redirect flow |
| My integrations API specification | list/disconnect UI/API | verified | Public surfaces and state flow |
| Webhook management specification | list/create/delete | verified/corrected | Current body/query validation and store transitions |
This module supports native integration connection, the authenticated My Integrations page, authorization removal, and webhook listing/creation/deletion. The browser uses same-origin APIs and Nano Stores; route handlers acquire server session tokens and call the Hydra/Webex adapter layer.
Owns user-visible integration and webhook lifecycle orchestration; upstream services remain the system-of-record.
Astro endpoints/pages, React islands, Nano Stores, Hydra/Webex adapters, secure cookies, Vitest.
src/pages/
├── integration/[integrationId]/connect.ts
├── integration/auth.ts
├── my-integrations.astro
└── api/{my-integrations,my-webhooks,webhooks,remove-authorization}.ts
src/components/{MyIntegrations,Webhooks,WebhookConnectButton,WebhookAppGate}.tsx
src/stores/{myIntegrations,authorizations,webhooks}Store.ts
| File | Holds |
|---|---|
integration/[integrationId]/connect.ts | connect validation/state/cookies/authorization redirect |
integration/auth.ts | state validation, token exchange, result redirect |
api/webhooks.ts | create/delete validation and response status |
api/my-*.ts | authenticated list responses |
src/lib/adapters/data-service.ts | integrations/webhooks domain calls |
| related stores/components | browser state/UI flow |
| Contract ID | Type | Surface | Purpose | Compatibility | Detail | Root |
|---|---|---|---|---|---|---|
integration.connect | HTTP | GET /integration/:integrationId/connect | Start native OAuth | path/query/redirect stable | route file | CONTRACTS.md |
integration.callback | HTTP | GET /integration/auth | Complete native OAuth | result query stable | route file | CONTRACTS.md |
integrations.list/remove | HTTP | GET /api/my-integrations, DELETE /api/remove-authorization | Manage authorizations | JSON/status stable | API files | CONTRACTS.md |
webhooks.list/create/delete | HTTP | GET /api/my-webhooks, POST/DELETE /api/webhooks | Manage webhooks | body/query/status stable | API files | CONTRACTS.md |
Authenticated server session, Hydra/Webex APIs, adapter types/validation constants, CSRF middleware/client helper, safe URL helpers, integration/webhook stores and notifications.
| ID | WHAT | WHY | Source Evidence | Test Evidence | Gaps | Confidence |
|---|---|---|---|---|---|---|
INT-R-001 | Integration connect MUST validate the integration ID, scopes, navigation provenance, authentication, and safe return path before setting OAuth cookies/redirecting. | Prevents open redirect, drive-by connect, and invalid upstream requests. | src/pages/integration/[integrationId]/connect.ts, src/lib/url-safety.ts | tests/unit/lib/integration-routes.test.ts | none | PRESENT |
INT-R-002 | Integration callback MUST delete temporary cookies, compare state, map denial/failure/success to safe return-query results, and never expose tokens to the browser. | Preserves secure understandable OAuth completion. | src/pages/integration/auth.ts | tests/unit/lib/integration-routes.test.ts | none | PRESENT |
INT-R-003 | My Integrations and My Webhooks list endpoints MUST require auth and return validated item arrays. | Prevents cross-user disclosure and malformed UI data. | src/pages/api/my-integrations.ts, src/pages/api/my-webhooks.ts, src/lib/adapters/data-service.ts | tests/unit/lib/api-routes.test.ts, tests/unit/lib/adapters/data-service.test.ts | none | PRESENT |
INT-R-004 | Webhook creation/deletion MUST validate body size, JSON/query fields, supported webhook type/name constraints, and use CSRF-protected authenticated calls. | Prevents abusive/invalid webhook mutations. | src/pages/api/webhooks.ts, src/lib/adapters/types.ts, src/middleware.ts | tests/unit/lib/api-webhooks.test.ts | none | PRESENT |
INT-R-005 | Browser stores/UI MUST represent independent loading/error/result state for list, add, delete, and disconnect operations and update lists only on success. | Prevents false success and stale management UI. | src/components/MyIntegrations.tsx, src/components/Webhooks.tsx, src/stores/webhooksStore.ts | tests/unit/stores/myIntegrationsStore.test.ts, tests/unit/stores/webhooksStore.test.ts, tests/unit/stores/authorizationsStore.test.ts | full page E2E may be environment-dependent | PRESENT |
Native integration OAuth uses short-lived cookies separate from the main login state. Management routes use the main server session and adapter facade. React components coordinate stores and same-origin API calls; successful mutations update lists and notifications without owning upstream persistence.
flowchart LR
UI --> ClientApi["same-origin API"]
ClientApi --> Auth["requireAuth"]
Auth --> Service["DataService/Hydra client"]
Service --> Webex
Webex --> Service --> APIResponse --> Stores --> UI
UI --> Connect --> CI["integration OAuth"] --> Callback --> UI
| Operation group | Diagram | Failure coverage |
|---|---|---|
| Native connect | connect → OAuth → callback | invalid ID/navigation/state, denial, exchange failure |
| List management | session → upstream → validated items | unauthenticated/upstream/schema error |
| Webhook mutation | CSRF/body validation → upstream → list update | validation, conflict/upstream failure |
sequenceDiagram
participant U as User
participant UI as Management UI
participant A as App Hub API
participant W as Webex
U->>UI: create/delete/disconnect
UI->>A: same-origin request + CSRF
A->>A: requireAuth + validate
A->>W: authorized mutation
alt success
W-->>A: result
A-->>UI: 201/204/200
UI->>UI: update store + success notification
else failure
W-->>A: error
A-->>UI: stable error status
UI->>UI: preserve list + error notification
end
sequenceDiagram
participant U as User
participant C as Connect route
participant I as Identity provider
participant A as Callback route
U->>C: navigate /integration/:id/connect
C->>C: validate id/scopes/navigation/session/return
C-->>I: state cookies + 302 authorize
I-->>A: code or denial + state
A->>A: clear cookies + compare state + exchange
A-->>U: 302 safe return with result query
sequenceDiagram
participant UI as My Integrations UI
participant A as List API
participant S as DataService
UI->>A: GET integration/webhook list
A->>A: requireAuth
alt authenticated
A->>S: fetch and validate items
S-->>A: items
A-->>UI: JSON list
else invalid session/upstream
A-->>UI: stable error
end
classDiagram
class MyIntegrations
class Webhooks
class IntegrationRoutes
class ApiRoutes
class NanoStores
class DataService
MyIntegrations --> NanoStores
Webhooks --> NanoStores
MyIntegrations --> ApiRoutes
Webhooks --> ApiRoutes
ApiRoutes --> DataService
IntegrationRoutes --> DataService
src/pages/integration/[integrationId]/connect.ts, src/pages/integration/auth.ts.src/pages/api/remove-authorization.ts, src/stores/authorizationsStore.ts.src/pages/api/webhooks.ts, src/components/Webhooks.tsx, src/stores/webhooksStore.ts.myIntegrationsStore, authorizationsStore, and webhooksStore keep separate list/loading/error and mutation-loading/error fields. OAuth completion communicates transient result through safe query parameters rather than browser token state.
src/lib/adapters/types.ts.stateDiagram-v2
[*] --> Loading
Loading --> Ready: list success
Loading --> Error: list failure
Ready --> Mutating: add/delete/disconnect
Mutating --> Ready: success + list update
Mutating --> Error: failure + list preserved
Error --> Loading: retry
| Condition | Signal | Recovery |
|---|---|---|
| Not authenticated | 401/login redirect path | login |
| Invalid ID/state/return | safe error redirect or 400/403 | restart valid flow |
| Invalid webhook input | 400/413 JSON error | correct form |
| Upstream auth/failure | mapped route error | refresh/login/retry |
| Delete succeeds | 204 | remove list item |
GET connect endpoint is guarded as navigation; converting it to fetch semantics changes CSRF posture.requireAuth(), shared adapters, body-size checks, and client API helpers.Same-origin management APIs and server sessions add an application hop, but keep credentials out of the browser and centralize validation/observability.
Cover OAuth success/denial/bad state/navigation/return paths; list auth/schema failures; webhook body/type/name/status paths; store success/error/reset; and representative authenticated E2E when environment credentials exist.
| Behavior | Evidence | Gap |
|---|---|---|
| integration routes | integration-routes.test.ts | live provider integration |
| webhook APIs | api-webhooks.test.ts | live Webex integration |
| stores/components | store/component suites | environment-gated full E2E |
SECURITY.mdCONTRACTS.md.sdd/manifest.json