@tumbaland/backend-core 1.36.0 → 1.38.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.
- package/dist/apiKeys/ApiKey.d.ts +12 -3
- package/dist/apiKeys/ApiKey.d.ts.map +1 -1
- package/dist/apiKeys/ApiKey.js +5 -1
- package/dist/apiKeys/ApiKey.js.map +1 -1
- package/dist/apiKeys/index.d.ts +2 -2
- package/dist/apiKeys/index.d.ts.map +1 -1
- package/dist/apiKeys/index.js +5 -1
- package/dist/apiKeys/index.js.map +1 -1
- package/dist/apiKeys/middleware.d.ts +9 -5
- package/dist/apiKeys/middleware.d.ts.map +1 -1
- package/dist/apiKeys/middleware.js +125 -59
- package/dist/apiKeys/middleware.js.map +1 -1
- package/dist/apiKeys/service.d.ts +5 -3
- package/dist/apiKeys/service.d.ts.map +1 -1
- package/dist/apiKeys/service.js +10 -3
- package/dist/apiKeys/service.js.map +1 -1
- package/dist/apiKeys/types.d.ts +41 -8
- package/dist/apiKeys/types.d.ts.map +1 -1
- package/dist/apiKeys/types.js +35 -1
- package/dist/apiKeys/types.js.map +1 -1
- package/dist/middleware/authMiddleware.d.ts +7 -0
- package/dist/middleware/authMiddleware.d.ts.map +1 -1
- package/dist/middleware/authMiddleware.js +25 -4
- package/dist/middleware/authMiddleware.js.map +1 -1
- package/dist/oauth/index.d.ts +1 -1
- package/dist/oauth/index.d.ts.map +1 -1
- package/dist/oauth/index.js +3 -1
- package/dist/oauth/index.js.map +1 -1
- package/dist/oauth/models.d.ts +13 -2
- package/dist/oauth/models.d.ts.map +1 -1
- package/dist/oauth/models.js +9 -0
- package/dist/oauth/models.js.map +1 -1
- package/dist/oauth/service.d.ts +15 -8
- package/dist/oauth/service.d.ts.map +1 -1
- package/dist/oauth/service.js +10 -3
- package/dist/oauth/service.js.map +1 -1
- package/dist/oauth/tokens.d.ts +34 -8
- package/dist/oauth/tokens.d.ts.map +1 -1
- package/dist/oauth/tokens.js +22 -6
- package/dist/oauth/tokens.js.map +1 -1
- package/package.json +1 -1
- package/src/apiKeys/ApiKey.ts +16 -4
- package/src/apiKeys/index.ts +16 -2
- package/src/apiKeys/middleware.test.ts +207 -16
- package/src/apiKeys/middleware.ts +159 -66
- package/src/apiKeys/service.test.ts +56 -9
- package/src/apiKeys/service.ts +24 -6
- package/src/apiKeys/types.ts +61 -8
- package/src/middleware/authMiddleware.test.ts +52 -0
- package/src/middleware/authMiddleware.ts +26 -4
- package/src/oauth/index.ts +7 -1
- package/src/oauth/models.ts +21 -2
- package/src/oauth/service.test.ts +58 -6
- package/src/oauth/service.ts +25 -7
- package/src/oauth/tokens.test.ts +20 -5
- package/src/oauth/tokens.ts +51 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/apiKeys/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,cAAc,oHAOjB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,WAC4B,CAAC;AAErF;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/apiKeys/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,cAAc,oHAOjB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,WAC4B,CAAC;AAErF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,aAAa,CAAC;AAE1C,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAE5B,8EAA8E;AAC9E,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,KAAG,MAAM,GAAG,IACR,CAAC;AAE7C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,6EAA6E;AAC7E,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,EAAE,KAAG,MAAM,EACG,CAAC;AAEzD;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GAAI,QAAQ;IAClC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,KAAG,YAaH,CAAC;AAEF,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,2FAA2F;AAC3F,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,SAAS,GACT,SAAS,GACT,SAAS,GACT,YAAY,CAAC;AAEjB,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB"}
|
package/dist/apiKeys/types.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* it writes to rather than choosing one per request the way the UI does.
|
|
10
10
|
*/
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.isApiKeyScope = exports.API_KEY_SCOPES = void 0;
|
|
12
|
+
exports.readTenants = exports.groupIdsOf = exports.groupIdOf = exports.PERSONAL_TENANT = exports.isApiKeyScope = exports.API_KEY_SCOPES = void 0;
|
|
13
13
|
/** Everything a key may be granted. Read and write are separate on purpose. */
|
|
14
14
|
exports.API_KEY_SCOPES = [
|
|
15
15
|
'relationship:read',
|
|
@@ -21,4 +21,38 @@ exports.API_KEY_SCOPES = [
|
|
|
21
21
|
];
|
|
22
22
|
const isApiKeyScope = (value) => typeof value === 'string' && exports.API_KEY_SCOPES.includes(value);
|
|
23
23
|
exports.isApiKeyScope = isApiKeyScope;
|
|
24
|
+
/**
|
|
25
|
+
* A tenant a credential may act in: a group id, or the user's own data.
|
|
26
|
+
*
|
|
27
|
+
* Personal is a named sentinel rather than `null` so that a tenant is always a
|
|
28
|
+
* plain string — storable in an array, sendable in a JWT claim, comparable
|
|
29
|
+
* without a special case at every layer. It cannot collide with a real tenant:
|
|
30
|
+
* group ids are 24-character hex.
|
|
31
|
+
*/
|
|
32
|
+
exports.PERSONAL_TENANT = 'personal';
|
|
33
|
+
/** The `groupId` a tenant corresponds to, as handlers have always read it. */
|
|
34
|
+
const groupIdOf = (tenant) => tenant === exports.PERSONAL_TENANT ? null : tenant;
|
|
35
|
+
exports.groupIdOf = groupIdOf;
|
|
36
|
+
/** Just the groups, for the `req.userGroups` every handler already reads. */
|
|
37
|
+
const groupIdsOf = (tenants) => tenants.filter((tenant) => tenant !== exports.PERSONAL_TENANT);
|
|
38
|
+
exports.groupIdsOf = groupIdsOf;
|
|
39
|
+
/**
|
|
40
|
+
* Read a stored tenant grant, tolerating one written before tenants were a set.
|
|
41
|
+
*
|
|
42
|
+
* Keys and grants issued under the old single-tenant model carry `groupId`
|
|
43
|
+
* alone. Falling back to it here means they keep working across the deploy
|
|
44
|
+
* rather than every connected assistant breaking at once.
|
|
45
|
+
*/
|
|
46
|
+
const readTenants = (stored) => {
|
|
47
|
+
const allowed = stored.tenants && stored.tenants.length > 0
|
|
48
|
+
? stored.tenants
|
|
49
|
+
: [stored.groupId ?? exports.PERSONAL_TENANT];
|
|
50
|
+
const fallbackDefault = allowed[0];
|
|
51
|
+
const preferred = stored.defaultTenant ?? fallbackDefault;
|
|
52
|
+
return {
|
|
53
|
+
allowed,
|
|
54
|
+
default: allowed.includes(preferred) ? preferred : fallbackDefault
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
exports.readTenants = readTenants;
|
|
24
58
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/apiKeys/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAEH,+EAA+E;AAClE,QAAA,cAAc,GAAG;IAC5B,mBAAmB;IACnB,oBAAoB;IACpB,YAAY;IACZ,aAAa;IACb,cAAc;IACd,eAAe;CACP,CAAC;AAIJ,MAAM,aAAa,GAAG,CAAC,KAAc,EAAwB,EAAE,CACpE,OAAO,KAAK,KAAK,QAAQ,IAAK,sBAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AADxE,QAAA,aAAa,iBAC2D"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/apiKeys/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;AAEH,+EAA+E;AAClE,QAAA,cAAc,GAAG;IAC5B,mBAAmB;IACnB,oBAAoB;IACpB,YAAY;IACZ,aAAa;IACb,cAAc;IACd,eAAe;CACP,CAAC;AAIJ,MAAM,aAAa,GAAG,CAAC,KAAc,EAAwB,EAAE,CACpE,OAAO,KAAK,KAAK,QAAQ,IAAK,sBAAoC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AADxE,QAAA,aAAa,iBAC2D;AAErF;;;;;;;GAOG;AACU,QAAA,eAAe,GAAG,UAAU,CAAC;AAI1C,8EAA8E;AACvE,MAAM,SAAS,GAAG,CAAC,MAAc,EAAiB,EAAE,CACzD,MAAM,KAAK,uBAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AADhC,QAAA,SAAS,aACuB;AAoB7C,6EAA6E;AACtE,MAAM,UAAU,GAAG,CAAC,OAAiB,EAAY,EAAE,CACxD,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,uBAAe,CAAC,CAAC;AAD5C,QAAA,UAAU,cACkC;AAEzD;;;;;;GAMG;AACI,MAAM,WAAW,GAAG,CAAC,MAI3B,EAAgB,EAAE;IACjB,MAAM,OAAO,GACX,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QACzC,CAAC,CAAC,MAAM,CAAC,OAAO;QAChB,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,IAAI,uBAAe,CAAC,CAAC;IAE1C,MAAM,eAAe,GAAG,OAAO,CAAC,CAAC,CAAW,CAAC;IAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,aAAa,IAAI,eAAe,CAAC;IAE1D,OAAO;QACL,OAAO;QACP,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe;KACnE,CAAC;AACJ,CAAC,CAAC;AAjBW,QAAA,WAAW,eAiBtB"}
|
|
@@ -4,6 +4,13 @@ import { Request, Response, NextFunction } from 'express';
|
|
|
4
4
|
* Verifies JWT token and attaches user info (and its embedded groups) to
|
|
5
5
|
* the request — typed via the global `Express.Request` augmentation in
|
|
6
6
|
* `../types/auth`, no `(req as any)` cast needed.
|
|
7
|
+
*
|
|
8
|
+
* OAuth access tokens are refused outright. They are signed with the same
|
|
9
|
+
* secret, so they verify here, but they mean something this middleware has no
|
|
10
|
+
* way to honour: an assistant acting within scopes, pinned to one tenant.
|
|
11
|
+
* Routes that software may legitimately reach use `authenticateAgent`, which
|
|
12
|
+
* enforces both — so anything still guarded by this one is a person's to do,
|
|
13
|
+
* and letting a token through would be handing an assistant the account.
|
|
7
14
|
*/
|
|
8
15
|
export declare function authenticateToken(req: Request, res: Response, next: NextFunction): void;
|
|
9
16
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/authMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"authMiddleware.d.ts","sourceRoot":"","sources":["../../src/middleware/authMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAM1D;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CA0BvF;AACD;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAmBnF"}
|
|
@@ -7,11 +7,19 @@ exports.authenticateToken = authenticateToken;
|
|
|
7
7
|
exports.optionalAuth = optionalAuth;
|
|
8
8
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
9
9
|
const env_1 = require("../config/env");
|
|
10
|
+
const tokens_1 = require("../oauth/tokens");
|
|
10
11
|
/**
|
|
11
12
|
* JWT authentication middleware
|
|
12
13
|
* Verifies JWT token and attaches user info (and its embedded groups) to
|
|
13
14
|
* the request — typed via the global `Express.Request` augmentation in
|
|
14
15
|
* `../types/auth`, no `(req as any)` cast needed.
|
|
16
|
+
*
|
|
17
|
+
* OAuth access tokens are refused outright. They are signed with the same
|
|
18
|
+
* secret, so they verify here, but they mean something this middleware has no
|
|
19
|
+
* way to honour: an assistant acting within scopes, pinned to one tenant.
|
|
20
|
+
* Routes that software may legitimately reach use `authenticateAgent`, which
|
|
21
|
+
* enforces both — so anything still guarded by this one is a person's to do,
|
|
22
|
+
* and letting a token through would be handing an assistant the account.
|
|
15
23
|
*/
|
|
16
24
|
function authenticateToken(req, res, next) {
|
|
17
25
|
try {
|
|
@@ -21,7 +29,15 @@ function authenticateToken(req, res, next) {
|
|
|
21
29
|
res.status(401).json({ success: false, message: 'Access token required' });
|
|
22
30
|
return;
|
|
23
31
|
}
|
|
24
|
-
const
|
|
32
|
+
const claims = jsonwebtoken_1.default.verify(token, JWT_SECRET);
|
|
33
|
+
if ((0, tokens_1.isAccessTokenClaims)(claims)) {
|
|
34
|
+
res.status(403).json({
|
|
35
|
+
success: false,
|
|
36
|
+
message: 'This operation requires an interactive session, not a connected assistant'
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const user = claims;
|
|
25
41
|
req.user = user;
|
|
26
42
|
req.userGroups = user.groups ?? [];
|
|
27
43
|
next();
|
|
@@ -48,9 +64,14 @@ function optionalAuth(req, _res, next) {
|
|
|
48
64
|
const JWT_SECRET = (0, env_1.requireEnv)('JWT_SECRET');
|
|
49
65
|
const token = req.cookies?.access_token || req.headers.authorization?.replace('Bearer ', '');
|
|
50
66
|
if (token) {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
67
|
+
const claims = jsonwebtoken_1.default.verify(token, JWT_SECRET);
|
|
68
|
+
// An access token is not a session; treated as none, exactly like an
|
|
69
|
+
// expired cookie, so the route still answers with its public form.
|
|
70
|
+
if (!(0, tokens_1.isAccessTokenClaims)(claims)) {
|
|
71
|
+
const user = claims;
|
|
72
|
+
req.user = user;
|
|
73
|
+
req.userGroups = user.groups ?? [];
|
|
74
|
+
}
|
|
54
75
|
}
|
|
55
76
|
}
|
|
56
77
|
catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authMiddleware.js","sourceRoot":"","sources":["../../src/middleware/authMiddleware.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"authMiddleware.js","sourceRoot":"","sources":["../../src/middleware/authMiddleware.ts"],"names":[],"mappings":";;;;;AAmBA,8CA0BC;AAcD,oCAmBC;AA7ED,gEAA+B;AAC/B,uCAA2C;AAC3C,4CAAsD;AAGtD;;;;;;;;;;;;GAYG;AACH,SAAgB,iBAAiB,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC/E,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAA,gBAAU,EAAC,YAAY,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,YAAY,IAAI,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAE7F,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAC7C,IAAI,IAAA,4BAAmB,EAAC,MAAM,CAAC,EAAE,CAAC;YAChC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,2EAA2E;aACrF,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,MAAqB,CAAC;QACnC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAChB,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;QACnC,IAAI,EAAE,CAAC;IACT,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC,CAAC;IAChF,CAAC;AACH,CAAC;AACD;;;;;;;;;;;;GAYG;AACH,SAAgB,YAAY,CAAC,GAAY,EAAE,IAAc,EAAE,IAAkB;IAC3E,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAA,gBAAU,EAAC,YAAY,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,YAAY,IAAI,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAE7F,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,MAAM,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YAC7C,qEAAqE;YACrE,mEAAmE;YACnE,IAAI,CAAC,IAAA,4BAAmB,EAAC,MAAM,CAAC,EAAE,CAAC;gBACjC,MAAM,IAAI,GAAG,MAAqB,CAAC;gBACnC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;gBAChB,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;YACrC,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,oCAAoC;IACtC,CAAC;IACD,IAAI,EAAE,CAAC;AACT,CAAC"}
|
package/dist/oauth/index.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ export { OAuthClient, AuthorizationCode, RefreshToken } from './models';
|
|
|
2
2
|
export type { IOAuthClient, IAuthorizationCode, IRefreshToken } from './models';
|
|
3
3
|
export { registerClient, findClient, isRegisteredRedirect, issueAuthorizationCode, redeemAuthorizationCode, issueRefreshToken, redeemRefreshToken, revokeRefreshTokensForUser, listConnections } from './service';
|
|
4
4
|
export type { RegisterClientInput, RegisteredClient, IssueCodeInput, CodeRedemption, CodeRejection, RefreshRedemption } from './service';
|
|
5
|
-
export { mintAccessToken, verifyAccessToken, parseScopes } from './tokens';
|
|
5
|
+
export { mintAccessToken, verifyAccessToken, parseScopes, isAccessTokenClaims, ACCESS_TOKEN_TYPE } from './tokens';
|
|
6
6
|
export type { AccessTokenClaims, MintAccessTokenInput, MintedAccessToken, AccessTokenVerification } from './tokens';
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxE,YAAY,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAChF,OAAO,EACL,cAAc,EACd,UAAU,EACV,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,EAClB,0BAA0B,EAC1B,eAAe,EAChB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,aAAa,EACb,iBAAiB,EAClB,MAAM,WAAW,CAAC;AACnB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxE,YAAY,EAAE,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAChF,OAAO,EACL,cAAc,EACd,UAAU,EACV,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,EAClB,0BAA0B,EAC1B,eAAe,EAChB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,aAAa,EACb,iBAAiB,EAClB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/oauth/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseScopes = exports.verifyAccessToken = exports.mintAccessToken = exports.listConnections = exports.revokeRefreshTokensForUser = exports.redeemRefreshToken = exports.issueRefreshToken = exports.redeemAuthorizationCode = exports.issueAuthorizationCode = exports.isRegisteredRedirect = exports.findClient = exports.registerClient = exports.RefreshToken = exports.AuthorizationCode = exports.OAuthClient = void 0;
|
|
3
|
+
exports.ACCESS_TOKEN_TYPE = exports.isAccessTokenClaims = exports.parseScopes = exports.verifyAccessToken = exports.mintAccessToken = exports.listConnections = exports.revokeRefreshTokensForUser = exports.redeemRefreshToken = exports.issueRefreshToken = exports.redeemAuthorizationCode = exports.issueAuthorizationCode = exports.isRegisteredRedirect = exports.findClient = exports.registerClient = exports.RefreshToken = exports.AuthorizationCode = exports.OAuthClient = void 0;
|
|
4
4
|
var models_1 = require("./models");
|
|
5
5
|
Object.defineProperty(exports, "OAuthClient", { enumerable: true, get: function () { return models_1.OAuthClient; } });
|
|
6
6
|
Object.defineProperty(exports, "AuthorizationCode", { enumerable: true, get: function () { return models_1.AuthorizationCode; } });
|
|
@@ -19,4 +19,6 @@ var tokens_1 = require("./tokens");
|
|
|
19
19
|
Object.defineProperty(exports, "mintAccessToken", { enumerable: true, get: function () { return tokens_1.mintAccessToken; } });
|
|
20
20
|
Object.defineProperty(exports, "verifyAccessToken", { enumerable: true, get: function () { return tokens_1.verifyAccessToken; } });
|
|
21
21
|
Object.defineProperty(exports, "parseScopes", { enumerable: true, get: function () { return tokens_1.parseScopes; } });
|
|
22
|
+
Object.defineProperty(exports, "isAccessTokenClaims", { enumerable: true, get: function () { return tokens_1.isAccessTokenClaims; } });
|
|
23
|
+
Object.defineProperty(exports, "ACCESS_TOKEN_TYPE", { enumerable: true, get: function () { return tokens_1.ACCESS_TOKEN_TYPE; } });
|
|
22
24
|
//# sourceMappingURL=index.js.map
|
package/dist/oauth/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":";;;AAAA,mCAAwE;AAA/D,qGAAA,WAAW,OAAA;AAAE,2GAAA,iBAAiB,OAAA;AAAE,sGAAA,YAAY,OAAA;AAErD,qCAUmB;AATjB,yGAAA,cAAc,OAAA;AACd,qGAAA,UAAU,OAAA;AACV,+GAAA,oBAAoB,OAAA;AACpB,iHAAA,sBAAsB,OAAA;AACtB,kHAAA,uBAAuB,OAAA;AACvB,4GAAA,iBAAiB,OAAA;AACjB,6GAAA,kBAAkB,OAAA;AAClB,qHAAA,0BAA0B,OAAA;AAC1B,0GAAA,eAAe,OAAA;AAUjB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":";;;AAAA,mCAAwE;AAA/D,qGAAA,WAAW,OAAA;AAAE,2GAAA,iBAAiB,OAAA;AAAE,sGAAA,YAAY,OAAA;AAErD,qCAUmB;AATjB,yGAAA,cAAc,OAAA;AACd,qGAAA,UAAU,OAAA;AACV,+GAAA,oBAAoB,OAAA;AACpB,iHAAA,sBAAsB,OAAA;AACtB,kHAAA,uBAAuB,OAAA;AACvB,4GAAA,iBAAiB,OAAA;AACjB,6GAAA,kBAAkB,OAAA;AAClB,qHAAA,0BAA0B,OAAA;AAC1B,0GAAA,eAAe,OAAA;AAUjB,mCAMkB;AALhB,yGAAA,eAAe,OAAA;AACf,2GAAA,iBAAiB,OAAA;AACjB,qGAAA,WAAW,OAAA;AACX,6GAAA,mBAAmB,OAAA;AACnB,2GAAA,iBAAiB,OAAA"}
|
package/dist/oauth/models.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import mongoose, { Document } from 'mongoose';
|
|
2
|
+
import { type Tenant } from '../apiKeys/types';
|
|
2
3
|
/**
|
|
3
4
|
* A client registered through RFC 7591 Dynamic Client Registration.
|
|
4
5
|
*
|
|
@@ -38,7 +39,13 @@ export interface IAuthorizationCode extends Document {
|
|
|
38
39
|
userName: string;
|
|
39
40
|
redirectUri: string;
|
|
40
41
|
scopes: string[];
|
|
41
|
-
|
|
42
|
+
/** every tenant the user approved, and the one chosen as the default */
|
|
43
|
+
tenants: Tenant[];
|
|
44
|
+
defaultTenant: Tenant;
|
|
45
|
+
/** what each approved tenant is called, snapshotted at consent */
|
|
46
|
+
tenantNames: Record<Tenant, string>;
|
|
47
|
+
/** the single tenant an older grant was pinned to; read by `readTenants` */
|
|
48
|
+
groupId?: string | null;
|
|
42
49
|
/** RFC 8707: the MCP server this will be minted for */
|
|
43
50
|
resource: string;
|
|
44
51
|
/** PKCE, always S256 — the spec does not allow `plain` */
|
|
@@ -68,7 +75,11 @@ export interface IRefreshToken extends Document {
|
|
|
68
75
|
clientId: string;
|
|
69
76
|
userId: string;
|
|
70
77
|
scopes: string[];
|
|
71
|
-
|
|
78
|
+
tenants: Tenant[];
|
|
79
|
+
defaultTenant: Tenant;
|
|
80
|
+
tenantNames: Record<Tenant, string>;
|
|
81
|
+
/** the single tenant an older grant was pinned to; read by `readTenants` */
|
|
82
|
+
groupId?: string | null;
|
|
72
83
|
resource: string;
|
|
73
84
|
/**
|
|
74
85
|
* When the user actually connected this assistant.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/oauth/models.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,EAAE,EAAE,QAAQ,EAAU,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/oauth/models.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,EAAE,EAAE,QAAQ,EAAU,MAAM,UAAU,CAAC;AACtD,OAAO,EAAmB,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAEhE;;;;;;;GAOG;AACH,MAAM,WAAW,YAAa,SAAQ,QAAQ;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAWD,eAAO,MAAM,WAAW;;;;;;qBAE0C,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAmB,SAAQ,QAAQ;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,wEAAwE;IACxE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,mFAAmF;IACnF,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AA4BD,eAAO,MAAM,iBAAiB;;;;;;2BAEsD,CAAC;AAErF;;;;;;;GAOG;AACH,MAAM,WAAW,aAAc,SAAQ,QAAQ;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAuBD,eAAO,MAAM,YAAY;;;;;;sBAE4C,CAAC"}
|
package/dist/oauth/models.js
CHANGED
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.RefreshToken = exports.AuthorizationCode = exports.OAuthClient = void 0;
|
|
37
37
|
const mongoose_1 = __importStar(require("mongoose"));
|
|
38
|
+
const types_1 = require("../apiKeys/types");
|
|
38
39
|
const OAuthClientSchema = new mongoose_1.Schema({
|
|
39
40
|
clientId: { type: String, required: true, unique: true, index: true },
|
|
40
41
|
clientName: { type: String, required: true, maxlength: 200 },
|
|
@@ -51,6 +52,10 @@ const AuthorizationCodeSchema = new mongoose_1.Schema({
|
|
|
51
52
|
userName: { type: String, default: '' },
|
|
52
53
|
redirectUri: { type: String, required: true },
|
|
53
54
|
scopes: { type: [String], default: [] },
|
|
55
|
+
tenants: { type: [String], default: () => [types_1.PERSONAL_TENANT] },
|
|
56
|
+
defaultTenant: { type: String, default: types_1.PERSONAL_TENANT },
|
|
57
|
+
tenantNames: { type: mongoose_1.Schema.Types.Mixed, default: () => ({}) },
|
|
58
|
+
// Written by the single-tenant model this replaced; read-only now.
|
|
54
59
|
groupId: { type: String, default: null },
|
|
55
60
|
resource: { type: String, required: true },
|
|
56
61
|
codeChallenge: { type: String, required: true },
|
|
@@ -68,6 +73,10 @@ const RefreshTokenSchema = new mongoose_1.Schema({
|
|
|
68
73
|
clientId: { type: String, required: true },
|
|
69
74
|
userId: { type: String, required: true, index: true },
|
|
70
75
|
scopes: { type: [String], default: [] },
|
|
76
|
+
tenants: { type: [String], default: () => [types_1.PERSONAL_TENANT] },
|
|
77
|
+
defaultTenant: { type: String, default: types_1.PERSONAL_TENANT },
|
|
78
|
+
tenantNames: { type: mongoose_1.Schema.Types.Mixed, default: () => ({}) },
|
|
79
|
+
// Written by the single-tenant model this replaced; read-only now.
|
|
71
80
|
groupId: { type: String, default: null },
|
|
72
81
|
resource: { type: String, required: true },
|
|
73
82
|
grantedAt: { type: Date, default: Date.now },
|
package/dist/oauth/models.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/oauth/models.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qDAAsD;
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/oauth/models.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth/service.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IAuthorizationCode } from './models';
|
|
2
|
-
import type
|
|
2
|
+
import { type ApiKeyScope, type ApiKeyTenant, type Tenant } from '../apiKeys/types';
|
|
3
3
|
export interface RegisterClientInput {
|
|
4
4
|
clientName: string;
|
|
5
5
|
redirectUris: string[];
|
|
@@ -54,7 +54,9 @@ export interface IssueCodeInput {
|
|
|
54
54
|
userName: string;
|
|
55
55
|
redirectUri: string;
|
|
56
56
|
scopes: ApiKeyScope[];
|
|
57
|
-
|
|
57
|
+
tenants: Tenant[];
|
|
58
|
+
defaultTenant: Tenant;
|
|
59
|
+
tenantNames: Record<Tenant, string>;
|
|
58
60
|
resource: string;
|
|
59
61
|
codeChallenge: string;
|
|
60
62
|
}
|
|
@@ -87,7 +89,9 @@ export declare const issueRefreshToken: (input: {
|
|
|
87
89
|
clientId: string;
|
|
88
90
|
userId: string;
|
|
89
91
|
scopes: ApiKeyScope[];
|
|
90
|
-
|
|
92
|
+
tenants: Tenant[];
|
|
93
|
+
defaultTenant: Tenant;
|
|
94
|
+
tenantNames: Record<Tenant, string>;
|
|
91
95
|
resource: string;
|
|
92
96
|
}) => Promise<IssuedRefreshToken>;
|
|
93
97
|
export interface RefreshRedemption {
|
|
@@ -96,7 +100,8 @@ export interface RefreshRedemption {
|
|
|
96
100
|
reused?: boolean;
|
|
97
101
|
userId?: string;
|
|
98
102
|
scopes?: ApiKeyScope[];
|
|
99
|
-
|
|
103
|
+
tenants?: ApiKeyTenant;
|
|
104
|
+
tenantNames?: Record<Tenant, string>;
|
|
100
105
|
resource?: string;
|
|
101
106
|
/** the replacement the client must store; the presented one is now dead */
|
|
102
107
|
rotatedToken?: string;
|
|
@@ -120,13 +125,15 @@ export declare const redeemRefreshToken: (token: string, clientId: string) => Pr
|
|
|
120
125
|
/** Cut off an assistant: without a refresh token it can obtain nothing new. */
|
|
121
126
|
export declare const revokeRefreshTokensForUser: (userId: string, clientId?: string) => Promise<number>;
|
|
122
127
|
export declare const listConnections: (userId: string) => Promise<{
|
|
128
|
+
tenantNames: Record<string, string>;
|
|
129
|
+
createdAt: string;
|
|
130
|
+
lastRenewedAt: string | null;
|
|
131
|
+
revokedAt: string | null;
|
|
132
|
+
tenants: string[];
|
|
133
|
+
defaultTenant: string;
|
|
123
134
|
id: string;
|
|
124
135
|
clientId: string;
|
|
125
136
|
clientName: string;
|
|
126
137
|
scopes: string[];
|
|
127
|
-
groupId: string | null;
|
|
128
|
-
createdAt: string;
|
|
129
|
-
lastRenewedAt: string | null;
|
|
130
|
-
revokedAt: string | null;
|
|
131
138
|
}[]>;
|
|
132
139
|
//# sourceMappingURL=service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/oauth/service.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,kBAAkB,EAA6B,MAAM,UAAU,CAAC;AAC5F,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/oauth/service.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth/service.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.listConnections = exports.revokeRefreshTokensForUser = exports.redeemRefreshToken = exports.issueRefreshToken = exports.redeemAuthorizationCode = exports.issueAuthorizationCode = exports.isRegisteredRedirect = exports.findClient = exports.registerClient = void 0;
|
|
4
4
|
const crypto_1 = require("crypto");
|
|
5
5
|
const models_1 = require("./models");
|
|
6
|
+
const types_1 = require("../apiKeys/types");
|
|
6
7
|
/** How long a user has between approving and the client exchanging the code. */
|
|
7
8
|
const CODE_TTL_MS = 60 * 1000;
|
|
8
9
|
const sha256 = (value) => (0, crypto_1.createHash)('sha256').update(value).digest('hex');
|
|
@@ -143,7 +144,11 @@ const redeemRefreshToken = async (token, clientId) => {
|
|
|
143
144
|
clientId,
|
|
144
145
|
userId: record.userId,
|
|
145
146
|
scopes: record.scopes,
|
|
146
|
-
|
|
147
|
+
// Carried, not reset: rotation reissues the same grant, and re-deriving the
|
|
148
|
+
// tenants would quietly narrow a connection every time it refreshed.
|
|
149
|
+
tenants: record.tenants,
|
|
150
|
+
defaultTenant: record.defaultTenant,
|
|
151
|
+
tenantNames: record.tenantNames,
|
|
147
152
|
resource: record.resource,
|
|
148
153
|
// Carried, not reset: this is still the grant the user approved.
|
|
149
154
|
grantedAt: record.grantedAt ?? record.createdAt
|
|
@@ -152,7 +157,8 @@ const redeemRefreshToken = async (token, clientId) => {
|
|
|
152
157
|
ok: true,
|
|
153
158
|
userId: record.userId,
|
|
154
159
|
scopes: record.scopes,
|
|
155
|
-
|
|
160
|
+
tenants: (0, types_1.readTenants)(record),
|
|
161
|
+
tenantNames: record.tenantNames ?? {},
|
|
156
162
|
resource: record.resource,
|
|
157
163
|
rotatedToken: rotated
|
|
158
164
|
};
|
|
@@ -176,7 +182,8 @@ const listConnections = async (userId) => {
|
|
|
176
182
|
clientId: token.clientId,
|
|
177
183
|
clientName: nameById.get(token.clientId) ?? 'Unknown app',
|
|
178
184
|
scopes: token.scopes,
|
|
179
|
-
|
|
185
|
+
...(({ allowed, default: fallback }) => ({ tenants: allowed, defaultTenant: fallback }))((0, types_1.readTenants)(token)),
|
|
186
|
+
tenantNames: token.tenantNames ?? {},
|
|
180
187
|
createdAt: (token.grantedAt ?? token.createdAt).toISOString(),
|
|
181
188
|
// Set when the refresh token is exchanged, not when a tool runs — access
|
|
182
189
|
// tokens are validated statelessly, so the server never sees ordinary use.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/oauth/service.ts"],"names":[],"mappings":";;;AAAA,mCAAkE;AAClE,qCAA4F;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/oauth/service.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth/tokens.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ApiKeyScope } from '../apiKeys/types';
|
|
1
|
+
import { type ApiKeyScope, type ApiKeyTenant, type Tenant } from '../apiKeys/types';
|
|
2
2
|
/**
|
|
3
3
|
* Access tokens for the OAuth flow that lets an assistant connect to Tumbaland.
|
|
4
4
|
*
|
|
@@ -10,7 +10,7 @@ import { type ApiKeyScope } from '../apiKeys/types';
|
|
|
10
10
|
* token, which is the thing that actually persists.
|
|
11
11
|
*/
|
|
12
12
|
/** Marks a token as issued by the OAuth flow, for the MCP resource specifically. */
|
|
13
|
-
declare const
|
|
13
|
+
export declare const ACCESS_TOKEN_TYPE = "mcp_access";
|
|
14
14
|
export interface AccessTokenClaims {
|
|
15
15
|
/** the user the assistant is acting for */
|
|
16
16
|
sub: string;
|
|
@@ -18,11 +18,25 @@ export interface AccessTokenClaims {
|
|
|
18
18
|
aud: string;
|
|
19
19
|
iss: string;
|
|
20
20
|
scope: string;
|
|
21
|
-
/**
|
|
22
|
-
|
|
21
|
+
/** every tenant this token may act in */
|
|
22
|
+
tenants: Tenant[];
|
|
23
|
+
/** the one it acts in when a call names none */
|
|
24
|
+
defaultTenant: Tenant;
|
|
25
|
+
/**
|
|
26
|
+
* What each tenant is called, for a client that has to offer the choice.
|
|
27
|
+
*
|
|
28
|
+
* Carried on the token because the only place these names are known is the
|
|
29
|
+
* consent screen that rendered them, and the MCP server — which has to name
|
|
30
|
+
* the choice to a model — cannot reach group-service. A snapshot: a group
|
|
31
|
+
* renamed after the connection was made shows its old name until reconnect,
|
|
32
|
+
* which is the same trade the owner's name on an API key already makes.
|
|
33
|
+
*/
|
|
34
|
+
tenantNames: Record<Tenant, string>;
|
|
35
|
+
/** the single tenant an older token was pinned to; read by `readTenants` */
|
|
36
|
+
groupId?: string | null;
|
|
23
37
|
email: string;
|
|
24
38
|
name: string;
|
|
25
|
-
typ: typeof
|
|
39
|
+
typ: typeof ACCESS_TOKEN_TYPE;
|
|
26
40
|
jti: string;
|
|
27
41
|
exp: number;
|
|
28
42
|
iat: number;
|
|
@@ -35,7 +49,9 @@ export interface MintAccessTokenInput {
|
|
|
35
49
|
resource: string;
|
|
36
50
|
issuer: string;
|
|
37
51
|
scopes: ApiKeyScope[];
|
|
38
|
-
|
|
52
|
+
tenants: Tenant[];
|
|
53
|
+
defaultTenant: Tenant;
|
|
54
|
+
tenantNames: Record<Tenant, string>;
|
|
39
55
|
}
|
|
40
56
|
export interface MintedAccessToken {
|
|
41
57
|
accessToken: string;
|
|
@@ -50,7 +66,8 @@ export interface AccessTokenVerification {
|
|
|
50
66
|
email?: string;
|
|
51
67
|
name?: string;
|
|
52
68
|
scopes?: ApiKeyScope[];
|
|
53
|
-
|
|
69
|
+
tenants?: ApiKeyTenant;
|
|
70
|
+
tenantNames?: Record<Tenant, string>;
|
|
54
71
|
}
|
|
55
72
|
/**
|
|
56
73
|
* Check a bearer token presented to the MCP server.
|
|
@@ -63,7 +80,16 @@ export interface AccessTokenVerification {
|
|
|
63
80
|
* pin — cannot be presented as an access token and quietly get everything.
|
|
64
81
|
*/
|
|
65
82
|
export declare const verifyAccessToken: (token: string, expectedAudience: string) => AccessTokenVerification;
|
|
83
|
+
/**
|
|
84
|
+
* Tell an OAuth access token apart from an ordinary session JWT.
|
|
85
|
+
*
|
|
86
|
+
* They are signed with the same secret and arrive in the same header, so
|
|
87
|
+
* anything holding one has to ask which it got. Getting this wrong is not a
|
|
88
|
+
* subtle failure: read as a session, an access token has no `id` and no
|
|
89
|
+
* `groups`, so `req.user.id` lands as `undefined` and every scoped query goes
|
|
90
|
+
* out unbounded.
|
|
91
|
+
*/
|
|
92
|
+
export declare const isAccessTokenClaims: (claims: unknown) => claims is AccessTokenClaims;
|
|
66
93
|
/** Parse a space-separated `scope` parameter, dropping anything we do not define. */
|
|
67
94
|
export declare const parseScopes: (scope: unknown) => ApiKeyScope[];
|
|
68
|
-
export {};
|
|
69
95
|
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/oauth/tokens.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/oauth/tokens.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,MAAM,EACZ,MAAM,kBAAkB,CAAC;AAE1B;;;;;;;;;GASG;AAEH,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,eAAe,CAAC;AAK9C,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gDAAgD;IAChD,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,iBAAiB,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,eAAe,GAAI,OAAO,oBAAoB,KAAG,iBAsB7D,CAAC;AAEF,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,gBAAgB,GAAG,YAAY,GAAG,eAAe,CAAC;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,MAAM,EACb,kBAAkB,MAAM,KACvB,uBAsBF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,OAAO,KAAG,MAAM,IAAI,iBAGP,CAAC;AAE1D,qFAAqF;AACrF,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,KAAG,WAAW,EACmB,CAAC"}
|
package/dist/oauth/tokens.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.parseScopes = exports.verifyAccessToken = exports.mintAccessToken = void 0;
|
|
6
|
+
exports.parseScopes = exports.isAccessTokenClaims = exports.verifyAccessToken = exports.mintAccessToken = exports.ACCESS_TOKEN_TYPE = void 0;
|
|
7
7
|
const crypto_1 = require("crypto");
|
|
8
8
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
9
9
|
const env_1 = require("../config/env");
|
|
@@ -19,7 +19,7 @@ const types_1 = require("../apiKeys/types");
|
|
|
19
19
|
* token, which is the thing that actually persists.
|
|
20
20
|
*/
|
|
21
21
|
/** Marks a token as issued by the OAuth flow, for the MCP resource specifically. */
|
|
22
|
-
|
|
22
|
+
exports.ACCESS_TOKEN_TYPE = 'mcp_access';
|
|
23
23
|
/** Short enough that a leaked token is a small window, long enough to be usable. */
|
|
24
24
|
const ACCESS_TOKEN_TTL_SECONDS = 60 * 60;
|
|
25
25
|
const mintAccessToken = (input) => {
|
|
@@ -29,10 +29,12 @@ const mintAccessToken = (input) => {
|
|
|
29
29
|
aud: input.resource,
|
|
30
30
|
iss: input.issuer,
|
|
31
31
|
scope,
|
|
32
|
-
|
|
32
|
+
tenants: input.tenants,
|
|
33
|
+
defaultTenant: input.defaultTenant,
|
|
34
|
+
tenantNames: input.tenantNames,
|
|
33
35
|
email: input.email,
|
|
34
36
|
name: input.name,
|
|
35
|
-
typ:
|
|
37
|
+
typ: exports.ACCESS_TOKEN_TYPE,
|
|
36
38
|
jti: (0, crypto_1.randomUUID)()
|
|
37
39
|
}, (0, env_1.requireEnv)('JWT_SECRET'), { expiresIn: ACCESS_TOKEN_TTL_SECONDS });
|
|
38
40
|
return { accessToken, expiresIn: ACCESS_TOKEN_TTL_SECONDS, scope };
|
|
@@ -57,7 +59,7 @@ const verifyAccessToken = (token, expectedAudience) => {
|
|
|
57
59
|
const expired = error?.name === 'TokenExpiredError';
|
|
58
60
|
return { ok: false, rejection: expired ? 'expired' : 'bad-signature' };
|
|
59
61
|
}
|
|
60
|
-
if (
|
|
62
|
+
if (!(0, exports.isAccessTokenClaims)(claims))
|
|
61
63
|
return { ok: false, rejection: 'wrong-type' };
|
|
62
64
|
if (claims.aud !== expectedAudience)
|
|
63
65
|
return { ok: false, rejection: 'wrong-audience' };
|
|
@@ -69,10 +71,24 @@ const verifyAccessToken = (token, expectedAudience) => {
|
|
|
69
71
|
email: claims.email ?? '',
|
|
70
72
|
name: claims.name ?? '',
|
|
71
73
|
scopes: (claims.scope ?? '').split(' ').filter(types_1.isApiKeyScope),
|
|
72
|
-
|
|
74
|
+
tenants: (0, types_1.readTenants)(claims),
|
|
75
|
+
tenantNames: claims.tenantNames ?? {}
|
|
73
76
|
};
|
|
74
77
|
};
|
|
75
78
|
exports.verifyAccessToken = verifyAccessToken;
|
|
79
|
+
/**
|
|
80
|
+
* Tell an OAuth access token apart from an ordinary session JWT.
|
|
81
|
+
*
|
|
82
|
+
* They are signed with the same secret and arrive in the same header, so
|
|
83
|
+
* anything holding one has to ask which it got. Getting this wrong is not a
|
|
84
|
+
* subtle failure: read as a session, an access token has no `id` and no
|
|
85
|
+
* `groups`, so `req.user.id` lands as `undefined` and every scoped query goes
|
|
86
|
+
* out unbounded.
|
|
87
|
+
*/
|
|
88
|
+
const isAccessTokenClaims = (claims) => typeof claims === 'object' &&
|
|
89
|
+
claims !== null &&
|
|
90
|
+
claims.typ === exports.ACCESS_TOKEN_TYPE;
|
|
91
|
+
exports.isAccessTokenClaims = isAccessTokenClaims;
|
|
76
92
|
/** Parse a space-separated `scope` parameter, dropping anything we do not define. */
|
|
77
93
|
const parseScopes = (scope) => typeof scope === 'string' ? scope.split(/\s+/).filter(types_1.isApiKeyScope) : [];
|
|
78
94
|
exports.parseScopes = parseScopes;
|
package/dist/oauth/tokens.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/oauth/tokens.ts"],"names":[],"mappings":";;;;;;AAAA,mCAAoC;AACpC,gEAA+B;AAC/B,uCAA2C;AAC3C,
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/oauth/tokens.ts"],"names":[],"mappings":"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"}
|