@tumbaland/backend-core 1.32.0 → 1.34.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/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export type { PaymentRequiredDetails } from './errors/HttpError';
13
13
  export * from './entitlements';
14
14
  export * from './groups';
15
15
  export * from './apiKeys';
16
+ export * from './oauth';
16
17
  export { authenticateToken, optionalAuth } from './middleware/authMiddleware';
17
18
  export { requireInternalServiceToken, internalServiceTokenBypass, allowUserOrInternalService, verifyInternalToken, INTERNAL_TOKEN_HEADER, SERVICE_ID_HEADER } from './middleware/internalServiceAuth';
18
19
  export { createCorsMiddleware } from './middleware/corsMiddleware';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAG9D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC7K,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGjE,cAAc,gBAAgB,CAAC;AAG/B,cAAc,UAAU,CAAC;AAGzB,cAAc,WAAW,CAAC;AAG1B,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC9E,OAAO,EACL,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC1G,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACnH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7E,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG9E,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,QAAQ,EACT,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,UAAU,EACV,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,UAAU,EACV,aAAa,EACb,kBAAkB,EACnB,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAG9D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAGpE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC7K,YAAY,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGjE,cAAc,gBAAgB,CAAC;AAG/B,cAAc,UAAU,CAAC;AAGzB,cAAc,WAAW,CAAC;AAG1B,cAAc,SAAS,CAAC;AAGxB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC9E,OAAO,EACL,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAC1G,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACnH,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7E,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG9E,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,QAAQ,EACT,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,UAAU,EACV,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,UAAU,EACV,aAAa,EACb,kBAAkB,EACnB,MAAM,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -58,6 +58,8 @@ __exportStar(require("./entitlements"), exports);
58
58
  __exportStar(require("./groups"), exports);
59
59
  // API keys (non-browser clients: MCP servers, scripts, agents)
60
60
  __exportStar(require("./apiKeys"), exports);
61
+ // OAuth 2.1 authorization server, for assistants connecting over MCP
62
+ __exportStar(require("./oauth"), exports);
61
63
  // Middleware
62
64
  var authMiddleware_1 = require("./middleware/authMiddleware");
63
65
  Object.defineProperty(exports, "authenticateToken", { enumerable: true, get: function () { return authMiddleware_1.authenticateToken; } });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,qFAAqF;;;;;;;;;;;;;;;;;;;;;AAErF,gBAAgB;AAChB,qDAAoD;AAA3C,8GAAA,aAAa,OAAA;AAEtB,2CAAkD;AAAzC,4GAAA,gBAAgB,OAAA;AAGzB,UAAU;AACV,2CAAqD;AAA5C,iHAAA,OAAO,OAAU;AAE1B,gBAAgB;AAChB,8DAAoF;AAA3E,+GAAA,WAAW,OAAA;AAAE,8GAAA,UAAU,OAAA;AAAE,kHAAA,cAAc,OAAA;AAChD,gEAA+D;AAAtD,sHAAA,iBAAiB,OAAA;AAG1B,WAAW;AACX,oDAAgE;AAAvD,uGAAA,SAAS,OAAA;AAAE,0GAAA,YAAY,OAAA;AAEhC,SAAS;AACT,oCAA0C;AAAjC,iGAAA,UAAU,OAAA;AAEnB,SAAS;AACT,gDAA6K;AAApK,sGAAA,SAAS,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,iHAAA,oBAAoB,OAAA;AAAE,iHAAA,oBAAoB,OAAA;AAGhJ,wDAAwD;AACxD,iDAA+B;AAE/B,0DAA0D;AAC1D,2CAAyB;AAEzB,+DAA+D;AAC/D,4CAA0B;AAE1B,aAAa;AACb,8DAA8E;AAArE,mHAAA,iBAAiB,OAAA;AAAE,8GAAA,YAAY,OAAA;AACxC,wEAO0C;AANxC,kIAAA,2BAA2B,OAAA;AAC3B,iIAAA,0BAA0B,OAAA;AAC1B,iIAAA,0BAA0B,OAAA;AAC1B,0HAAA,mBAAmB,OAAA;AACnB,4HAAA,qBAAqB,OAAA;AACrB,wHAAA,iBAAiB,OAAA;AAEnB,8DAAmE;AAA1D,sHAAA,oBAAoB,OAAA;AAC7B,0DAAyD;AAAhD,4GAAA,YAAY,OAAA;AACrB,4DAA0G;AAAjG,8GAAA,aAAa,OAAA;AAAE,yHAAA,wBAAwB,OAAA;AAAE,oHAAA,mBAAmB,OAAA;AACrE,kDAAmH;AAA1G,2GAAA,eAAe,OAAA;AAAE,6GAAA,iBAAiB,OAAA;AAAE,+GAAA,mBAAmB,OAAA;AAAE,6GAAA,iBAAiB,OAAA;AACnF,kDAAiD;AAAxC,oGAAA,QAAQ,OAAA;AAKjB,QAAQ;AACR,mDAAmF;AAA1E,oHAAA,qBAAqB,OAAA;AAAE,oHAAA,qBAAqB,OAAA;AACrD,6CAA6E;AAApE,6GAAA,iBAAiB,OAAA;AAAE,uGAAA,WAAW,OAAA;AAAE,qGAAA,SAAS,OAAA;AAElD,2DAA8E;AAArE,mHAAA,gBAAgB,OAAA;AAAE,oHAAA,iBAAiB,OAAA;AAE5C,UAAU;AACV,qCAQmB;AAPjB,4GAAA,iBAAiB,OAAA;AACjB,8GAAA,mBAAmB,OAAA;AACnB,4GAAA,iBAAiB,OAAA;AACjB,gHAAA,qBAAqB,OAAA;AACrB,+GAAA,oBAAoB,OAAA;AACpB,0GAAA,eAAe,OAAA;AACf,mGAAA,QAAQ,OAAA;AAGV,UAAU;AACV,qCAUmB;AATjB,qGAAA,UAAU,OAAA;AACV,oGAAA,SAAS,OAAA;AACT,oGAAA,SAAS,OAAA;AACT,4GAAA,iBAAiB,OAAA;AACjB,0GAAA,eAAe,OAAA;AACf,oGAAA,SAAS,OAAA;AACT,qGAAA,UAAU,OAAA;AACV,wGAAA,aAAa,OAAA;AACb,6GAAA,kBAAkB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,qFAAqF;;;;;;;;;;;;;;;;;;;;;AAErF,gBAAgB;AAChB,qDAAoD;AAA3C,8GAAA,aAAa,OAAA;AAEtB,2CAAkD;AAAzC,4GAAA,gBAAgB,OAAA;AAGzB,UAAU;AACV,2CAAqD;AAA5C,iHAAA,OAAO,OAAU;AAE1B,gBAAgB;AAChB,8DAAoF;AAA3E,+GAAA,WAAW,OAAA;AAAE,8GAAA,UAAU,OAAA;AAAE,kHAAA,cAAc,OAAA;AAChD,gEAA+D;AAAtD,sHAAA,iBAAiB,OAAA;AAG1B,WAAW;AACX,oDAAgE;AAAvD,uGAAA,SAAS,OAAA;AAAE,0GAAA,YAAY,OAAA;AAEhC,SAAS;AACT,oCAA0C;AAAjC,iGAAA,UAAU,OAAA;AAEnB,SAAS;AACT,gDAA6K;AAApK,sGAAA,SAAS,OAAA;AAAE,4GAAA,eAAe,OAAA;AAAE,8GAAA,iBAAiB,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,iHAAA,oBAAoB,OAAA;AAAE,iHAAA,oBAAoB,OAAA;AAGhJ,wDAAwD;AACxD,iDAA+B;AAE/B,0DAA0D;AAC1D,2CAAyB;AAEzB,+DAA+D;AAC/D,4CAA0B;AAE1B,qEAAqE;AACrE,0CAAwB;AAExB,aAAa;AACb,8DAA8E;AAArE,mHAAA,iBAAiB,OAAA;AAAE,8GAAA,YAAY,OAAA;AACxC,wEAO0C;AANxC,kIAAA,2BAA2B,OAAA;AAC3B,iIAAA,0BAA0B,OAAA;AAC1B,iIAAA,0BAA0B,OAAA;AAC1B,0HAAA,mBAAmB,OAAA;AACnB,4HAAA,qBAAqB,OAAA;AACrB,wHAAA,iBAAiB,OAAA;AAEnB,8DAAmE;AAA1D,sHAAA,oBAAoB,OAAA;AAC7B,0DAAyD;AAAhD,4GAAA,YAAY,OAAA;AACrB,4DAA0G;AAAjG,8GAAA,aAAa,OAAA;AAAE,yHAAA,wBAAwB,OAAA;AAAE,oHAAA,mBAAmB,OAAA;AACrE,kDAAmH;AAA1G,2GAAA,eAAe,OAAA;AAAE,6GAAA,iBAAiB,OAAA;AAAE,+GAAA,mBAAmB,OAAA;AAAE,6GAAA,iBAAiB,OAAA;AACnF,kDAAiD;AAAxC,oGAAA,QAAQ,OAAA;AAKjB,QAAQ;AACR,mDAAmF;AAA1E,oHAAA,qBAAqB,OAAA;AAAE,oHAAA,qBAAqB,OAAA;AACrD,6CAA6E;AAApE,6GAAA,iBAAiB,OAAA;AAAE,uGAAA,WAAW,OAAA;AAAE,qGAAA,SAAS,OAAA;AAElD,2DAA8E;AAArE,mHAAA,gBAAgB,OAAA;AAAE,oHAAA,iBAAiB,OAAA;AAE5C,UAAU;AACV,qCAQmB;AAPjB,4GAAA,iBAAiB,OAAA;AACjB,8GAAA,mBAAmB,OAAA;AACnB,4GAAA,iBAAiB,OAAA;AACjB,gHAAA,qBAAqB,OAAA;AACrB,+GAAA,oBAAoB,OAAA;AACpB,0GAAA,eAAe,OAAA;AACf,mGAAA,QAAQ,OAAA;AAGV,UAAU;AACV,qCAUmB;AATjB,qGAAA,UAAU,OAAA;AACV,oGAAA,SAAS,OAAA;AACT,oGAAA,SAAS,OAAA;AACT,4GAAA,iBAAiB,OAAA;AACjB,0GAAA,eAAe,OAAA;AACf,oGAAA,SAAS,OAAA;AACT,qGAAA,UAAU,OAAA;AACV,wGAAA,aAAa,OAAA;AACb,6GAAA,kBAAkB,OAAA"}
@@ -0,0 +1,7 @@
1
+ export { OAuthClient, AuthorizationCode, RefreshToken } from './models';
2
+ export type { IOAuthClient, IAuthorizationCode, IRefreshToken } from './models';
3
+ export { registerClient, findClient, isRegisteredRedirect, issueAuthorizationCode, redeemAuthorizationCode, issueRefreshToken, redeemRefreshToken, revokeRefreshTokensForUser, listConnections } from './service';
4
+ export type { RegisterClientInput, RegisteredClient, IssueCodeInput, CodeRedemption, CodeRejection, RefreshRedemption } from './service';
5
+ export { mintAccessToken, verifyAccessToken, parseScopes } from './tokens';
6
+ export type { AccessTokenClaims, MintAccessTokenInput, MintedAccessToken, AccessTokenVerification } from './tokens';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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,EAAE,eAAe,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC3E,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,22 @@
1
+ "use strict";
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;
4
+ var models_1 = require("./models");
5
+ Object.defineProperty(exports, "OAuthClient", { enumerable: true, get: function () { return models_1.OAuthClient; } });
6
+ Object.defineProperty(exports, "AuthorizationCode", { enumerable: true, get: function () { return models_1.AuthorizationCode; } });
7
+ Object.defineProperty(exports, "RefreshToken", { enumerable: true, get: function () { return models_1.RefreshToken; } });
8
+ var service_1 = require("./service");
9
+ Object.defineProperty(exports, "registerClient", { enumerable: true, get: function () { return service_1.registerClient; } });
10
+ Object.defineProperty(exports, "findClient", { enumerable: true, get: function () { return service_1.findClient; } });
11
+ Object.defineProperty(exports, "isRegisteredRedirect", { enumerable: true, get: function () { return service_1.isRegisteredRedirect; } });
12
+ Object.defineProperty(exports, "issueAuthorizationCode", { enumerable: true, get: function () { return service_1.issueAuthorizationCode; } });
13
+ Object.defineProperty(exports, "redeemAuthorizationCode", { enumerable: true, get: function () { return service_1.redeemAuthorizationCode; } });
14
+ Object.defineProperty(exports, "issueRefreshToken", { enumerable: true, get: function () { return service_1.issueRefreshToken; } });
15
+ Object.defineProperty(exports, "redeemRefreshToken", { enumerable: true, get: function () { return service_1.redeemRefreshToken; } });
16
+ Object.defineProperty(exports, "revokeRefreshTokensForUser", { enumerable: true, get: function () { return service_1.revokeRefreshTokensForUser; } });
17
+ Object.defineProperty(exports, "listConnections", { enumerable: true, get: function () { return service_1.listConnections; } });
18
+ var tokens_1 = require("./tokens");
19
+ Object.defineProperty(exports, "mintAccessToken", { enumerable: true, get: function () { return tokens_1.mintAccessToken; } });
20
+ Object.defineProperty(exports, "verifyAccessToken", { enumerable: true, get: function () { return tokens_1.verifyAccessToken; } });
21
+ Object.defineProperty(exports, "parseScopes", { enumerable: true, get: function () { return tokens_1.parseScopes; } });
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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,mCAA2E;AAAlE,yGAAA,eAAe,OAAA;AAAE,2GAAA,iBAAiB,OAAA;AAAE,qGAAA,WAAW,OAAA"}
@@ -0,0 +1,93 @@
1
+ import mongoose, { Document } from 'mongoose';
2
+ /**
3
+ * A client registered through RFC 7591 Dynamic Client Registration.
4
+ *
5
+ * Assistants register themselves — nobody is going to pre-provision Claude,
6
+ * ChatGPT and Gemini by hand, and the MCP spec expects a server to accept
7
+ * registrations. Clients are public (no secret): the caller is a browser-driven
8
+ * flow that cannot keep one, which is exactly why PKCE is mandatory here.
9
+ */
10
+ export interface IOAuthClient extends Document {
11
+ clientId: string;
12
+ clientName: string;
13
+ redirectUris: string[];
14
+ createdAt: Date;
15
+ updatedAt: Date;
16
+ }
17
+ export declare const OAuthClient: mongoose.Model<IOAuthClient, {}, {}, {}, mongoose.Document<unknown, {}, IOAuthClient, {}, mongoose.DefaultSchemaOptions> & IOAuthClient & Required<{
18
+ _id: mongoose.Types.ObjectId;
19
+ }> & {
20
+ __v: number;
21
+ } & {
22
+ id: string;
23
+ }, any, IOAuthClient>;
24
+ /**
25
+ * A one-time authorization code, alive for the seconds between the user
26
+ * approving and the client exchanging it.
27
+ *
28
+ * Everything the token will assert is fixed here, at the moment consent is
29
+ * given: which scopes, which tenant, which resource. The exchange cannot widen
30
+ * any of it, so a client that asks for more at the token endpoint than the user
31
+ * agreed to gets what the user agreed to.
32
+ */
33
+ export interface IAuthorizationCode extends Document {
34
+ code: string;
35
+ clientId: string;
36
+ userId: string;
37
+ userEmail: string;
38
+ userName: string;
39
+ redirectUri: string;
40
+ scopes: string[];
41
+ groupId: string | null;
42
+ /** RFC 8707: the MCP server this will be minted for */
43
+ resource: string;
44
+ /** PKCE, always S256 — the spec does not allow `plain` */
45
+ codeChallenge: string;
46
+ /** set once the code is exchanged, so a replay is detectable rather than silent */
47
+ usedAt?: Date;
48
+ expiresAt: Date;
49
+ createdAt: Date;
50
+ }
51
+ export declare const AuthorizationCode: mongoose.Model<IAuthorizationCode, {}, {}, {}, mongoose.Document<unknown, {}, IAuthorizationCode, {}, mongoose.DefaultSchemaOptions> & IAuthorizationCode & Required<{
52
+ _id: mongoose.Types.ObjectId;
53
+ }> & {
54
+ __v: number;
55
+ } & {
56
+ id: string;
57
+ }, any, IAuthorizationCode>;
58
+ /**
59
+ * A refresh token: the part that actually persists, and therefore the part
60
+ * revocation acts on.
61
+ *
62
+ * Access tokens are unrevokable JWTs by design, kept short so that matters
63
+ * little. Cutting off an assistant means deleting its refresh token, after
64
+ * which it can obtain nothing new.
65
+ */
66
+ export interface IRefreshToken extends Document {
67
+ tokenHash: string;
68
+ clientId: string;
69
+ userId: string;
70
+ scopes: string[];
71
+ groupId: string | null;
72
+ resource: string;
73
+ /**
74
+ * When the user actually connected this assistant.
75
+ *
76
+ * Distinct from `createdAt`, which rotation resets on every refresh — showing
77
+ * that in the UI would tell someone they connected Claude an hour ago when
78
+ * they did it in March.
79
+ */
80
+ grantedAt: Date;
81
+ revokedAt?: Date;
82
+ lastUsedAt?: Date;
83
+ createdAt: Date;
84
+ updatedAt: Date;
85
+ }
86
+ export declare const RefreshToken: mongoose.Model<IRefreshToken, {}, {}, {}, mongoose.Document<unknown, {}, IRefreshToken, {}, mongoose.DefaultSchemaOptions> & IRefreshToken & Required<{
87
+ _id: mongoose.Types.ObjectId;
88
+ }> & {
89
+ __v: number;
90
+ } & {
91
+ id: string;
92
+ }, any, IRefreshToken>;
93
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +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;AAEtD;;;;;;;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,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,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;AAwBD,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,GAAG,IAAI,CAAC;IACvB,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;AAmBD,eAAO,MAAM,YAAY;;;;;;sBAE4C,CAAC"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.RefreshToken = exports.AuthorizationCode = exports.OAuthClient = void 0;
37
+ const mongoose_1 = __importStar(require("mongoose"));
38
+ const OAuthClientSchema = new mongoose_1.Schema({
39
+ clientId: { type: String, required: true, unique: true, index: true },
40
+ clientName: { type: String, required: true, maxlength: 200 },
41
+ redirectUris: { type: [String], required: true }
42
+ }, { timestamps: true, collection: 'oauth_clients' });
43
+ exports.OAuthClient = mongoose_1.default.models.OAuthClient
44
+ ? mongoose_1.default.models.OAuthClient
45
+ : mongoose_1.default.model('OAuthClient', OAuthClientSchema);
46
+ const AuthorizationCodeSchema = new mongoose_1.Schema({
47
+ code: { type: String, required: true, unique: true, index: true },
48
+ clientId: { type: String, required: true },
49
+ userId: { type: String, required: true },
50
+ userEmail: { type: String, required: true },
51
+ userName: { type: String, default: '' },
52
+ redirectUri: { type: String, required: true },
53
+ scopes: { type: [String], default: [] },
54
+ groupId: { type: String, default: null },
55
+ resource: { type: String, required: true },
56
+ codeChallenge: { type: String, required: true },
57
+ usedAt: { type: Date },
58
+ expiresAt: { type: Date, required: true }
59
+ }, { timestamps: { createdAt: true, updatedAt: false }, collection: 'oauth_authorization_codes' });
60
+ // Codes are short-lived and never read after expiry; let Mongo sweep them so a
61
+ // replay cannot be attempted against a record nobody is cleaning up.
62
+ AuthorizationCodeSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });
63
+ exports.AuthorizationCode = mongoose_1.default.models.AuthorizationCode
64
+ ? mongoose_1.default.models.AuthorizationCode
65
+ : mongoose_1.default.model('AuthorizationCode', AuthorizationCodeSchema);
66
+ const RefreshTokenSchema = new mongoose_1.Schema({
67
+ tokenHash: { type: String, required: true, unique: true, index: true },
68
+ clientId: { type: String, required: true },
69
+ userId: { type: String, required: true, index: true },
70
+ scopes: { type: [String], default: [] },
71
+ groupId: { type: String, default: null },
72
+ resource: { type: String, required: true },
73
+ grantedAt: { type: Date, default: Date.now },
74
+ revokedAt: { type: Date },
75
+ lastUsedAt: { type: Date }
76
+ }, { timestamps: true, collection: 'oauth_refresh_tokens' });
77
+ RefreshTokenSchema.index({ userId: 1, createdAt: -1 });
78
+ exports.RefreshToken = mongoose_1.default.models.RefreshToken
79
+ ? mongoose_1.default.models.RefreshToken
80
+ : mongoose_1.default.model('RefreshToken', RefreshTokenSchema);
81
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/oauth/models.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,qDAAsD;AAkBtD,MAAM,iBAAiB,GAAG,IAAI,iBAAM,CAClC;IACE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IACrE,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE;IAC5D,YAAY,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;CACjD,EACD,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,eAAe,EAAE,CAClD,CAAC;AAEW,QAAA,WAAW,GAAG,kBAAQ,CAAC,MAAM,CAAC,WAAW;IACpD,CAAC,CAAE,kBAAQ,CAAC,MAAM,CAAC,WAA4C;IAC/D,CAAC,CAAC,kBAAQ,CAAC,KAAK,CAAe,aAAa,EAAE,iBAAiB,CAAC,CAAC;AA8BnE,MAAM,uBAAuB,GAAG,IAAI,iBAAM,CACxC;IACE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IACjE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC1C,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IACxC,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC3C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;IACvC,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC7C,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;IACvC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;IACxC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC1C,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC/C,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;IACtB,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;CAC1C,EACD,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,2BAA2B,EAAE,CAC/F,CAAC;AAEF,+EAA+E;AAC/E,qEAAqE;AACrE,uBAAuB,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,kBAAkB,EAAE,CAAC,EAAE,CAAC,CAAC;AAE9D,QAAA,iBAAiB,GAAG,kBAAQ,CAAC,MAAM,CAAC,iBAAiB;IAChE,CAAC,CAAE,kBAAQ,CAAC,MAAM,CAAC,iBAAwD;IAC3E,CAAC,CAAC,kBAAQ,CAAC,KAAK,CAAqB,mBAAmB,EAAE,uBAAuB,CAAC,CAAC;AA+BrF,MAAM,kBAAkB,GAAG,IAAI,iBAAM,CACnC;IACE,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IACtE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC1C,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IACrD,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;IACvC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;IACxC,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC1C,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE;IAC5C,SAAS,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;IACzB,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE;CAC3B,EACD,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,sBAAsB,EAAE,CACzD,CAAC;AAEF,kBAAkB,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;AAE1C,QAAA,YAAY,GAAG,kBAAQ,CAAC,MAAM,CAAC,YAAY;IACtD,CAAC,CAAE,kBAAQ,CAAC,MAAM,CAAC,YAA8C;IACjE,CAAC,CAAC,kBAAQ,CAAC,KAAK,CAAgB,cAAc,EAAE,kBAAkB,CAAC,CAAC"}
@@ -0,0 +1,111 @@
1
+ import { IAuthorizationCode } from './models';
2
+ import type { ApiKeyScope } from '../apiKeys/types';
3
+ export interface RegisterClientInput {
4
+ clientName: string;
5
+ redirectUris: string[];
6
+ }
7
+ export interface RegisteredClient {
8
+ clientId: string;
9
+ clientName: string;
10
+ redirectUris: string[];
11
+ }
12
+ export declare const registerClient: (input: RegisterClientInput) => Promise<RegisteredClient>;
13
+ export declare const findClient: (clientId: string) => import("mongoose").Query<(import("mongoose").Document<unknown, {}, import("./models").IOAuthClient, {}, import("mongoose").DefaultSchemaOptions> & import("./models").IOAuthClient & Required<{
14
+ _id: import("mongoose").Types.ObjectId;
15
+ }> & {
16
+ __v: number;
17
+ } & {
18
+ id: string;
19
+ }) | null, import("mongoose").Document<unknown, {}, import("./models").IOAuthClient, {}, import("mongoose").DefaultSchemaOptions> & import("./models").IOAuthClient & Required<{
20
+ _id: import("mongoose").Types.ObjectId;
21
+ }> & {
22
+ __v: number;
23
+ } & {
24
+ id: string;
25
+ }, {}, import("./models").IOAuthClient, "findOne", {}>;
26
+ /**
27
+ * Whether a client may be sent back to this URI.
28
+ *
29
+ * Exact string match, deliberately. Prefix or wildcard matching on redirect URIs
30
+ * is the classic way an authorization code ends up delivered to somewhere the
31
+ * client never controlled.
32
+ */
33
+ export declare const isRegisteredRedirect: (client: {
34
+ redirectUris: string[];
35
+ }, uri: string) => boolean;
36
+ export interface IssueCodeInput {
37
+ clientId: string;
38
+ userId: string;
39
+ userEmail: string;
40
+ userName: string;
41
+ redirectUri: string;
42
+ scopes: ApiKeyScope[];
43
+ groupId: string | null;
44
+ resource: string;
45
+ codeChallenge: string;
46
+ }
47
+ export declare const issueAuthorizationCode: (input: IssueCodeInput) => Promise<string>;
48
+ export type CodeRejection = 'unknown' | 'expired' | 'already-used' | 'client-mismatch' | 'redirect-mismatch' | 'pkce-failed';
49
+ export interface CodeRedemption {
50
+ ok: boolean;
51
+ rejection?: CodeRejection;
52
+ code?: IAuthorizationCode;
53
+ }
54
+ /**
55
+ * Exchange a code, once.
56
+ *
57
+ * The `usedAt` stamp is set by the same atomic update that fetches the code, so
58
+ * two simultaneous exchanges cannot both succeed — a replayed code loses the
59
+ * race rather than being caught by a check that ran a moment earlier.
60
+ */
61
+ export declare const redeemAuthorizationCode: (code: string, clientId: string, redirectUri: string, codeVerifier: string) => Promise<CodeRedemption>;
62
+ export interface IssuedRefreshToken {
63
+ token: string;
64
+ }
65
+ export declare const issueRefreshToken: (input: {
66
+ clientId: string;
67
+ userId: string;
68
+ scopes: ApiKeyScope[];
69
+ groupId: string | null;
70
+ resource: string;
71
+ }) => Promise<IssuedRefreshToken>;
72
+ export interface RefreshRedemption {
73
+ ok: boolean;
74
+ /** true when a retired token was presented again — treated as a compromise */
75
+ reused?: boolean;
76
+ userId?: string;
77
+ scopes?: ApiKeyScope[];
78
+ groupId?: string | null;
79
+ resource?: string;
80
+ /** the replacement the client must store; the presented one is now dead */
81
+ rotatedToken?: string;
82
+ }
83
+ /**
84
+ * Exchange a refresh token for a new one, rotating as we go.
85
+ *
86
+ * Rotation matters because these are the long-lived half: an access token is
87
+ * gone within the hour, but a refresh token that never changes is a permanent
88
+ * credential for whoever obtains a copy. Each use retires the old token and
89
+ * issues a fresh one, so a stolen copy stops working as soon as the legitimate
90
+ * client refreshes.
91
+ *
92
+ * Reuse of an already-rotated token is treated as theft rather than as an
93
+ * ordinary failure: the honest client and the thief now both hold tokens
94
+ * descended from the same grant, and there is no way to tell which just called.
95
+ * So the whole chain is revoked and the user reconnects — noisy, but the
96
+ * alternative is leaving an attacker with working access.
97
+ */
98
+ export declare const redeemRefreshToken: (token: string, clientId: string) => Promise<RefreshRedemption>;
99
+ /** Cut off an assistant: without a refresh token it can obtain nothing new. */
100
+ export declare const revokeRefreshTokensForUser: (userId: string, clientId?: string) => Promise<number>;
101
+ export declare const listConnections: (userId: string) => Promise<{
102
+ id: string;
103
+ clientId: string;
104
+ clientName: string;
105
+ scopes: string[];
106
+ groupId: string | null;
107
+ createdAt: string;
108
+ lastUsedAt: string | null;
109
+ revokedAt: string | null;
110
+ }[]>;
111
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/oauth/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listConnections = exports.revokeRefreshTokensForUser = exports.redeemRefreshToken = exports.issueRefreshToken = exports.redeemAuthorizationCode = exports.issueAuthorizationCode = exports.isRegisteredRedirect = exports.findClient = exports.registerClient = void 0;
4
+ const crypto_1 = require("crypto");
5
+ const models_1 = require("./models");
6
+ /** How long a user has between approving and the client exchanging the code. */
7
+ const CODE_TTL_MS = 60 * 1000;
8
+ const sha256 = (value) => (0, crypto_1.createHash)('sha256').update(value).digest('hex');
9
+ /** base64url of the SHA-256 digest, which is what PKCE `S256` specifies. */
10
+ const s256 = (verifier) => (0, crypto_1.createHash)('sha256').update(verifier).digest('base64url');
11
+ const constantTimeEquals = (a, b) => {
12
+ const left = Buffer.from(a);
13
+ const right = Buffer.from(b);
14
+ if (left.length !== right.length)
15
+ return false;
16
+ return (0, crypto_1.timingSafeEqual)(left, right);
17
+ };
18
+ const registerClient = async (input) => {
19
+ const client = await models_1.OAuthClient.create({
20
+ clientId: `tmb-client-${(0, crypto_1.randomBytes)(16).toString('hex')}`,
21
+ clientName: input.clientName.slice(0, 200),
22
+ redirectUris: input.redirectUris
23
+ });
24
+ return {
25
+ clientId: client.clientId,
26
+ clientName: client.clientName,
27
+ redirectUris: client.redirectUris
28
+ };
29
+ };
30
+ exports.registerClient = registerClient;
31
+ const findClient = (clientId) => models_1.OAuthClient.findOne({ clientId });
32
+ exports.findClient = findClient;
33
+ /**
34
+ * Whether a client may be sent back to this URI.
35
+ *
36
+ * Exact string match, deliberately. Prefix or wildcard matching on redirect URIs
37
+ * is the classic way an authorization code ends up delivered to somewhere the
38
+ * client never controlled.
39
+ */
40
+ const isRegisteredRedirect = (client, uri) => client.redirectUris.includes(uri);
41
+ exports.isRegisteredRedirect = isRegisteredRedirect;
42
+ const issueAuthorizationCode = async (input) => {
43
+ const code = (0, crypto_1.randomBytes)(32).toString('base64url');
44
+ await models_1.AuthorizationCode.create({
45
+ ...input,
46
+ code,
47
+ expiresAt: new Date(Date.now() + CODE_TTL_MS)
48
+ });
49
+ return code;
50
+ };
51
+ exports.issueAuthorizationCode = issueAuthorizationCode;
52
+ /**
53
+ * Exchange a code, once.
54
+ *
55
+ * The `usedAt` stamp is set by the same atomic update that fetches the code, so
56
+ * two simultaneous exchanges cannot both succeed — a replayed code loses the
57
+ * race rather than being caught by a check that ran a moment earlier.
58
+ */
59
+ const redeemAuthorizationCode = async (code, clientId, redirectUri, codeVerifier) => {
60
+ const record = await models_1.AuthorizationCode.findOneAndUpdate({ code, usedAt: { $exists: false } }, { $set: { usedAt: new Date() } }, { new: true });
61
+ if (!record) {
62
+ // Either it never existed or it has already been redeemed; the client is
63
+ // told the same thing for both.
64
+ const existed = await models_1.AuthorizationCode.exists({ code });
65
+ return { ok: false, rejection: existed ? 'already-used' : 'unknown' };
66
+ }
67
+ if (record.expiresAt.getTime() <= Date.now())
68
+ return { ok: false, rejection: 'expired' };
69
+ if (record.clientId !== clientId)
70
+ return { ok: false, rejection: 'client-mismatch' };
71
+ if (record.redirectUri !== redirectUri)
72
+ return { ok: false, rejection: 'redirect-mismatch' };
73
+ if (!constantTimeEquals(s256(codeVerifier), record.codeChallenge)) {
74
+ return { ok: false, rejection: 'pkce-failed' };
75
+ }
76
+ return { ok: true, code: record };
77
+ };
78
+ exports.redeemAuthorizationCode = redeemAuthorizationCode;
79
+ const issueRefreshToken = async (input) => {
80
+ const token = (0, crypto_1.randomBytes)(32).toString('base64url');
81
+ await models_1.RefreshToken.create({ ...input, tokenHash: sha256(token) });
82
+ return { token };
83
+ };
84
+ exports.issueRefreshToken = issueRefreshToken;
85
+ /**
86
+ * Exchange a refresh token for a new one, rotating as we go.
87
+ *
88
+ * Rotation matters because these are the long-lived half: an access token is
89
+ * gone within the hour, but a refresh token that never changes is a permanent
90
+ * credential for whoever obtains a copy. Each use retires the old token and
91
+ * issues a fresh one, so a stolen copy stops working as soon as the legitimate
92
+ * client refreshes.
93
+ *
94
+ * Reuse of an already-rotated token is treated as theft rather than as an
95
+ * ordinary failure: the honest client and the thief now both hold tokens
96
+ * descended from the same grant, and there is no way to tell which just called.
97
+ * So the whole chain is revoked and the user reconnects — noisy, but the
98
+ * alternative is leaving an attacker with working access.
99
+ */
100
+ const redeemRefreshToken = async (token, clientId) => {
101
+ const record = await models_1.RefreshToken.findOne({ tokenHash: sha256(token), clientId });
102
+ if (!record)
103
+ return { ok: false };
104
+ if (record.revokedAt) {
105
+ // Already rotated or explicitly revoked. If something is still presenting
106
+ // it, a copy is loose — cut every token in this grant.
107
+ await models_1.RefreshToken.updateMany({ userId: record.userId, clientId, revokedAt: { $exists: false } }, { $set: { revokedAt: new Date() } });
108
+ return { ok: false, reused: true };
109
+ }
110
+ record.revokedAt = new Date();
111
+ record.lastUsedAt = new Date();
112
+ await record.save();
113
+ const rotated = (0, crypto_1.randomBytes)(32).toString('base64url');
114
+ await models_1.RefreshToken.create({
115
+ tokenHash: sha256(rotated),
116
+ clientId,
117
+ userId: record.userId,
118
+ scopes: record.scopes,
119
+ groupId: record.groupId ?? null,
120
+ resource: record.resource,
121
+ // Carried, not reset: this is still the grant the user approved.
122
+ grantedAt: record.grantedAt ?? record.createdAt
123
+ });
124
+ return {
125
+ ok: true,
126
+ userId: record.userId,
127
+ scopes: record.scopes,
128
+ groupId: record.groupId ?? null,
129
+ resource: record.resource,
130
+ rotatedToken: rotated
131
+ };
132
+ };
133
+ exports.redeemRefreshToken = redeemRefreshToken;
134
+ /** Cut off an assistant: without a refresh token it can obtain nothing new. */
135
+ const revokeRefreshTokensForUser = async (userId, clientId) => {
136
+ const filter = { userId, revokedAt: { $exists: false } };
137
+ if (clientId)
138
+ filter.clientId = clientId;
139
+ const result = await models_1.RefreshToken.updateMany(filter, { $set: { revokedAt: new Date() } });
140
+ return result.modifiedCount;
141
+ };
142
+ exports.revokeRefreshTokensForUser = revokeRefreshTokensForUser;
143
+ const listConnections = async (userId) => {
144
+ const tokens = await models_1.RefreshToken.find({ userId }).sort({ createdAt: -1 });
145
+ const clients = await models_1.OAuthClient.find({ clientId: { $in: tokens.map((t) => t.clientId) } });
146
+ const nameById = new Map(clients.map((client) => [client.clientId, client.clientName]));
147
+ return tokens.map((token) => ({
148
+ id: String(token._id),
149
+ clientId: token.clientId,
150
+ clientName: nameById.get(token.clientId) ?? 'Unknown app',
151
+ scopes: token.scopes,
152
+ groupId: token.groupId ?? null,
153
+ createdAt: (token.grantedAt ?? token.createdAt).toISOString(),
154
+ lastUsedAt: token.lastUsedAt?.toISOString() ?? null,
155
+ revokedAt: token.revokedAt?.toISOString() ?? null
156
+ }));
157
+ };
158
+ exports.listConnections = listConnections;
159
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/oauth/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import { type ApiKeyScope } from '../apiKeys/types';
2
+ /**
3
+ * Access tokens for the OAuth flow that lets an assistant connect to Tumbaland.
4
+ *
5
+ * These are JWTs rather than database rows so the MCP server can validate one
6
+ * without a query on every tool call, and because OAuth expects short-lived
7
+ * bearer tokens with a refresh path rather than the indefinite credentials an
8
+ * API key is. The trade is that a token cannot be revoked before it expires —
9
+ * hence the deliberately short life, with revocation applied at the refresh
10
+ * token, which is the thing that actually persists.
11
+ */
12
+ /** Marks a token as issued by the OAuth flow, for the MCP resource specifically. */
13
+ declare const TOKEN_TYPE = "mcp_access";
14
+ export interface AccessTokenClaims {
15
+ /** the user the assistant is acting for */
16
+ sub: string;
17
+ /** the MCP server this token may be used against — RFC 8707 audience binding */
18
+ aud: string;
19
+ iss: string;
20
+ scope: string;
21
+ /** the tenant the token is pinned to; null means the user's personal data */
22
+ groupId: string | null;
23
+ email: string;
24
+ name: string;
25
+ typ: typeof TOKEN_TYPE;
26
+ jti: string;
27
+ exp: number;
28
+ iat: number;
29
+ }
30
+ export interface MintAccessTokenInput {
31
+ userId: string;
32
+ email: string;
33
+ name: string;
34
+ /** the canonical URI of the MCP server the token is for */
35
+ resource: string;
36
+ issuer: string;
37
+ scopes: ApiKeyScope[];
38
+ groupId: string | null;
39
+ }
40
+ export interface MintedAccessToken {
41
+ accessToken: string;
42
+ expiresIn: number;
43
+ scope: string;
44
+ }
45
+ export declare const mintAccessToken: (input: MintAccessTokenInput) => MintedAccessToken;
46
+ export interface AccessTokenVerification {
47
+ ok: boolean;
48
+ rejection?: 'malformed' | 'expired' | 'wrong-audience' | 'wrong-type' | 'bad-signature';
49
+ userId?: string;
50
+ email?: string;
51
+ name?: string;
52
+ scopes?: ApiKeyScope[];
53
+ groupId?: string | null;
54
+ }
55
+ /**
56
+ * Check a bearer token presented to the MCP server.
57
+ *
58
+ * Two checks beyond the signature carry real weight. The audience must match
59
+ * this server: a token minted for one resource must not work against another,
60
+ * which is what RFC 8707 binding is for and what stops a token obtained for
61
+ * somewhere else being replayed here. And the type must be `mcp_access`, so an
62
+ * ordinary session JWT — same secret, same issuer, but no scopes and no tenant
63
+ * pin — cannot be presented as an access token and quietly get everything.
64
+ */
65
+ export declare const verifyAccessToken: (token: string, expectedAudience: string) => AccessTokenVerification;
66
+ /** Parse a space-separated `scope` parameter, dropping anything we do not define. */
67
+ export declare const parseScopes: (scope: unknown) => ApiKeyScope[];
68
+ export {};
69
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/oauth/tokens.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEnE;;;;;;;;;GASG;AAEH,oFAAoF;AACpF,QAAA,MAAM,UAAU,eAAe,CAAC;AAKhC,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,6EAA6E;IAC7E,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,UAAU,CAAC;IACvB,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,GAAG,IAAI,CAAC;CACxB;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,iBAoB7D,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,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,MAAM,EACb,kBAAkB,MAAM,KACvB,uBAqBF,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,KAAG,WAAW,EACmB,CAAC"}