Account integrations
Per-org credential links the admin operator wires through the
alphaswarm_admin Next.js surface. Six integration kinds ship today:
| Kind | Persisted under | Wizard | Backend |
|---|---|---|---|
huggingface | CredentialKey("huggingface", "org:<org_id>") | frontend/components/accounts/HuggingFaceWizard.tsx | src/alphaswarm_admin/providers/huggingface.py |
docker_hub | CredentialKey("docker_hub", "org:<org_id>") | frontend/components/accounts/DockerHubWizard.tsx | src/alphaswarm_admin/providers/dockerhub.py |
cloud_aws | CredentialKey("cloud_aws", "org:<org_id>") | frontend/components/cloud/CloudOnboardingWizard.tsx | src/alphaswarm_admin/providers/cloud_aws.py |
cloud_azure | CredentialKey("cloud_azure", "org:<org_id>") | frontend/components/cloud/CloudOnboardingWizard.tsx | src/alphaswarm_admin/providers/cloud_azure.py |
cloud_gcp | CredentialKey("cloud_gcp", "org:<org_id>") | frontend/components/cloud/CloudOnboardingWizard.tsx | src/alphaswarm_admin/providers/cloud_gcp.py |
cloud_cloudflare | CredentialKey("cloud_cloudflare", "org:<org_id>") | frontend/components/cloud/CloudOnboardingWizard.tsx | src/alphaswarm_admin/providers/cloud_cloudflare.py |
The four cloud_* kinds use the same AccountIntegrationProvider
ABC but extend it with a 5-step wizard contract
(bootstrap_artifacts → validate_identity →
validate_permissions → enumerate_resources → connect) and
are exclusively federated-first — no long-lived secrets are
stored. See
Connect a company cloud account
for the full runbook.
Both share the same AccountIntegrationProvider ABC defined in
alphaswarm_admin/src/alphaswarm_admin/providers/base.py and the same encrypted
file-backed store at
alphaswarm_admin/src/alphaswarm_admin/services/integration_store.py.
Lifecycle
The flow is audit-first (see alphaswarm_admin/src/alphaswarm_admin/api/routers/integrations.py)
and step-up MFA gated (require_admin_step_up("admin:cluster")). The
PAT itself never crosses the BFF response boundary after the
initial connect call — the wizard renders the masked metadata
(namespace, status, connected_at) only.
HuggingFace Hub
What you need
- A fine-grained PAT with read access on the org's models / datasets. Generate at https://huggingface.co/settings/tokens.
- The org's HuggingFace namespace (e.g.
acme-quant). Optional — the BFF derives it fromHfApi().whoami()when omitted.
Wire-format
POST /admin/accounts/{org_id}/integrations/huggingface
Authorization: Bearer <admin JWT, MFA-fresh>
Content-Type: application/json
{
"token": "hf_*****",
"namespace": "acme-quant"
}
{
"integration": {
"org_id": "org-acme",
"kind": "huggingface",
"namespace": "acme-quant",
"credential_key": "huggingface:org:org-acme",
"status": "healthy",
"connected_at": "2026-05-27T20:00:00Z",
"last_health_at": null,
"error": null,
"metadata": { "type": "org", "auth_email": "ops@example.com", "orgs": ["acme-quant"] }
},
"audit_run_id": "..."
}
Revocation
DELETE /admin/accounts/{org_id}/integrations/huggingface drops the
local record. Always revoke the PAT on the HuggingFace side
too — settings → Personal access tokens → Revoke. Without that step
the PAT remains usable from any source that holds the bytes.
Docker Hub
What you need
- A Docker Hub PAT (Account → Personal access tokens) with the intended scope. Username + PAT together are required (Docker Hub v2 login does not accept PAT-only).
- The Docker Hub namespace (defaults to the username on connect).
Wire-format
POST /admin/accounts/{org_id}/integrations/dockerhub
{
"username": "acmeops",
"pat": "dckr_pat_*****",
"namespace": "acmeops"
}
The BFF posts to https://hub.docker.com/v2/users/login to mint a
JWT (proving the credential is valid), then /v2/users/{namespace}/
to confirm namespace scope. Both calls happen server-side; only
metadata returns to the wizard.
Revocation
DELETE /admin/accounts/{org_id}/integrations/docker_hub drops the
local record only. Docker Hub does NOT expose a PAT-revocation API,
so you must delete the PAT manually in
Account → Security → Personal access tokens to fully terminate
access.
Health checks
The wizard's "Re-check" action calls
POST /admin/accounts/{org_id}/integrations/{kind}/health which
re-runs the whoami (HuggingFace) or login + namespace probe
(Docker Hub). The result lands on the row's last_health_at /
last_health_status fields and is rendered as a badge.
Operator runbook
| Scenario | Action |
|---|---|
| PAT expired upstream | Re-run the wizard; the new PAT replaces the encrypted blob in-place. |
| PAT compromised | Revoke upstream first, then disconnect locally. |
| Switching org owners | Disconnect, delete the PAT upstream, have the new owner connect with their own PAT. |
Lost encryption key (ALPHASWARM_ADMIN_INTEGRATIONS_KEY) | Drop the local store JSON, rotate the encryption key, re-run all connect wizards. The upstream PATs are unaffected. |
Configuration
| Env var | Purpose | Default |
|---|---|---|
ALPHASWARM_ADMIN_INTEGRATIONS_PATH | JSON file the encrypted store writes to. | ~/.alphaswarm/integrations.json |
ALPHASWARM_ADMIN_INTEGRATIONS_KEY | Fernet key used to encrypt PATs. Required in production. | (ephemeral key minted per process — refused in production by IntegrationCredentialStore.assert_production_ready) |
Generate a Fernet key with:
from cryptography.fernet import Fernet
print(Fernet.generate_key().decode())
Persist the key in your platform secret manager and inject it as an env var; the store reads it once at boot.