Repository navigation
Commit f4daf59
authored
fix(billing): stop account deletion from resetting the free allowance (#9141)
* fix(billing): stop account deletion from resetting the free allowance
Self-service deletion cascades the usage ledger with the user row, and signup
grants every new user row the free allowance, so deleting an account and
signing up again on the same email, Google, GitHub, or Microsoft identity
reset the one-time free credit.
Deletion at the holder's request now keeps keyed digests (HMAC-SHA256 under a
purpose-bound key derived from BETTER_AUTH_SECRET) of the account's canonical
email and social sign-in subjects for 365 days, and a new account on a matching
identity is created without the free allowance. The SCIM provisioning rollback
records nothing, and nothing is kept where billing is disabled.
- The allowance is a per-user `user_stats.free_tier_eligible` fact, so plan
re-syncs, the null-limit heal, usage reads, and admin grants keep it
withheld while prepaid credit and paid plans are unaffected.
- Signup checks the email and any sign-in already linked; a social sign-in
committed after the user hook is checked only when it was created in the
same auth request as its user, so linking a sign-in to an existing or
provisioned user later never withholds anything.
- A stats row created by the fallback (signup failed to create it) gets the
same check, failing open without failing the caller.
- Forfeiting sets the flag and re-derives the limit in one transaction.
- The deletion dialog says free credits are granted once per person.
Migration 0433 adds the `deleted_account_identity` table and the
`free_tier_eligible` column (constant default, metadata-only).
* fix(billing): never let the identity record block an erasure, and keep later links unchecked
- Recording a deleted account's identity digests now runs in a savepoint and
only logs on failure, so an anti-abuse write can never abort the holder's
deletion; before this change nothing of the kind could block it.
- A stats row the fallback creates gets only the check signup would have made:
the email always, and the linked sign-ins only for a user created in the
same auth request. A legacy user without a stats row who links a sign-in
later is no longer withheld through the fallback.
- Docs say exactly who is checked: every user Better Auth creates, SCIM- and
SSO-provisioned ones included, is checked by email at creation; only a
sign-in linked in a later request never withholds anything.
* fix(billing): keep deleted identities 30 days, drop Google subjects, leave the dialog unchanged
- Identity digests now expire 30 days after the deletion, inside the privacy
policy's 30-day Account Data window.
- Google subject ids are no longer recorded or matched (the policy keeps
Google API data only 7 days after deletion); a Google re-signup is still
caught by its email digest. GitHub and Microsoft subjects are kept.
- The deletion dialog is unchanged from staging.
- Callers added on staging pass the deletion option.
* improvement(billing): skip locked rows in the identity purge, share the auth-request lookup
Concurrent account deletions no longer wait on each other's purge batch.
syncUsageLimitsFromSubscription reads in parallel again, and email
canonicalization reuses normalizeEmail.
* fix(billing): drain expired identity digests hourly, record only verified emails
- Expired deleted-account digests were removed only while recording a later
deletion, so with no later deletions they outlived the 30-day window. The
hourly OAuth-token cleanup cron now drains them first in bounded batches
(indexed expires_at order, SKIP LOCKED, batch and time caps); a failed purge
is logged and never holds up the token sweep.
- A deleted account's email is recorded only when it was verified, so an
unverified signup can never cost the address's real owner the allowance.
GitHub and Microsoft subjects are still recorded; matching is unchanged.
- The admin credit grant creates a missing stats row with the same email
check as every other row creation instead of assuming eligibility, looked
up before its transaction.1 parent d44cee4 commit f4daf59
38 files changed
Lines changed: 32687 additions & 110 deletions
File tree
- apps/sim
- app/api/cron/cleanup-oauth-tokens
- ee/scim/lib/application/users
- lib
- admin
- auth
- billing
- core
- subscriptions
- execution
- mothership
- memories
- request/application
- projects/files/__integration__
- uploads/contexts/workspace/__integration__
- users
- application
- workspace-files/search
- workspaces/access
- packages
- db
- migrations
- meta
- testing/src/mocks
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
14 | 15 | | |
15 | 16 | | |
16 | 17 | | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
17 | 22 | | |
18 | 23 | | |
19 | 24 | | |
20 | 25 | | |
21 | 26 | | |
22 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
23 | 32 | | |
24 | | - | |
| 33 | + | |
25 | 34 | | |
26 | 35 | | |
27 | 36 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
211 | 211 | | |
212 | 212 | | |
213 | 213 | | |
214 | | - | |
| 214 | + | |
215 | 215 | | |
216 | 216 | | |
217 | 217 | | |
| |||
221 | 221 | | |
222 | 222 | | |
223 | 223 | | |
224 | | - | |
| 224 | + | |
225 | 225 | | |
226 | 226 | | |
227 | 227 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
242 | 242 | | |
243 | 243 | | |
244 | 244 | | |
245 | | - | |
| 245 | + | |
246 | 246 | | |
247 | 247 | | |
248 | 248 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| 24 | + | |
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
| |||
53 | 54 | | |
54 | 55 | | |
55 | 56 | | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
56 | 60 | | |
57 | 61 | | |
58 | 62 | | |
| |||
150 | 154 | | |
151 | 155 | | |
152 | 156 | | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
153 | 181 | | |
154 | 182 | | |
155 | 183 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| 81 | + | |
81 | 82 | | |
82 | 83 | | |
83 | 84 | | |
| |||
1497 | 1498 | | |
1498 | 1499 | | |
1499 | 1500 | | |
| 1501 | + | |
| 1502 | + | |
| 1503 | + | |
| 1504 | + | |
| 1505 | + | |
| 1506 | + | |
| 1507 | + | |
| 1508 | + | |
1500 | 1509 | | |
1501 | 1510 | | |
1502 | 1511 | | |
| |||
1518 | 1527 | | |
1519 | 1528 | | |
1520 | 1529 | | |
1521 | | - | |
| 1530 | + | |
1522 | 1531 | | |
1523 | 1532 | | |
1524 | 1533 | | |
1525 | 1534 | | |
1526 | 1535 | | |
1527 | 1536 | | |
| 1537 | + | |
1528 | 1538 | | |
1529 | 1539 | | |
1530 | 1540 | | |
| |||
1533 | 1543 | | |
1534 | 1544 | | |
1535 | 1545 | | |
| 1546 | + | |
1536 | 1547 | | |
1537 | 1548 | | |
1538 | 1549 | | |
| |||
1566 | 1577 | | |
1567 | 1578 | | |
1568 | 1579 | | |
1569 | | - | |
| 1580 | + | |
| 1581 | + | |
| 1582 | + | |
1570 | 1583 | | |
1571 | 1584 | | |
1572 | 1585 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
96 | | - | |
| 96 | + | |
97 | 97 | | |
98 | 98 | | |
99 | 99 | | |
| |||
405 | 405 | | |
406 | 406 | | |
407 | 407 | | |
408 | | - | |
| 408 | + | |
409 | 409 | | |
410 | 410 | | |
411 | 411 | | |
| |||
651 | 651 | | |
652 | 652 | | |
653 | 653 | | |
654 | | - | |
| 654 | + | |
655 | 655 | | |
656 | 656 | | |
657 | 657 | | |
| |||
660 | 660 | | |
661 | 661 | | |
662 | 662 | | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
663 | 672 | | |
664 | 673 | | |
665 | 674 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
| 25 | + | |
25 | 26 | | |
26 | 27 | | |
27 | 28 | | |
| |||
276 | 277 | | |
277 | 278 | | |
278 | 279 | | |
| 280 | + | |
279 | 281 | | |
280 | 282 | | |
281 | 283 | | |
| |||
326 | 328 | | |
327 | 329 | | |
328 | 330 | | |
329 | | - | |
| 331 | + | |
330 | 332 | | |
331 | 333 | | |
332 | 334 | | |
| |||
0 commit comments