Docs
Open in panel → /app · general
Identity
PostMTA Hosted ships email/password by default and gates sensitive actions (send / suppress / reputation edits / credit grant) behind AAL2 in production.
AAL2 (TOTP / WebAuthn)
When REQUIRE_AAL2=1 (the production default), the API returns
401 MFA_REQUIRED on every /v1/panel/send / /v1/panel/* call where the
caller lacks AAL2. The unified check (apps/api/src/auth/requireAAL2.ts)
accepts any of:
user.app_metadata.aal === 'aal2'- JWT payload
aal === 'aal2' - JWT
amrcontainingmfa,otp,totp, orwebauthn
/v1/send (API key) is not affected — API keys are machine identities.
MOCK mode
MOCK_AAL2=1 forces the gate on but accepts any caller so the smoke suite
can prove the path end-to-end. The mock returns
{ ok: true, aal: 'aal1-mocked', mock: true }.
OIDC / SAML
supabase/config.toml documents provider blocks; operators wire the actual
IdP at runtime via GoTrue env vars.
Keycloak lab (local OIDC)
cd /home/dchat/mtaig
docker compose -f infra/keycloak/docker-compose.yml up -d
set -a; source supabase/.env.local; set +a
pnpm exec supabase stop --no-backup && pnpm exec supabase start
REQUIRE_IDP_LIVE=1 bash scripts/check-idp-live.sh
The local realm export uses the confidential postmta-hosted client and its
dev-only secret; supabase/.env.local passes it to GoTrue.
SAML: GOTRUE_SAML_ENABLED=true plus IdP metadata and an SP private
key for assertion signing. The panel UI is unchanged; SSO adds a sign-in
button only.
TOTP enrollment
apps/web/src/components/react/MfaEnroll.tsx is the operator-visible wizard.
MOCK (PUBLIC_MOCK_MFA=1 or MOCK_MFA=1): in-memory verifier; smoke
path uses code 000000.
Production / lab Supabase:
supabase.auth.mfa.enroll({ factorType: 'totp' })— show QR + secretsupabase.auth.mfa.challenge({ factorId })supabase.auth.mfa.verify({ factorId, challengeId, code })
After verify, the refreshed session carries aal2 and panel send paths pass
the API gate.
MOCK fixtures
MOCK_AAL2=1— gate on, accept any caller.MOCK_MFA=1/PUBLIC_MOCK_MFA=1— TOTP wizard mock; code000000.MOCK_OIDC=1— pretend OIDC login; panel skips Supabase.SKIP_IDP_LIVE=1— skip Keycloak live gate incheck-idp-live.sh.
Related
- docs/security-architecture.md — AAL2 layer.
- trust/security — PMH-SEC table.
infra/keycloak/README.md— Keycloak + GoTrue env reference.supabase/config.toml— provider toggles.
Last verified: Sun Jul 12 2026 17:00:00 GMT-0700 (Pacific Daylight Time). Cross-link maintained byscripts/check-docs-drift.sh (M54).