Raxx · internal docs

internal · gated ↑ index

ADR-0046 — Support Portal: FreeScout API Token in Infisical (not SSM)

(Renumbered from 0044 → 0046 to avoid collision with PR #996's ADR-0044 which claimed the slot first.)

Status: Accepted Date: 2026-05-03 UTC Deciders: software-architect Scope: Secret store selection for the FreeScout API token used by Raptor's support portal endpoints Design doc: docs/architecture/support-raxx-app.md Refs: Epic #651 · ADR-0002 (no stored credentials)


Context

Raptor's /api/v1/support/* endpoints proxy FreeScout using a FreeScout API token. This token is a server-side secret: it must never touch the browser bundle, CF Pages env vars accessible to client code, or any observable response. It must be rotatable without a code redeploy.

The constraint document asks us to choose between AWS SSM Parameter Store and Infisical and justify the decision. The project memory file feedback_aws_workloads_use_ssm_not_vault.md indicates SSM is preferred for AWS-hosted workloads. Raptor runs on Heroku, not AWS.


Decision

Use Infisical for the FreeScout API token and webhook secret.

The two secrets are: - /raxx/prod/freescout-api-token → Heroku config var FREESCOUT_API_TOKEN - /raxx/prod/freescout-support-webhook-secret → Heroku config var FREESCOUT_SUPPORT_WEBHOOK_SECRET

Both are surfaced to Raptor as Heroku config vars at dyno boot. Infisical's Heroku integration (or CI-driven Heroku config:set) syncs them. Rotation: update the value in Infisical, re-sync to Heroku config, Heroku restarts the dyno. No code redeploy required.


Consequences

Positive

Negative / Risks

Neutral


Alternatives Considered

Alternative A: AWS SSM Parameter Store

Rejected for Heroku-hosted Raptor. SSM requires either (a) AWS SDK in Raptor with an IAM user and access keys — adding two new secrets to manage a secret, or (b) a Lambda/ECS sidecar to sync SSM → Heroku env vars. Either path adds more complexity than Infisical's existing Heroku integration provides. The feedback_aws_workloads_use_ssm_not_vault.md preference applies to AWS-native workloads; Raptor is not one.

Alternative B: Heroku config var only (no external vault)

Rejected. A secret set only in Heroku config has no audit trail, no rotation automation, and no DPA-ready access log. Per platform invariant, secrets must be in a managed secret store with rotation and audit capability.

Alternative C: CF Pages environment variables (client-accessible)

Rejected outright. The FreeScout API token in CF Pages env vars could be read by any CF Pages build step or — worse — accidentally bundled into the static output. The architecture invariant is absolute: the FreeScout API token is a server-side secret only. It lives in Raptor (Heroku), never in CF Pages.