Background
PR #137 (#122 PR B1) reworked Subscription ↔ Authorization to N:1 with Authorization as the aggregate root:
Authorization @OneToMany(cascade=ALL, orphanRemoval=true) → Subscription
subscriptions.authorization_id is NOT NULL with DB-level ON DELETE CASCADE
That makes the mechanism correct: deleting an Authorization cascades to its Subscription(s); dropping the customer-PII child from the collection removes only the customerResourceURI subscription via orphanRemoval.
The gap
The policy / trigger is still missing. Two cases:
-
Token expiration / revocation → today this does not propagate to the Authorization aggregate. An expired or revoked access token leaves the Authorization row (and its Subscription children) sitting in the DB as stale state.
-
Customer withdraws consent (via the utility's customer portal) → today this does not automatically revoke the OAuth access token. The token remains valid until natural expiry, so the TP keeps pulling data the customer has withdrawn consent for.
These are the two halves of the same invariant: authorization lifecycle and token lifecycle must move together.
Proposed direction (for discussion, not this issue's scope)
- Token-revoked / token-expired → Authorization removal: hook the AS revocation endpoint and an expiry sweep to delete the corresponding
Authorization. With B1's cascade, the Subscription(s) go with it.
- Consent-withdrawn → token revocation: when the customer portal removes (or narrows) consent, call the AS revocation endpoint (RFC 7009) — or, for PII-narrowing, mutate the
Authorization.subscriptions list to drop the customerResourceURI child (relies on orphanRemoval from B1) and re-mint the token with the reduced scope (since opaque tokens encode scope at mint time).
Out of scope here
Acceptance criteria (when this issue is worked)
Related: #122, #137.
Background
PR #137 (#122 PR B1) reworked
Subscription ↔ Authorizationto N:1 with Authorization as the aggregate root:Authorization@OneToMany(cascade=ALL, orphanRemoval=true)→Subscriptionsubscriptions.authorization_idisNOT NULLwith DB-levelON DELETE CASCADEThat makes the mechanism correct: deleting an
Authorizationcascades to itsSubscription(s); dropping the customer-PII child from the collection removes only thecustomerResourceURIsubscription viaorphanRemoval.The gap
The policy / trigger is still missing. Two cases:
Token expiration / revocation → today this does not propagate to the
Authorizationaggregate. An expired or revoked access token leaves theAuthorizationrow (and itsSubscriptionchildren) sitting in the DB as stale state.Customer withdraws consent (via the utility's customer portal) → today this does not automatically revoke the OAuth access token. The token remains valid until natural expiry, so the TP keeps pulling data the customer has withdrawn consent for.
These are the two halves of the same invariant: authorization lifecycle and token lifecycle must move together.
Proposed direction (for discussion, not this issue's scope)
Authorization. With B1's cascade, theSubscription(s) go with it.Authorization.subscriptionslist to drop thecustomerResourceURIchild (relies onorphanRemovalfrom B1) and re-mint the token with the reduced scope (since opaque tokens encode scope at mint time).Out of scope here
Acceptance criteria (when this issue is worked)
Authorizationrow and cascades to itsSubscription(s).customerResourceURIsubscription from the aggregate and re-mints the token with the reduced scope.Related: #122, #137.