@boopkit/cap-users 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.teamInvitationsStore = exports.authorizationStore = void 0;
4
+ exports.rehashAuthorizationGrants = rehashAuthorizationGrants;
5
+ exports.rehashTeamInvitations = rehashTeamInvitations;
6
+ exports.migrateCredentialStore = migrateCredentialStore;
7
+ /**
8
+ * Credential-hashing migration (boop-j8xc epic).
9
+ *
10
+ * A handful of property payloads once stored a raw, redeemable bearer credential
11
+ * beside its correctly-hashed twin (see boop-owbv). The fixed services now store
12
+ * the hash and read tolerantly, but existing rows keep the raw value until they
13
+ * are rewritten. Because the raw value is still present, those rows can be
14
+ * REHASHED IN PLACE rather than invalidated — so a deployment migrates without
15
+ * logging every user out or voiding every pending invitation.
16
+ *
17
+ * This module is the reusable core of the migration. It is deliberately generic:
18
+ * each credential store (the `authorization` user-property here, the
19
+ * `team_invitations` account-property in boop-j8xc.3) is described by a
20
+ * {@link CredentialStore} and rehashed by the SAME runner — there is no second
21
+ * tool. A thin CLI (scaffold/src/scripts/migrate-credentials.ts) wires a project's
22
+ * Prisma client to this core.
23
+ *
24
+ * ONE-WAY, NO ROLLBACK. Hashing is irreversible; there is no way back to the raw
25
+ * values once they are overwritten. Take a database backup before running with
26
+ * `run: true`. Re-running is safe: idempotency is decided by value shape (a
27
+ * SHA-256 digest is left untouched, {@link isHashedToken}), so nothing is ever
28
+ * double-hashed.
29
+ *
30
+ * SCOPE BOUNDARY. Provider access/refresh tokens in the `authentication`
31
+ * property are replayed to Google/Microsoft and must NEVER be hashed. No store
32
+ * here touches them.
33
+ */
34
+ const auth_service_js_1 = require("./auth-service.js");
35
+ const info_schema_tags_js_1 = require("./info-schema-tags.js");
36
+ /**
37
+ * Rehash the identity keys of an `authorization` payload. Each grant's
38
+ * `identity_key` is a bearer token compared only for equality, so a raw value is
39
+ * replaced with `hashToken(value)`; an already-hashed value is left untouched
40
+ * (idempotent). A non-array payload is returned unchanged.
41
+ */
42
+ function rehashAuthorizationGrants(info) {
43
+ if (!Array.isArray(info))
44
+ return { info, changed: false };
45
+ let changed = false;
46
+ const grants = info.map((grant) => {
47
+ if (grant && typeof grant === 'object' && typeof grant.identity_key === 'string') {
48
+ if (!(0, auth_service_js_1.isHashedToken)(grant.identity_key)) {
49
+ changed = true;
50
+ return { ...grant, identity_key: (0, auth_service_js_1.hashToken)(grant.identity_key) };
51
+ }
52
+ }
53
+ return grant;
54
+ });
55
+ return { info: grants, changed };
56
+ }
57
+ /** The `authorization` user-property store (boop-j8xc.2). */
58
+ exports.authorizationStore = {
59
+ label: 'authorization grants',
60
+ property: 'authorization',
61
+ infoSchema: info_schema_tags_js_1.AUTHORIZATION_HASHED_INFO_SCHEMA,
62
+ rehash: rehashAuthorizationGrants,
63
+ };
64
+ /**
65
+ * Rehash the tokens of a `team_invitations` payload. Each invitation's `token`
66
+ * is a bearer credential compared only for equality, so a raw value is replaced
67
+ * with `hashToken(value)`; an already-hashed value is left untouched
68
+ * (idempotent). A payload without an `invitations` array is returned unchanged.
69
+ */
70
+ function rehashTeamInvitations(info) {
71
+ const invitations = info?.invitations;
72
+ if (!Array.isArray(invitations))
73
+ return { info, changed: false };
74
+ let changed = false;
75
+ const rehashed = invitations.map((inv) => {
76
+ if (inv && typeof inv === 'object' && typeof inv.token === 'string' && !(0, auth_service_js_1.isHashedToken)(inv.token)) {
77
+ changed = true;
78
+ return { ...inv, token: (0, auth_service_js_1.hashToken)(inv.token) };
79
+ }
80
+ return inv;
81
+ });
82
+ return { info: { ...info, invitations: rehashed }, changed };
83
+ }
84
+ /** The `team_invitations` account-property store (boop-j8xc.3). */
85
+ exports.teamInvitationsStore = {
86
+ label: 'team invitations',
87
+ property: 'team_invitations',
88
+ infoSchema: info_schema_tags_js_1.TEAM_INVITATIONS_HASHED_INFO_SCHEMA,
89
+ rehash: rehashTeamInvitations,
90
+ };
91
+ /**
92
+ * Migrate one credential store. Reports by default; writes only when
93
+ * `opts.run` is true — mirroring `boop loop` and `tools/publish-caps.sh`.
94
+ *
95
+ * A row needs migration when its payload still holds a raw value OR its
96
+ * info_schema lacks the migrated tag (so a payload that is already hashed but
97
+ * untagged is still stamped, keeping the `boop status` probe truthful). The
98
+ * write stamps the tag and bumps the revision.
99
+ */
100
+ async function migrateCredentialStore(model, store, opts = {}) {
101
+ const run = opts.run ?? false;
102
+ const rows = await model.findMany({ where: { property: store.property } });
103
+ let needsMigration = 0;
104
+ let migrated = 0;
105
+ for (const row of rows) {
106
+ const { info, changed } = store.rehash(row.info);
107
+ const currentTag = row.infoSchema ?? '';
108
+ const needsWrite = changed || currentTag !== store.infoSchema;
109
+ if (!needsWrite)
110
+ continue;
111
+ needsMigration += 1;
112
+ if (run) {
113
+ await model.update({
114
+ where: { id: row.id },
115
+ data: {
116
+ info: info,
117
+ infoSchema: store.infoSchema,
118
+ revision: (row.revision ?? 1) + 1,
119
+ },
120
+ });
121
+ migrated += 1;
122
+ }
123
+ }
124
+ return { property: store.property, label: store.label, scanned: rows.length, needsMigration, migrated, run };
125
+ }
126
+ //# sourceMappingURL=credential-migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-migration.js","sourceRoot":"","sources":["../src/credential-migration.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@ export { createIdentityService } from './identity-service.js';
12
12
  export type { IdentityService, IdentityServiceOptions, IdentityQueryOptions } from './identity-service.js';
13
13
  export { createUserPropertyService } from './user-property-service.js';
14
14
  export type { UserPropertyService, UserPropertyServiceOptions } from './user-property-service.js';
15
- export { createAuthService, AuthValidationError, AuthError, generateToken, hashToken } from './auth-service.js';
15
+ export { createAuthService, AuthValidationError, AuthError, generateToken, hashToken, isHashedToken } from './auth-service.js';
16
16
  export type { AuthService, AuthServiceDeps, AuthServiceOptions, AddAuthMethodOptions, SignupInput, SignupResult, LoginResult, VerifyEmailResult, } from './auth-service.js';
17
17
  export { createAuthMiddleware } from './auth-middleware.js';
18
18
  export type { AuthMiddleware, AuthMiddlewareDeps, AuthMiddlewareOptions, AuthLocals, } from './auth-middleware.js';
@@ -24,4 +24,7 @@ export { createAccountManagementService, AccountManagementError } from './accoun
24
24
  export type { AccountManagementService, AccountManagementServiceDeps, AccountManagementServiceOptions, ProvisionAccountInput, ProvisionAccountResult, TeamMember, } from './account-management-service.js';
25
25
  export { createTeamInvitationService, TeamInvitationError, DEFAULT_INVITATION_TTL_MS, MAX_PENDING_INVITATIONS, MAX_RESENDS, } from './team-invitation-service.js';
26
26
  export type { TeamInvitation, TeamInvitationsPropertyInfo, TeamInvitationService, TeamInvitationServiceDeps, TeamInvitationServiceOptions, AccountUserRole, } from './team-invitation-service.js';
27
+ export { AUTHORIZATION_HASHED_INFO_SCHEMA, TEAM_INVITATIONS_HASHED_INFO_SCHEMA, } from './info-schema-tags.js';
28
+ export { migrateCredentialStore, rehashAuthorizationGrants, authorizationStore, rehashTeamInvitations, teamInvitationsStore, } from './credential-migration.js';
29
+ export type { MigrationDelegate, CredentialStore, RehashResult, MigrationReport, } from './credential-migration.js';
27
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAC/E,YAAY,EACV,YAAY,EACZ,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,OAAO,EACP,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE3G,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAElG,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAChH,YAAY,EACV,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,UAAU,GACX,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElF,OAAO,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAC7E,YAAY,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAC;AAE3G,OAAO,EAAE,8BAA8B,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzG,YAAY,EACV,wBAAwB,EACxB,4BAA4B,EAC5B,+BAA+B,EAC/B,qBAAqB,EACrB,sBAAsB,EACtB,UAAU,GACX,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,WAAW,GACZ,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,cAAc,EACd,2BAA2B,EAC3B,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,eAAe,GAChB,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAC/E,YAAY,EACV,YAAY,EACZ,IAAI,EACJ,YAAY,EACZ,WAAW,EACX,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,SAAS,EACT,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,OAAO,EACP,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE3G,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,YAAY,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAElG,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC/H,YAAY,EACV,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,UAAU,GACX,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAElF,OAAO,EAAE,4BAA4B,EAAE,MAAM,+BAA+B,CAAC;AAC7E,YAAY,EAAE,sBAAsB,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAC;AAE3G,OAAO,EAAE,8BAA8B,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzG,YAAY,EACV,wBAAwB,EACxB,4BAA4B,EAC5B,+BAA+B,EAC/B,qBAAqB,EACrB,sBAAsB,EACtB,UAAU,GACX,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,WAAW,GACZ,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,cAAc,EACd,2BAA2B,EAC3B,qBAAqB,EACrB,yBAAyB,EACzB,4BAA4B,EAC5B,eAAe,GAChB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EACL,gCAAgC,EAChC,mCAAmC,GACpC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,eAAe,GAChB,MAAM,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * composing on top of @boopkit/cap-services primitives.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.MAX_RESENDS = exports.MAX_PENDING_INVITATIONS = exports.DEFAULT_INVITATION_TTL_MS = exports.TeamInvitationError = exports.createTeamInvitationService = exports.AccountManagementError = exports.createAccountManagementService = exports.createAccountPropertyService = exports.createAccountService = exports.createAuthMiddleware = exports.hashToken = exports.generateToken = exports.AuthError = exports.AuthValidationError = exports.createAuthService = exports.createUserPropertyService = exports.createIdentityService = exports.createUserService = exports.DuplicateAccountUserError = exports.DuplicateIdentityError = void 0;
9
+ exports.teamInvitationsStore = exports.rehashTeamInvitations = exports.authorizationStore = exports.rehashAuthorizationGrants = exports.migrateCredentialStore = exports.TEAM_INVITATIONS_HASHED_INFO_SCHEMA = exports.AUTHORIZATION_HASHED_INFO_SCHEMA = exports.MAX_RESENDS = exports.MAX_PENDING_INVITATIONS = exports.DEFAULT_INVITATION_TTL_MS = exports.TeamInvitationError = exports.createTeamInvitationService = exports.AccountManagementError = exports.createAccountManagementService = exports.createAccountPropertyService = exports.createAccountService = exports.createAuthMiddleware = exports.isHashedToken = exports.hashToken = exports.generateToken = exports.AuthError = exports.AuthValidationError = exports.createAuthService = exports.createUserPropertyService = exports.createIdentityService = exports.createUserService = exports.DuplicateAccountUserError = exports.DuplicateIdentityError = void 0;
10
10
  var types_js_1 = require("./types.js");
11
11
  Object.defineProperty(exports, "DuplicateIdentityError", { enumerable: true, get: function () { return types_js_1.DuplicateIdentityError; } });
12
12
  Object.defineProperty(exports, "DuplicateAccountUserError", { enumerable: true, get: function () { return types_js_1.DuplicateAccountUserError; } });
@@ -22,6 +22,7 @@ Object.defineProperty(exports, "AuthValidationError", { enumerable: true, get: f
22
22
  Object.defineProperty(exports, "AuthError", { enumerable: true, get: function () { return auth_service_js_1.AuthError; } });
23
23
  Object.defineProperty(exports, "generateToken", { enumerable: true, get: function () { return auth_service_js_1.generateToken; } });
24
24
  Object.defineProperty(exports, "hashToken", { enumerable: true, get: function () { return auth_service_js_1.hashToken; } });
25
+ Object.defineProperty(exports, "isHashedToken", { enumerable: true, get: function () { return auth_service_js_1.isHashedToken; } });
25
26
  var auth_middleware_js_1 = require("./auth-middleware.js");
26
27
  Object.defineProperty(exports, "createAuthMiddleware", { enumerable: true, get: function () { return auth_middleware_js_1.createAuthMiddleware; } });
27
28
  var account_service_js_1 = require("./account-service.js");
@@ -37,4 +38,13 @@ Object.defineProperty(exports, "TeamInvitationError", { enumerable: true, get: f
37
38
  Object.defineProperty(exports, "DEFAULT_INVITATION_TTL_MS", { enumerable: true, get: function () { return team_invitation_service_js_1.DEFAULT_INVITATION_TTL_MS; } });
38
39
  Object.defineProperty(exports, "MAX_PENDING_INVITATIONS", { enumerable: true, get: function () { return team_invitation_service_js_1.MAX_PENDING_INVITATIONS; } });
39
40
  Object.defineProperty(exports, "MAX_RESENDS", { enumerable: true, get: function () { return team_invitation_service_js_1.MAX_RESENDS; } });
41
+ var info_schema_tags_js_1 = require("./info-schema-tags.js");
42
+ Object.defineProperty(exports, "AUTHORIZATION_HASHED_INFO_SCHEMA", { enumerable: true, get: function () { return info_schema_tags_js_1.AUTHORIZATION_HASHED_INFO_SCHEMA; } });
43
+ Object.defineProperty(exports, "TEAM_INVITATIONS_HASHED_INFO_SCHEMA", { enumerable: true, get: function () { return info_schema_tags_js_1.TEAM_INVITATIONS_HASHED_INFO_SCHEMA; } });
44
+ var credential_migration_js_1 = require("./credential-migration.js");
45
+ Object.defineProperty(exports, "migrateCredentialStore", { enumerable: true, get: function () { return credential_migration_js_1.migrateCredentialStore; } });
46
+ Object.defineProperty(exports, "rehashAuthorizationGrants", { enumerable: true, get: function () { return credential_migration_js_1.rehashAuthorizationGrants; } });
47
+ Object.defineProperty(exports, "authorizationStore", { enumerable: true, get: function () { return credential_migration_js_1.authorizationStore; } });
48
+ Object.defineProperty(exports, "rehashTeamInvitations", { enumerable: true, get: function () { return credential_migration_js_1.rehashTeamInvitations; } });
49
+ Object.defineProperty(exports, "teamInvitationsStore", { enumerable: true, get: function () { return credential_migration_js_1.teamInvitationsStore; } });
40
50
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,uCAA+E;AAAtE,kHAAA,sBAAsB,OAAA;AAAE,qHAAA,yBAAyB,OAAA;AAmB1D,qDAAsD;AAA7C,oHAAA,iBAAiB,OAAA;AAG1B,6DAA8D;AAArD,4HAAA,qBAAqB,OAAA;AAG9B,uEAAuE;AAA9D,qIAAA,yBAAyB,OAAA;AAGlC,qDAAgH;AAAvG,oHAAA,iBAAiB,OAAA;AAAE,sHAAA,mBAAmB,OAAA;AAAE,4GAAA,SAAS,OAAA;AAAE,gHAAA,aAAa,OAAA;AAAE,4GAAA,SAAS,OAAA;AAYpF,2DAA4D;AAAnD,0HAAA,oBAAoB,OAAA;AAQ7B,2DAA4D;AAAnD,0HAAA,oBAAoB,OAAA;AAG7B,6EAA6E;AAApE,2IAAA,4BAA4B,OAAA;AAGrC,iFAAyG;AAAhG,+IAAA,8BAA8B,OAAA;AAAE,uIAAA,sBAAsB,OAAA;AAU/D,2EAMsC;AALpC,yIAAA,2BAA2B,OAAA;AAC3B,iIAAA,mBAAmB,OAAA;AACnB,uIAAA,yBAAyB,OAAA;AACzB,qIAAA,uBAAuB,OAAA;AACvB,yHAAA,WAAW,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,uCAA+E;AAAtE,kHAAA,sBAAsB,OAAA;AAAE,qHAAA,yBAAyB,OAAA;AAmB1D,qDAAsD;AAA7C,oHAAA,iBAAiB,OAAA;AAG1B,6DAA8D;AAArD,4HAAA,qBAAqB,OAAA;AAG9B,uEAAuE;AAA9D,qIAAA,yBAAyB,OAAA;AAGlC,qDAA+H;AAAtH,oHAAA,iBAAiB,OAAA;AAAE,sHAAA,mBAAmB,OAAA;AAAE,4GAAA,SAAS,OAAA;AAAE,gHAAA,aAAa,OAAA;AAAE,4GAAA,SAAS,OAAA;AAAE,gHAAA,aAAa,OAAA;AAYnG,2DAA4D;AAAnD,0HAAA,oBAAoB,OAAA;AAQ7B,2DAA4D;AAAnD,0HAAA,oBAAoB,OAAA;AAG7B,6EAA6E;AAApE,2IAAA,4BAA4B,OAAA;AAGrC,iFAAyG;AAAhG,+IAAA,8BAA8B,OAAA;AAAE,uIAAA,sBAAsB,OAAA;AAU/D,2EAMsC;AALpC,yIAAA,2BAA2B,OAAA;AAC3B,iIAAA,mBAAmB,OAAA;AACnB,uIAAA,yBAAyB,OAAA;AACzB,qIAAA,uBAAuB,OAAA;AACvB,yHAAA,WAAW,OAAA;AAWb,6DAG+B;AAF7B,uIAAA,gCAAgC,OAAA;AAChC,0IAAA,mCAAmC,OAAA;AAGrC,qEAMmC;AALjC,iIAAA,sBAAsB,OAAA;AACtB,oIAAA,yBAAyB,OAAA;AACzB,6HAAA,kBAAkB,OAAA;AAClB,gIAAA,qBAAqB,OAAA;AACrB,+HAAA,oBAAoB,OAAA"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * info_schema tags that mark a property payload as written by the
3
+ * credential-hashing library (boop-j8xc epic).
4
+ *
5
+ * Both property tables carry an `info_schema` column that versions the payload
6
+ * shape. For most properties it stays `''`. The two properties that once stored
7
+ * a raw, redeemable credential get a distinct tag the moment their values are
8
+ * hashed — stamped by the fixed library on every new write and by the migration
9
+ * tool on every row it rewrites (boop-j8xc.2 and boop-j8xc.3).
10
+ *
11
+ * The `boop status` data probe uses these tags as a fast, exact migration
12
+ * signal: a row missing the tag predates the fix and may hold a cleartext
13
+ * credential, so the probe needs no JSON parsing — one column comparison with
14
+ * an early exit. Keep each literal in sync with the matching probe query in
15
+ * `capability.json`.
16
+ */
17
+ /** Stamped on the `authorization` user-property once its grants store hashed identity keys. */
18
+ export declare const AUTHORIZATION_HASHED_INFO_SCHEMA = "authorization-hashed-01";
19
+ /** Stamped on the `team_invitations` account-property once its tokens are stored hashed. */
20
+ export declare const TEAM_INVITATIONS_HASHED_INFO_SCHEMA = "team-invitations-hashed-01";
21
+ //# sourceMappingURL=info-schema-tags.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info-schema-tags.d.ts","sourceRoot":"","sources":["../src/info-schema-tags.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,+FAA+F;AAC/F,eAAO,MAAM,gCAAgC,4BAA4B,CAAC;AAE1E,4FAA4F;AAC5F,eAAO,MAAM,mCAAmC,+BAA+B,CAAC"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /**
3
+ * info_schema tags that mark a property payload as written by the
4
+ * credential-hashing library (boop-j8xc epic).
5
+ *
6
+ * Both property tables carry an `info_schema` column that versions the payload
7
+ * shape. For most properties it stays `''`. The two properties that once stored
8
+ * a raw, redeemable credential get a distinct tag the moment their values are
9
+ * hashed — stamped by the fixed library on every new write and by the migration
10
+ * tool on every row it rewrites (boop-j8xc.2 and boop-j8xc.3).
11
+ *
12
+ * The `boop status` data probe uses these tags as a fast, exact migration
13
+ * signal: a row missing the tag predates the fix and may hold a cleartext
14
+ * credential, so the probe needs no JSON parsing — one column comparison with
15
+ * an early exit. Keep each literal in sync with the matching probe query in
16
+ * `capability.json`.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.TEAM_INVITATIONS_HASHED_INFO_SCHEMA = exports.AUTHORIZATION_HASHED_INFO_SCHEMA = void 0;
20
+ /** Stamped on the `authorization` user-property once its grants store hashed identity keys. */
21
+ exports.AUTHORIZATION_HASHED_INFO_SCHEMA = 'authorization-hashed-01';
22
+ /** Stamped on the `team_invitations` account-property once its tokens are stored hashed. */
23
+ exports.TEAM_INVITATIONS_HASHED_INFO_SCHEMA = 'team-invitations-hashed-01';
24
+ //# sourceMappingURL=info-schema-tags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info-schema-tags.js","sourceRoot":"","sources":["../src/info-schema-tags.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAEH,+FAA+F;AAClF,QAAA,gCAAgC,GAAG,yBAAyB,CAAC;AAE1E,4FAA4F;AAC/E,QAAA,mCAAmC,GAAG,4BAA4B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"team-invitation-service.d.ts","sourceRoot":"","sources":["../src/team-invitation-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"team-invitation-service.d.ts","sourceRoot":"","sources":["../src/team-invitation-service.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TeamInvitationError = exports.PRUNE_AGE_MS = exports.PRUNE_THRESHOLD = exports.MAX_RESENDS = exports.MAX_PENDING_INVITATIONS = exports.DEFAULT_INVITATION_TTL_MS = void 0;
4
4
  exports.createTeamInvitationService = createTeamInvitationService;
5
5
  const auth_service_js_1 = require("./auth-service.js");
6
+ const info_schema_tags_js_1 = require("./info-schema-tags.js");
6
7
  const cap_services_1 = require("@boopkit/cap-services");
8
+ const logger_1 = require("@boopkit/logger");
9
+ const logger = (0, logger_1.createLogger)('users', 'invitations');
7
10
  // ---------- Constants ----------
8
11
  exports.DEFAULT_INVITATION_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
9
12
  exports.MAX_PENDING_INVITATIONS = 20;
@@ -11,9 +14,35 @@ exports.MAX_RESENDS = 3;
11
14
  exports.PRUNE_THRESHOLD = 100;
12
15
  exports.PRUNE_AGE_MS = 90 * 24 * 60 * 60 * 1000; // 90 days
13
16
  const PROPERTY = 'team_invitations';
14
- const SCHEMA = 'team-invitations-01';
15
17
  const MAX_CONCURRENCY_RETRIES = 3;
16
18
  const TERMINAL_STATUSES = new Set(['accepted', 'cancelled', 'expired']);
19
+ // An invitation token is a bearer credential: presenting it joins the account at
20
+ // the role the invitation grants. The stored `token` is therefore hashed, exactly
21
+ // as session cookies and API keys are — the raw value is emailed to the invitee
22
+ // once and never persisted. The read path hashes the presented token before
23
+ // comparing. Rows written before this fix stored the RAW token, and boop cannot
24
+ // know whether a downstream has run the migration, so the read tolerates BOTH
25
+ // forms permanently. The raw branch logs once per process to nudge an operator
26
+ // toward the migration; it goes quiet on its own once the data is hashed.
27
+ let warnedRawInvitation = false;
28
+ /**
29
+ * Does a stored invitation `storedToken` correspond to the raw `rawToken` a
30
+ * caller presented? Matches the hashed form (new writes and migrated rows) and
31
+ * the raw form (pre-hash rows). The raw branch warns once per process. Mirrors
32
+ * `grantMatchesIdentityKey` in auth-service, for the same reason.
33
+ */
34
+ function invitationMatchesToken(storedToken, rawToken) {
35
+ if (storedToken === (0, auth_service_js_1.hashToken)(rawToken))
36
+ return true;
37
+ if (storedToken === rawToken && !(0, auth_service_js_1.isHashedToken)(storedToken)) {
38
+ if (!warnedRawInvitation) {
39
+ warnedRawInvitation = true;
40
+ logger.warn('invitation matched a raw (pre-hash) token; run the credential-hashing migration to rehash it');
41
+ }
42
+ return true;
43
+ }
44
+ return false;
45
+ }
17
46
  // ---------- Errors ----------
18
47
  class TeamInvitationError extends Error {
19
48
  constructor(message) {
@@ -57,7 +86,7 @@ function createTeamInvitationService(deps, options) {
57
86
  }
58
87
  async function saveInvitations(accountId, invitations, expectedRevision) {
59
88
  pruneTerminalInvitations(invitations);
60
- await accountPropertyService.put(accountId, PROPERTY, { invitations }, { infoSchema: SCHEMA, expectedRevision });
89
+ await accountPropertyService.put(accountId, PROPERTY, { invitations }, { infoSchema: info_schema_tags_js_1.TEAM_INVITATIONS_HASHED_INFO_SCHEMA, expectedRevision });
61
90
  }
62
91
  /**
63
92
  * Retry a read-modify-write operation on StaleEntityError (optimistic concurrency conflict).
@@ -129,9 +158,11 @@ function createTeamInvitationService(deps, options) {
129
158
  throw new TeamInvitationError(`Maximum of ${maxPending} pending invitations reached`);
130
159
  }
131
160
  const now = new Date();
161
+ // The raw token is emailed to the invitee; only its hash is persisted.
162
+ const rawToken = (0, auth_service_js_1.generateToken)();
132
163
  const invitation = {
133
164
  id: (0, auth_service_js_1.generateToken)(),
134
- token: (0, auth_service_js_1.generateToken)(),
165
+ token: (0, auth_service_js_1.hashToken)(rawToken),
135
166
  email: normalizedEmail,
136
167
  role,
137
168
  status: 'pending',
@@ -143,7 +174,8 @@ function createTeamInvitationService(deps, options) {
143
174
  };
144
175
  snapshot.invitations.push(invitation);
145
176
  await saveInvitations(accountId, snapshot.invitations, snapshot.revision);
146
- return invitation;
177
+ // Hand the caller the RAW token to email; the stored record keeps only the hash.
178
+ return { ...invitation, token: rawToken };
147
179
  });
148
180
  }
149
181
  async function cancelInvitation(accountId, invitationId) {
@@ -171,11 +203,13 @@ function createTeamInvitationService(deps, options) {
171
203
  if (inv.resendCount >= maxResends) {
172
204
  throw new TeamInvitationError(`Maximum of ${maxResends} resends reached for this invitation`);
173
205
  }
174
- inv.token = (0, auth_service_js_1.generateToken)();
206
+ // Mint a fresh raw token, persist only its hash, and email the raw value.
207
+ const rawToken = (0, auth_service_js_1.generateToken)();
208
+ inv.token = (0, auth_service_js_1.hashToken)(rawToken);
175
209
  inv.expiresAt = new Date(Date.now() + invitationTtl).toISOString();
176
210
  inv.resendCount += 1;
177
211
  await saveInvitations(accountId, snapshot.invitations, snapshot.revision);
178
- return inv;
212
+ return { ...inv, token: rawToken };
179
213
  });
180
214
  }
181
215
  /**
@@ -188,7 +222,7 @@ function createTeamInvitationService(deps, options) {
188
222
  const snapshot = await loadInvitations(accountId);
189
223
  applyLazyExpiry(snapshot.invitations);
190
224
  const now = new Date().toISOString();
191
- const inv = snapshot.invitations.find((i) => i.token === token && i.status === 'pending');
225
+ const inv = snapshot.invitations.find((i) => i.status === 'pending' && invitationMatchesToken(i.token, token));
192
226
  if (!inv) {
193
227
  throw new TeamInvitationError('Invalid or expired invitation token');
194
228
  }
@@ -206,7 +240,7 @@ function createTeamInvitationService(deps, options) {
206
240
  }
207
241
  async function findByToken(accountId, token) {
208
242
  const all = await getInvitations(accountId);
209
- return all.find((i) => i.token === token && i.status === 'pending') ?? null;
243
+ return all.find((i) => i.status === 'pending' && invitationMatchesToken(i.token, token)) ?? null;
210
244
  }
211
245
  /**
212
246
  * Resolve emails for account members by looking up identities in the 'email' domain.
@@ -1 +1 @@
1
- {"version":3,"file":"team-invitation-service.js","sourceRoot":"","sources":["../src/team-invitation-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"team-invitation-service.js","sourceRoot":"","sources":["../src/team-invitation-service.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -35,6 +35,14 @@ export interface UserProfile {
35
35
  export interface CredentialEntry {
36
36
  strategy: string;
37
37
  secret: string;
38
+ /**
39
+ * The identity this secret belongs to, when a strategy can hold more than one
40
+ * credential per user. API keys use it: a user may hold several keys at once,
41
+ * so each key's bcrypt hash is tagged with `hashToken(key)` — the same value
42
+ * the key's identity row stores — instead of sharing the single strategy slot.
43
+ * Absent for single-credential strategies like `local`.
44
+ */
45
+ identity_key?: string;
38
46
  }
39
47
  /** Auth credentials — strategy-keyed array, never plaintext (property: "credentials"). */
40
48
  export type UserCredentials = CredentialEntry[];
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AA6BA,+DAA+D;AAC/D,MAAa,sBAAuB,SAAQ,KAAK;IAI/C,YAAY,MAAc,EAAE,GAAW;QACrC,KAAK,CAAC,uBAAuB,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF;AAVD,wDAUC;AA2ED,2EAA2E;AAC3E,MAAa,yBAA0B,SAAQ,KAAK;IAIlD,YAAY,SAAiB,EAAE,MAAc;QAC3C,KAAK,CAAC,QAAQ,MAAM,mCAAmC,SAAS,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QACxC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAVD,8DAUC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AA6BA,+DAA+D;AAC/D,MAAa,sBAAuB,SAAQ,KAAK;IAI/C,YAAY,MAAc,EAAE,GAAW;QACrC,KAAK,CAAC,uBAAuB,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF;AAVD,wDAUC;AAmFD,2EAA2E;AAC3E,MAAa,yBAA0B,SAAQ,KAAK;IAIlD,YAAY,SAAiB,EAAE,MAAc;QAC3C,KAAK,CAAC,QAAQ,MAAM,mCAAmC,SAAS,EAAE,CAAC,CAAC;QACpE,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QACxC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAVD,8DAUC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boopkit/cap-users",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "User accounts, authentication, and session management via Prisma",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -127,19 +127,43 @@ An API key is simultaneously an identity, a credential, and a bearer token. All
127
127
 
128
128
  | Layer | What happens |
129
129
  |-------|-------------|
130
- | **Identity** | `domain: "api-key", key: "47ZHJY-..."` — lookup on each request |
130
+ | **Identity** | `domain: "api-key", key: "a3f1..."` — the SHA-256 of the key, as the cookie domain holds a session token. Lookup hashes the presented key and searches for that |
131
131
  | **Authentication** | `{ strategy: "api-key", accepted: true }` — user can use API keys |
132
132
  | **Credentials** | `{ strategy: "api-key", secret: "$2b$..." }` — bcrypt hash of the key |
133
- | **Authorization** | `{ identity_key: "47ZHJY-...", strategy: "api-key", trust: "authenticated", expires_at: 0 }` — standing per-key grant |
133
+ | **Authorization** | `{ identity_key: "a3f1...", strategy: "api-key", trust: "authenticated", expires_at: 0 }` — standing per-key grant, keyed on `hashToken(key)` (the same hash the identity row holds) |
134
134
 
135
135
  **Three independent levers to control access:**
136
136
  1. **Revoke the key** — end-date the identity. Immediate.
137
137
  2. **Disable API key auth** — set `accepted: false` on the authentication entry. All API keys stop working, but keys still exist.
138
- 3. **Expire the grant** — set `expires_at` on the per-key grant. Can be re-enabled without rotating the key.
138
+ 3. **Expire the grant** — set `expires_at` on the per-key grant. Can be re-enabled without rotating the key. Enforced at the gate, not inside `validateApiKey`: the presented key is routed through `isAuthorized`.
139
139
 
140
- **Validation flow:** identity lookup → `isMethodAccepted("api-key")` → bcrypt compare → check per-key grant → return user.
140
+ **Validation flow.** `validateApiKey` resolves a key — hash the presented key → identity lookup → `isMethodAccepted("api-key")` → bcrypt compare → return user. It does not read the grant; resolving answers "whose key is this?", not "is this key still allowed?". The grant (lever 3) is checked at the gate: `requireAuth`/`requireApiKey` call `isAuthorized(user.id, presentedKey, trust)`, and `resolveBearer` records the presented key as `req.sessionToken` so that call finds the per-key grant.
141
141
 
142
- The plaintext key is returned exactly once at creation. Only the hash is stored.
142
+ **Presenting a key.** `resolveBearer`, exported from `src/middleware/auth.ts`, reads `Authorization: Bearer <key>`, sets the same `req.user` a session cookie yields, and also records `req.sessionToken` (the presented key) and `req.authStrategy = 'api-key'`. The `req.sessionToken` it sets is what lets `requireAuth` — which reads both `req.user` and `req.sessionToken` — admit the key instead of redirecting it to `/login`.
143
+ Mount it on your API router ahead of your routes and gate:
144
+
145
+ ```typescript
146
+ // src/routes/api.ts
147
+ import { resolveBearer, requireAuth, requireApiKey } from '../middleware/auth';
148
+
149
+ healthCheck(router); // before resolveBearer — a probe's stale key won't 401 it
150
+ router.use(resolveBearer); // authenticate a token, if one is sent
151
+ router.get('/me', requireAuth(), apiController.me); // cookie OR key — door-agnostic
152
+ router.get('/integrations', requireApiKey(), apiController.integrations); // an API key only
153
+ ```
154
+
155
+ `requireAuth` accepts any authorized principal, so a logged-in browser satisfies `/me` without a key (`resolveVisitor` runs app-wide and populates `req.user` before this router). Use `requireApiKey` when a route must be reached *with a key* — it accepts the request only when `req.authStrategy === 'api-key'`, then runs the same `isAuthorized` grant check, so revoking or expiring the key stops the request even for a user whose browser session is still alive.
156
+
157
+ `resolveBearer` is not mounted for you, because app-wide it would answer every request that carries a bad token.
158
+ A request with no `Authorization` header passes through with `req.user` unset, so the same router still serves anonymous routes.
159
+ A token that does not resolve gets `401 { error: 'invalid_token' }` and a `WWW-Authenticate` challenge, and does **not** fall back to the session cookie — revoking a key has to stop the request even from a browser that is still logged in.
160
+ It refuses a malformed token on every route it covers, open ones included, which is why the health check is mounted ahead of it: a route registered before `resolveBearer` never sees the middleware, so a monitor carrying a stale or garbled `Authorization` header still gets its `200` rather than a `401`.
161
+
162
+ **Issuing a key is yours to design.**
163
+ `authService.createApiKey(userId)` mints one and returns the raw key exactly once; the identity row holds its SHA-256 and the credentials entry a bcrypt hash, so nothing can hand it back later and any surface you build has to say so at the moment it is shown.
164
+ This capability deliberately ships no route, screen, or command for it.
165
+ Minting a credential that acts as a user is not a generic operation: who may do it, for whom, whether it needs a second factor or an approval, how many keys a user may hold, and what the audit trail looks like are answers only your application has, and a default affordance would answer them for you — wrongly, and on the sensitive side.
166
+ Wire it behind whatever authorization your app already trusts, and reach for the three levers below when you need to take a key back.
143
167
 
144
168
  ### OAuth (as client)
145
169
 
@@ -234,8 +258,23 @@ The raw key is returned once and is not what `user_identities` holds: the row st
234
258
  To authenticate an HTTP request with one, mount `resolveBearer` — it reads `Authorization: Bearer <key>`, sets the same `req.user` the cookie path yields, and answers `401 { error: 'invalid_token' }` with a `WWW-Authenticate: Bearer` challenge when the token does not resolve.
235
259
  It never falls back to the session cookie, so revoking a key stops the request even from a browser that still holds a session.
236
260
 
237
- > The authorization *grant* still records the raw key as its `identity_key`, because that is the value callers pass to `isAuthorized` and `getTrustTier` and session grants store their token the same way.
238
- > Fixing that half consistently — grants and sessions together, with a migration that rehashes rather than logging everyone out — is tracked separately.
261
+ > The authorization *grant* records `hashToken(key)` as its `identity_key`, never the raw key — the same treatment the identity row and credential entry get. Session grants store their token the same way. `identity_key` is only ever compared for equality, so `setAuthorization` hashes the value it is handed, and `isAuthorized` / `getTrustTier` hash the raw token a caller presents before comparing. The raw value never lands in the readable `authorization` property.
262
+ > `resolveBearer` still records the presented **raw** key as `req.sessionToken`, and the gate calls `isAuthorized(user.id, req.sessionToken, …)`. That keeps working because `isAuthorized` hashes its argument — so the call site does **not** hash, and must not: hashing at both ends would double-hash and never match.
263
+
264
+ ### Migrating existing deployments
265
+
266
+ A deployment that stored grants before this fix keeps a raw session token or API key in each `authorization` row. The read path tolerates the old form permanently — it matches either `identity_key === hashToken(token)` or `identity_key === token` — so **nobody is logged out by upgrading**. The first time a raw grant is matched, the service logs one warning per process nudging you to migrate; it goes quiet on its own once the data is hashed.
267
+
268
+ `boop status` flags the un-migrated rows (its probe checks that every `authorization` row carries the `authorization-hashed-01` info_schema tag). To clear them, rehash in place:
269
+
270
+ ```bash
271
+ npm run credentials:migrate # REPORT ONLY — counts what would change, writes nothing
272
+ npm run credentials:migrate -- --run # apply the rehash
273
+ ```
274
+
275
+ The same tool and command also rehash **team invitation tokens**. An invitation token is a bearer credential — presenting it joins the account at the role the invitation grants — so it is hashed at rest exactly as session cookies and API keys are: the raw token is emailed to the invitee once and only its hash is stored in the `team_invitations` account-property, and `acceptInvitation` / `findByToken` hash the presented token before comparing. The read path tolerates a pre-fix row whose stored token is still raw (matching `token === hashToken(presented)` or `token === presented`), so **no pending invitation is voided by upgrading**, and it warns once per process until the data is migrated. `boop status` has a matching probe (every `team_invitations` row must carry the `team-invitations-hashed-01` tag), and the migration run above stamps it.
276
+
277
+ Because the raw values are still present, the tool rehashes them in place rather than invalidating them — every session, standing key, and pending invitation keeps working. It is **one-way and has no rollback**: once a row is rewritten the raw value is gone, so **take a database backup before `--run`**. Re-running is safe: a value that is already a SHA-256 digest is left untouched, so nothing is ever double-hashed.
239
278
 
240
279
  **Trust queries**: `getTrustTier(userId, identityKey)`, `isAuthorized(userId, identityKey, requiredTrust?)`.
241
280
 
@@ -272,4 +311,7 @@ The type propagates through all service operations.
272
311
  |------|---------|
273
312
  | `prisma/users.prisma` | User, UserIdentity, UserProperty table definitions |
274
313
  | `src/services/users.service.ts` | Service wiring — instantiates all user services |
314
+ | `src/types/express.ts` | Global Express request augmentation: types `req.user`, `req.sessionToken`, `req.visitorToken`, `req.authStrategy` for every handler |
275
315
  | `@boopkit/cap-users` | Service factories (user, identity, property, auth) |
316
+
317
+ **Request typing.** The four fields the auth middleware writes onto the request — `req.user` (the resolved `User`), `req.sessionToken`, `req.visitorToken`, and `req.authStrategy` — are declared once in `src/types/express.ts`, a global ambient augmentation your tsconfig compiles with the rest of `src/`. Handlers read them off `express`'s `Request` directly, with no per-file cast or hand-rolled request interface. The user shape hangs off `Express.User` rather than being typed onto `Request.user` directly, so it merges cleanly with the empty `Express.User` that `@types/passport` contributes once oauth-client is installed instead of colliding with it.