Notify Security Notes
Holds NR2, NR6, and NR7 artefacts: tenant/RBAC approval matrix, webhook/ack hardening policy (HMAC/mTLS/DPoP + signed acks), and redaction/PII catalog with sanitized fixture samples.
Authority OAuth wiring (Sprint 20260513_015)
Notify.WebService validates Authority-issued OAuth tokens via the shared AddStellaOpsResourceServerAuthentication pipeline (see src/Notify/StellaOps.Notify.WebService/Program.cs:412-457).
notify:authority:allowAnonymousFallbackis deprecated for non-local hosts. The runtime guard inValidateNotifyRuntimeConfiguration(Program.cs:389-410) refuses to start non-Development/Testinghosts if the flag is stilltrue. The dev-time anonymous fallback path (AllowAllAuthenticationHandler) remains in source only for local unit tests and is gated behind that environment check.- Notify validates four scopes —
notify.viewer,notify.operator,notify.admin,notify.escalate— declared insrc/Authority/StellaOps.Authority/StellaOps.Auth.Abstractions/StellaOpsScopes.csand asserted byNotifyPolicies.*+NotifierPolicies.NotifyEscalate. - The first-party
stellaops-notifyAuthority client is provisioned by the collapsed seed baselinesrc/Authority/__Libraries/StellaOps.Authority.Persistence/Migrations/S001_v1_authority_operational_baseline.sql(client insert at line 656; folded in from the pre-1.0S004_notify_authority_client.sql, which is archived underMigrations/_archived/pre_1.0/mig061/and is no longer embedded). It is aclient_credentialsclient bound to tenantdefaultwithaudiences=notify. The client secret cleartext lives indevops/compose/.env(NOTIFY__AUTHORITY__CLIENT_SECRET); the base64(SHA-256) hash lives inline in the migration body. Rotate both together. - The first-party
stella-ops-uibrowser client must also mint access tokens with thenotifyaudience when calling the direct Notify inbox route. Fresh plugin bootstrap declares this indevops/etc/authority/plugins/standard.yaml; the audience backfill for existing dev volumes is folded into the same collapsed seed baselineS001_v1_authority_operational_baseline.sql(the pre-1.0S006_ui_notify_audience.sqlis archived). New audience/scope top-ups must ship as fresh forwardS0xx_*.sqlfiles after that baseline — never by editing it.
Smoke recipe
TOKEN=$(curl -sk -X POST http://authority.stella-ops.local/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=stellaops-notify\
&client_secret=<from .env>&scope=notify.viewer" \
| jq -r .access_token)
# 200 -- token validated, scope ok
curl -sk -H "Authorization: Bearer $TOKEN" -H "X-StellaOps-TenantId: default" \
http://notify.stella-ops.local/api/v1/notify/channels
# 401 -- no anonymous fallback
curl -sk -H "X-StellaOps-TenantId: default" \
http://notify.stella-ops.local/api/v1/notify/channels
