@mcp-z/oauth-microsoft 1.0.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/LICENSE +21 -0
- package/README.md +98 -0
- package/dist/cjs/index.d.cts +16 -0
- package/dist/cjs/index.d.ts +16 -0
- package/dist/cjs/index.js +112 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/lib/dcr-router.d.cts +44 -0
- package/dist/cjs/lib/dcr-router.d.ts +44 -0
- package/dist/cjs/lib/dcr-router.js +1227 -0
- package/dist/cjs/lib/dcr-router.js.map +1 -0
- package/dist/cjs/lib/dcr-utils.d.cts +160 -0
- package/dist/cjs/lib/dcr-utils.d.ts +160 -0
- package/dist/cjs/lib/dcr-utils.js +860 -0
- package/dist/cjs/lib/dcr-utils.js.map +1 -0
- package/dist/cjs/lib/dcr-verify.d.cts +53 -0
- package/dist/cjs/lib/dcr-verify.d.ts +53 -0
- package/dist/cjs/lib/dcr-verify.js +193 -0
- package/dist/cjs/lib/dcr-verify.js.map +1 -0
- package/dist/cjs/lib/fetch-with-timeout.d.cts +14 -0
- package/dist/cjs/lib/fetch-with-timeout.d.ts +14 -0
- package/dist/cjs/lib/fetch-with-timeout.js +257 -0
- package/dist/cjs/lib/fetch-with-timeout.js.map +1 -0
- package/dist/cjs/lib/token-verifier.d.cts +44 -0
- package/dist/cjs/lib/token-verifier.d.ts +44 -0
- package/dist/cjs/lib/token-verifier.js +253 -0
- package/dist/cjs/lib/token-verifier.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/providers/dcr.d.cts +110 -0
- package/dist/cjs/providers/dcr.d.ts +110 -0
- package/dist/cjs/providers/dcr.js +600 -0
- package/dist/cjs/providers/dcr.js.map +1 -0
- package/dist/cjs/providers/device-code.d.cts +179 -0
- package/dist/cjs/providers/device-code.d.ts +179 -0
- package/dist/cjs/providers/device-code.js +896 -0
- package/dist/cjs/providers/device-code.js.map +1 -0
- package/dist/cjs/providers/loopback-oauth.d.cts +125 -0
- package/dist/cjs/providers/loopback-oauth.d.ts +125 -0
- package/dist/cjs/providers/loopback-oauth.js +1325 -0
- package/dist/cjs/providers/loopback-oauth.js.map +1 -0
- package/dist/cjs/schemas/index.d.cts +20 -0
- package/dist/cjs/schemas/index.d.ts +20 -0
- package/dist/cjs/schemas/index.js +37 -0
- package/dist/cjs/schemas/index.js.map +1 -0
- package/dist/cjs/setup/config.d.cts +113 -0
- package/dist/cjs/setup/config.d.ts +113 -0
- package/dist/cjs/setup/config.js +246 -0
- package/dist/cjs/setup/config.js.map +1 -0
- package/dist/cjs/types.d.cts +188 -0
- package/dist/cjs/types.d.ts +188 -0
- package/dist/cjs/types.js +18 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/index.d.ts +16 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lib/dcr-router.d.ts +44 -0
- package/dist/esm/lib/dcr-router.js +556 -0
- package/dist/esm/lib/dcr-router.js.map +1 -0
- package/dist/esm/lib/dcr-utils.d.ts +160 -0
- package/dist/esm/lib/dcr-utils.js +270 -0
- package/dist/esm/lib/dcr-utils.js.map +1 -0
- package/dist/esm/lib/dcr-verify.d.ts +53 -0
- package/dist/esm/lib/dcr-verify.js +53 -0
- package/dist/esm/lib/dcr-verify.js.map +1 -0
- package/dist/esm/lib/fetch-with-timeout.d.ts +14 -0
- package/dist/esm/lib/fetch-with-timeout.js +30 -0
- package/dist/esm/lib/fetch-with-timeout.js.map +1 -0
- package/dist/esm/lib/token-verifier.d.ts +44 -0
- package/dist/esm/lib/token-verifier.js +53 -0
- package/dist/esm/lib/token-verifier.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/providers/dcr.d.ts +110 -0
- package/dist/esm/providers/dcr.js +235 -0
- package/dist/esm/providers/dcr.js.map +1 -0
- package/dist/esm/providers/device-code.d.ts +179 -0
- package/dist/esm/providers/device-code.js +417 -0
- package/dist/esm/providers/device-code.js.map +1 -0
- package/dist/esm/providers/loopback-oauth.d.ts +125 -0
- package/dist/esm/providers/loopback-oauth.js +643 -0
- package/dist/esm/providers/loopback-oauth.js.map +1 -0
- package/dist/esm/schemas/index.d.ts +20 -0
- package/dist/esm/schemas/index.js +18 -0
- package/dist/esm/schemas/index.js.map +1 -0
- package/dist/esm/setup/config.d.ts +113 -0
- package/dist/esm/setup/config.js +268 -0
- package/dist/esm/setup/config.js.map +1 -0
- package/dist/esm/types.d.ts +188 -0
- package/dist/esm/types.js +8 -0
- package/dist/esm/types.js.map +1 -0
- package/package.json +87 -0
|
@@ -0,0 +1,1227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DCR Router - OAuth 2.0 Authorization Server
|
|
3
|
+
*
|
|
4
|
+
* Implements OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591)
|
|
5
|
+
* and OAuth 2.0 Authorization Server endpoints (RFC 6749, RFC 8414, RFC 9728).
|
|
6
|
+
*
|
|
7
|
+
* Endpoints:
|
|
8
|
+
* - GET /.well-known/oauth-authorization-server (RFC 8414 metadata)
|
|
9
|
+
* - GET /.well-known/oauth-protected-resource (RFC 9728 metadata - root)
|
|
10
|
+
* - GET /.well-known/oauth-protected-resource/mcp (RFC 9728 metadata - sub-path)
|
|
11
|
+
* - POST /oauth/register (RFC 7591 client registration)
|
|
12
|
+
* - GET /oauth/authorize (RFC 6749 authorization endpoint)
|
|
13
|
+
* - POST /oauth/token (RFC 6749 token endpoint)
|
|
14
|
+
* - POST /oauth/revoke (RFC 7009 token revocation)
|
|
15
|
+
* - GET /oauth/verify (token verification for Resource Server)
|
|
16
|
+
*/ "use strict";
|
|
17
|
+
Object.defineProperty(exports, "__esModule", {
|
|
18
|
+
value: true
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(exports, "createDcrRouter", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
get: function() {
|
|
23
|
+
return createDcrRouter;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
var _crypto = require("crypto");
|
|
27
|
+
var _express = /*#__PURE__*/ _interop_require_default(require("express"));
|
|
28
|
+
var _dcrts = require("../providers/dcr.js");
|
|
29
|
+
var _dcrutilsts = /*#__PURE__*/ _interop_require_wildcard(require("./dcr-utils.js"));
|
|
30
|
+
function _array_like_to_array(arr, len) {
|
|
31
|
+
if (len == null || len > arr.length) len = arr.length;
|
|
32
|
+
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
33
|
+
return arr2;
|
|
34
|
+
}
|
|
35
|
+
function _array_with_holes(arr) {
|
|
36
|
+
if (Array.isArray(arr)) return arr;
|
|
37
|
+
}
|
|
38
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
39
|
+
try {
|
|
40
|
+
var info = gen[key](arg);
|
|
41
|
+
var value = info.value;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
reject(error);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (info.done) {
|
|
47
|
+
resolve(value);
|
|
48
|
+
} else {
|
|
49
|
+
Promise.resolve(value).then(_next, _throw);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function _async_to_generator(fn) {
|
|
53
|
+
return function() {
|
|
54
|
+
var self = this, args = arguments;
|
|
55
|
+
return new Promise(function(resolve, reject) {
|
|
56
|
+
var gen = fn.apply(self, args);
|
|
57
|
+
function _next(value) {
|
|
58
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
|
|
59
|
+
}
|
|
60
|
+
function _throw(err) {
|
|
61
|
+
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
|
|
62
|
+
}
|
|
63
|
+
_next(undefined);
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function _define_property(obj, key, value) {
|
|
68
|
+
if (key in obj) {
|
|
69
|
+
Object.defineProperty(obj, key, {
|
|
70
|
+
value: value,
|
|
71
|
+
enumerable: true,
|
|
72
|
+
configurable: true,
|
|
73
|
+
writable: true
|
|
74
|
+
});
|
|
75
|
+
} else {
|
|
76
|
+
obj[key] = value;
|
|
77
|
+
}
|
|
78
|
+
return obj;
|
|
79
|
+
}
|
|
80
|
+
function _instanceof(left, right) {
|
|
81
|
+
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
|
|
82
|
+
return !!right[Symbol.hasInstance](left);
|
|
83
|
+
} else {
|
|
84
|
+
return left instanceof right;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function _interop_require_default(obj) {
|
|
88
|
+
return obj && obj.__esModule ? obj : {
|
|
89
|
+
default: obj
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
93
|
+
if (typeof WeakMap !== "function") return null;
|
|
94
|
+
var cacheBabelInterop = new WeakMap();
|
|
95
|
+
var cacheNodeInterop = new WeakMap();
|
|
96
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
97
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
98
|
+
})(nodeInterop);
|
|
99
|
+
}
|
|
100
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
101
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
102
|
+
return obj;
|
|
103
|
+
}
|
|
104
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
105
|
+
return {
|
|
106
|
+
default: obj
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
110
|
+
if (cache && cache.has(obj)) {
|
|
111
|
+
return cache.get(obj);
|
|
112
|
+
}
|
|
113
|
+
var newObj = {
|
|
114
|
+
__proto__: null
|
|
115
|
+
};
|
|
116
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
117
|
+
for(var key in obj){
|
|
118
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
119
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
120
|
+
if (desc && (desc.get || desc.set)) {
|
|
121
|
+
Object.defineProperty(newObj, key, desc);
|
|
122
|
+
} else {
|
|
123
|
+
newObj[key] = obj[key];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
newObj.default = obj;
|
|
128
|
+
if (cache) {
|
|
129
|
+
cache.set(obj, newObj);
|
|
130
|
+
}
|
|
131
|
+
return newObj;
|
|
132
|
+
}
|
|
133
|
+
function _iterable_to_array_limit(arr, i) {
|
|
134
|
+
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
|
|
135
|
+
if (_i == null) return;
|
|
136
|
+
var _arr = [];
|
|
137
|
+
var _n = true;
|
|
138
|
+
var _d = false;
|
|
139
|
+
var _s, _e;
|
|
140
|
+
try {
|
|
141
|
+
for(_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true){
|
|
142
|
+
_arr.push(_s.value);
|
|
143
|
+
if (i && _arr.length === i) break;
|
|
144
|
+
}
|
|
145
|
+
} catch (err) {
|
|
146
|
+
_d = true;
|
|
147
|
+
_e = err;
|
|
148
|
+
} finally{
|
|
149
|
+
try {
|
|
150
|
+
if (!_n && _i["return"] != null) _i["return"]();
|
|
151
|
+
} finally{
|
|
152
|
+
if (_d) throw _e;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return _arr;
|
|
156
|
+
}
|
|
157
|
+
function _non_iterable_rest() {
|
|
158
|
+
throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
159
|
+
}
|
|
160
|
+
function _object_spread(target) {
|
|
161
|
+
for(var i = 1; i < arguments.length; i++){
|
|
162
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
163
|
+
var ownKeys = Object.keys(source);
|
|
164
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
165
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
166
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
169
|
+
ownKeys.forEach(function(key) {
|
|
170
|
+
_define_property(target, key, source[key]);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return target;
|
|
174
|
+
}
|
|
175
|
+
function ownKeys(object, enumerableOnly) {
|
|
176
|
+
var keys = Object.keys(object);
|
|
177
|
+
if (Object.getOwnPropertySymbols) {
|
|
178
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
179
|
+
if (enumerableOnly) {
|
|
180
|
+
symbols = symbols.filter(function(sym) {
|
|
181
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
keys.push.apply(keys, symbols);
|
|
185
|
+
}
|
|
186
|
+
return keys;
|
|
187
|
+
}
|
|
188
|
+
function _object_spread_props(target, source) {
|
|
189
|
+
source = source != null ? source : {};
|
|
190
|
+
if (Object.getOwnPropertyDescriptors) {
|
|
191
|
+
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
192
|
+
} else {
|
|
193
|
+
ownKeys(Object(source)).forEach(function(key) {
|
|
194
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return target;
|
|
198
|
+
}
|
|
199
|
+
function _sliced_to_array(arr, i) {
|
|
200
|
+
return _array_with_holes(arr) || _iterable_to_array_limit(arr, i) || _unsupported_iterable_to_array(arr, i) || _non_iterable_rest();
|
|
201
|
+
}
|
|
202
|
+
function _unsupported_iterable_to_array(o, minLen) {
|
|
203
|
+
if (!o) return;
|
|
204
|
+
if (typeof o === "string") return _array_like_to_array(o, minLen);
|
|
205
|
+
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
206
|
+
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
207
|
+
if (n === "Map" || n === "Set") return Array.from(n);
|
|
208
|
+
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
|
209
|
+
}
|
|
210
|
+
function _ts_generator(thisArg, body) {
|
|
211
|
+
var f, y, t, _ = {
|
|
212
|
+
label: 0,
|
|
213
|
+
sent: function() {
|
|
214
|
+
if (t[0] & 1) throw t[1];
|
|
215
|
+
return t[1];
|
|
216
|
+
},
|
|
217
|
+
trys: [],
|
|
218
|
+
ops: []
|
|
219
|
+
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
|
|
220
|
+
return d(g, "next", {
|
|
221
|
+
value: verb(0)
|
|
222
|
+
}), d(g, "throw", {
|
|
223
|
+
value: verb(1)
|
|
224
|
+
}), d(g, "return", {
|
|
225
|
+
value: verb(2)
|
|
226
|
+
}), typeof Symbol === "function" && d(g, Symbol.iterator, {
|
|
227
|
+
value: function() {
|
|
228
|
+
return this;
|
|
229
|
+
}
|
|
230
|
+
}), g;
|
|
231
|
+
function verb(n) {
|
|
232
|
+
return function(v) {
|
|
233
|
+
return step([
|
|
234
|
+
n,
|
|
235
|
+
v
|
|
236
|
+
]);
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function step(op) {
|
|
240
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
241
|
+
while(g && (g = 0, op[0] && (_ = 0)), _)try {
|
|
242
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
243
|
+
if (y = 0, t) op = [
|
|
244
|
+
op[0] & 2,
|
|
245
|
+
t.value
|
|
246
|
+
];
|
|
247
|
+
switch(op[0]){
|
|
248
|
+
case 0:
|
|
249
|
+
case 1:
|
|
250
|
+
t = op;
|
|
251
|
+
break;
|
|
252
|
+
case 4:
|
|
253
|
+
_.label++;
|
|
254
|
+
return {
|
|
255
|
+
value: op[1],
|
|
256
|
+
done: false
|
|
257
|
+
};
|
|
258
|
+
case 5:
|
|
259
|
+
_.label++;
|
|
260
|
+
y = op[1];
|
|
261
|
+
op = [
|
|
262
|
+
0
|
|
263
|
+
];
|
|
264
|
+
continue;
|
|
265
|
+
case 7:
|
|
266
|
+
op = _.ops.pop();
|
|
267
|
+
_.trys.pop();
|
|
268
|
+
continue;
|
|
269
|
+
default:
|
|
270
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
271
|
+
_ = 0;
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
275
|
+
_.label = op[1];
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
if (op[0] === 6 && _.label < t[1]) {
|
|
279
|
+
_.label = t[1];
|
|
280
|
+
t = op;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
if (t && _.label < t[2]) {
|
|
284
|
+
_.label = t[2];
|
|
285
|
+
_.ops.push(op);
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
if (t[2]) _.ops.pop();
|
|
289
|
+
_.trys.pop();
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
op = body.call(thisArg, _);
|
|
293
|
+
} catch (e) {
|
|
294
|
+
op = [
|
|
295
|
+
6,
|
|
296
|
+
e
|
|
297
|
+
];
|
|
298
|
+
y = 0;
|
|
299
|
+
} finally{
|
|
300
|
+
f = t = 0;
|
|
301
|
+
}
|
|
302
|
+
if (op[0] & 5) throw op[1];
|
|
303
|
+
return {
|
|
304
|
+
value: op[0] ? op[1] : void 0,
|
|
305
|
+
done: true
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function createDcrRouter(config) {
|
|
310
|
+
var router = _express.default.Router();
|
|
311
|
+
var store = config.store, issuerUrl = config.issuerUrl, baseUrl = config.baseUrl, scopesSupported = config.scopesSupported, clientConfig = config.clientConfig;
|
|
312
|
+
// Apply required middleware for OAuth 2.0 endpoints (RFC 6749)
|
|
313
|
+
router.use(_express.default.json()); // For /oauth/register (application/json)
|
|
314
|
+
router.use(_express.default.urlencoded({
|
|
315
|
+
extended: true
|
|
316
|
+
})); // For /oauth/token (application/x-www-form-urlencoded)
|
|
317
|
+
/**
|
|
318
|
+
* OAuth Authorization Server Metadata (RFC 8414)
|
|
319
|
+
* GET /.well-known/oauth-authorization-server
|
|
320
|
+
*/ router.get('/.well-known/oauth-authorization-server', function(_req, res) {
|
|
321
|
+
var metadata = {
|
|
322
|
+
issuer: issuerUrl,
|
|
323
|
+
authorization_endpoint: "".concat(baseUrl, "/oauth/authorize"),
|
|
324
|
+
token_endpoint: "".concat(baseUrl, "/oauth/token"),
|
|
325
|
+
registration_endpoint: "".concat(baseUrl, "/oauth/register"),
|
|
326
|
+
revocation_endpoint: "".concat(baseUrl, "/oauth/revoke"),
|
|
327
|
+
scopes_supported: scopesSupported,
|
|
328
|
+
response_types_supported: [
|
|
329
|
+
'code'
|
|
330
|
+
],
|
|
331
|
+
grant_types_supported: [
|
|
332
|
+
'authorization_code',
|
|
333
|
+
'refresh_token'
|
|
334
|
+
],
|
|
335
|
+
token_endpoint_auth_methods_supported: [
|
|
336
|
+
'client_secret_basic',
|
|
337
|
+
'client_secret_post'
|
|
338
|
+
],
|
|
339
|
+
code_challenge_methods_supported: [
|
|
340
|
+
'S256',
|
|
341
|
+
'plain'
|
|
342
|
+
],
|
|
343
|
+
service_documentation: "".concat(baseUrl, "/docs")
|
|
344
|
+
};
|
|
345
|
+
res.json(metadata);
|
|
346
|
+
});
|
|
347
|
+
/**
|
|
348
|
+
* OAuth Protected Resource Metadata (RFC 9728 - Root)
|
|
349
|
+
* GET /.well-known/oauth-protected-resource
|
|
350
|
+
*/ router.get('/.well-known/oauth-protected-resource', function(_req, res) {
|
|
351
|
+
var metadata = {
|
|
352
|
+
resource: baseUrl,
|
|
353
|
+
authorization_servers: [
|
|
354
|
+
baseUrl
|
|
355
|
+
],
|
|
356
|
+
scopes_supported: scopesSupported,
|
|
357
|
+
bearer_methods_supported: [
|
|
358
|
+
'header'
|
|
359
|
+
]
|
|
360
|
+
};
|
|
361
|
+
res.json(metadata);
|
|
362
|
+
});
|
|
363
|
+
/**
|
|
364
|
+
* OAuth Protected Resource Metadata (RFC 9728 - Sub-path /mcp)
|
|
365
|
+
* GET /.well-known/oauth-protected-resource/mcp
|
|
366
|
+
*/ router.get('/.well-known/oauth-protected-resource/mcp', function(_req, res) {
|
|
367
|
+
var metadata = {
|
|
368
|
+
resource: "".concat(baseUrl, "/mcp"),
|
|
369
|
+
authorization_servers: [
|
|
370
|
+
baseUrl
|
|
371
|
+
],
|
|
372
|
+
scopes_supported: scopesSupported,
|
|
373
|
+
bearer_methods_supported: [
|
|
374
|
+
'header'
|
|
375
|
+
]
|
|
376
|
+
};
|
|
377
|
+
res.json(metadata);
|
|
378
|
+
});
|
|
379
|
+
/**
|
|
380
|
+
* Dynamic Client Registration (RFC 7591)
|
|
381
|
+
* POST /oauth/register
|
|
382
|
+
*/ router.post('/oauth/register', function(req, res) {
|
|
383
|
+
return _async_to_generator(function() {
|
|
384
|
+
var registrationRequest, client, error;
|
|
385
|
+
return _ts_generator(this, function(_state) {
|
|
386
|
+
switch(_state.label){
|
|
387
|
+
case 0:
|
|
388
|
+
_state.trys.push([
|
|
389
|
+
0,
|
|
390
|
+
2,
|
|
391
|
+
,
|
|
392
|
+
3
|
|
393
|
+
]);
|
|
394
|
+
registrationRequest = req.body;
|
|
395
|
+
return [
|
|
396
|
+
4,
|
|
397
|
+
_dcrutilsts.registerClient(store, registrationRequest)
|
|
398
|
+
];
|
|
399
|
+
case 1:
|
|
400
|
+
client = _state.sent();
|
|
401
|
+
// Return client information (RFC 7591 Section 3.2.1)
|
|
402
|
+
res.status(201).json(client);
|
|
403
|
+
return [
|
|
404
|
+
3,
|
|
405
|
+
3
|
|
406
|
+
];
|
|
407
|
+
case 2:
|
|
408
|
+
error = _state.sent();
|
|
409
|
+
res.status(400).json({
|
|
410
|
+
error: 'invalid_client_metadata',
|
|
411
|
+
error_description: _instanceof(error, Error) ? error.message : 'Invalid registration request'
|
|
412
|
+
});
|
|
413
|
+
return [
|
|
414
|
+
3,
|
|
415
|
+
3
|
|
416
|
+
];
|
|
417
|
+
case 3:
|
|
418
|
+
return [
|
|
419
|
+
2
|
|
420
|
+
];
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
})();
|
|
424
|
+
});
|
|
425
|
+
/**
|
|
426
|
+
* OAuth Authorization Endpoint (RFC 6749 Section 3.1)
|
|
427
|
+
* GET /oauth/authorize
|
|
428
|
+
*
|
|
429
|
+
* Initiates Microsoft OAuth flow, then generates DCR authorization code
|
|
430
|
+
*/ router.get('/oauth/authorize', function(req, res) {
|
|
431
|
+
return _async_to_generator(function() {
|
|
432
|
+
var _req_query, response_type, client_id, redirect_uri, _req_query_scope, scope, _req_query_state, state, code_challenge, code_challenge_method, client, isValidRedirect, msState, dcrRequestState, msAuthUrl;
|
|
433
|
+
return _ts_generator(this, function(_state) {
|
|
434
|
+
switch(_state.label){
|
|
435
|
+
case 0:
|
|
436
|
+
_req_query = req.query, response_type = _req_query.response_type, client_id = _req_query.client_id, redirect_uri = _req_query.redirect_uri, _req_query_scope = _req_query.scope, scope = _req_query_scope === void 0 ? '' : _req_query_scope, _req_query_state = _req_query.state, state = _req_query_state === void 0 ? '' : _req_query_state, code_challenge = _req_query.code_challenge, code_challenge_method = _req_query.code_challenge_method;
|
|
437
|
+
// Validate required parameters
|
|
438
|
+
if (response_type !== 'code') {
|
|
439
|
+
return [
|
|
440
|
+
2,
|
|
441
|
+
res.status(400).json({
|
|
442
|
+
error: 'unsupported_response_type',
|
|
443
|
+
error_description: 'Only response_type=code is supported'
|
|
444
|
+
})
|
|
445
|
+
];
|
|
446
|
+
}
|
|
447
|
+
if (!client_id || typeof client_id !== 'string') {
|
|
448
|
+
return [
|
|
449
|
+
2,
|
|
450
|
+
res.status(400).json({
|
|
451
|
+
error: 'invalid_request',
|
|
452
|
+
error_description: 'client_id is required'
|
|
453
|
+
})
|
|
454
|
+
];
|
|
455
|
+
}
|
|
456
|
+
if (!redirect_uri || typeof redirect_uri !== 'string') {
|
|
457
|
+
return [
|
|
458
|
+
2,
|
|
459
|
+
res.status(400).json({
|
|
460
|
+
error: 'invalid_request',
|
|
461
|
+
error_description: 'redirect_uri is required'
|
|
462
|
+
})
|
|
463
|
+
];
|
|
464
|
+
}
|
|
465
|
+
return [
|
|
466
|
+
4,
|
|
467
|
+
_dcrutilsts.getClient(store, client_id)
|
|
468
|
+
];
|
|
469
|
+
case 1:
|
|
470
|
+
client = _state.sent();
|
|
471
|
+
if (!client) {
|
|
472
|
+
return [
|
|
473
|
+
2,
|
|
474
|
+
res.status(400).json({
|
|
475
|
+
error: 'invalid_client',
|
|
476
|
+
error_description: 'Unknown client_id'
|
|
477
|
+
})
|
|
478
|
+
];
|
|
479
|
+
}
|
|
480
|
+
return [
|
|
481
|
+
4,
|
|
482
|
+
_dcrutilsts.validateRedirectUri(store, client_id, redirect_uri)
|
|
483
|
+
];
|
|
484
|
+
case 2:
|
|
485
|
+
isValidRedirect = _state.sent();
|
|
486
|
+
if (!isValidRedirect) {
|
|
487
|
+
return [
|
|
488
|
+
2,
|
|
489
|
+
res.status(400).json({
|
|
490
|
+
error: 'invalid_request',
|
|
491
|
+
error_description: 'Invalid redirect_uri'
|
|
492
|
+
})
|
|
493
|
+
];
|
|
494
|
+
}
|
|
495
|
+
// Store DCR request state for Microsoft OAuth callback
|
|
496
|
+
msState = (0, _crypto.randomUUID)();
|
|
497
|
+
dcrRequestState = {
|
|
498
|
+
client_id: client_id,
|
|
499
|
+
redirect_uri: redirect_uri,
|
|
500
|
+
scope: typeof scope === 'string' ? scope : '',
|
|
501
|
+
state: typeof state === 'string' ? state : undefined,
|
|
502
|
+
code_challenge: typeof code_challenge === 'string' ? code_challenge : undefined,
|
|
503
|
+
code_challenge_method: typeof code_challenge_method === 'string' ? code_challenge_method : undefined,
|
|
504
|
+
created_at: Date.now(),
|
|
505
|
+
expires_at: Date.now() + 600000
|
|
506
|
+
};
|
|
507
|
+
return [
|
|
508
|
+
4,
|
|
509
|
+
store.set("dcr:ms-state:".concat(msState), dcrRequestState, 600000)
|
|
510
|
+
];
|
|
511
|
+
case 3:
|
|
512
|
+
_state.sent(); // 10 min TTL
|
|
513
|
+
// Build Microsoft authorization URL
|
|
514
|
+
msAuthUrl = new URL("https://login.microsoftonline.com/".concat(clientConfig.tenantId || 'common', "/oauth2/v2.0/authorize"));
|
|
515
|
+
msAuthUrl.searchParams.set('client_id', clientConfig.clientId);
|
|
516
|
+
msAuthUrl.searchParams.set('response_type', 'code');
|
|
517
|
+
msAuthUrl.searchParams.set('redirect_uri', "".concat(baseUrl, "/oauth/callback"));
|
|
518
|
+
msAuthUrl.searchParams.set('scope', typeof scope === 'string' ? scope : '');
|
|
519
|
+
msAuthUrl.searchParams.set('state', msState);
|
|
520
|
+
msAuthUrl.searchParams.set('response_mode', 'query');
|
|
521
|
+
// Redirect user to Microsoft for authorization
|
|
522
|
+
return [
|
|
523
|
+
2,
|
|
524
|
+
res.redirect(msAuthUrl.toString())
|
|
525
|
+
];
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
})();
|
|
529
|
+
});
|
|
530
|
+
/**
|
|
531
|
+
* OAuth Callback Handler
|
|
532
|
+
* GET /oauth/callback
|
|
533
|
+
*
|
|
534
|
+
* Handles callback from Microsoft after user authorization
|
|
535
|
+
*/ router.get('/oauth/callback', function(req, res) {
|
|
536
|
+
return _async_to_generator(function() {
|
|
537
|
+
var _req_query, msCode, msState, _$error, error_description, dcrRequestState, tokenUrl, tokenParams, tokenResponse, errorData, tokenData, providerTokens, dcrCode, authCode, clientRedirectUrl, error;
|
|
538
|
+
return _ts_generator(this, function(_state) {
|
|
539
|
+
switch(_state.label){
|
|
540
|
+
case 0:
|
|
541
|
+
_req_query = req.query, msCode = _req_query.code, msState = _req_query.state, _$error = _req_query.error, error_description = _req_query.error_description;
|
|
542
|
+
// Handle Microsoft OAuth errors
|
|
543
|
+
if (_$error) {
|
|
544
|
+
return [
|
|
545
|
+
2,
|
|
546
|
+
res.status(400).json({
|
|
547
|
+
error: _$error,
|
|
548
|
+
error_description: error_description || 'Microsoft OAuth authorization failed'
|
|
549
|
+
})
|
|
550
|
+
];
|
|
551
|
+
}
|
|
552
|
+
if (!msCode || typeof msCode !== 'string') {
|
|
553
|
+
return [
|
|
554
|
+
2,
|
|
555
|
+
res.status(400).json({
|
|
556
|
+
error: 'invalid_request',
|
|
557
|
+
error_description: 'Authorization code is required'
|
|
558
|
+
})
|
|
559
|
+
];
|
|
560
|
+
}
|
|
561
|
+
if (!msState || typeof msState !== 'string') {
|
|
562
|
+
return [
|
|
563
|
+
2,
|
|
564
|
+
res.status(400).json({
|
|
565
|
+
error: 'invalid_request',
|
|
566
|
+
error_description: 'State parameter is required'
|
|
567
|
+
})
|
|
568
|
+
];
|
|
569
|
+
}
|
|
570
|
+
return [
|
|
571
|
+
4,
|
|
572
|
+
store.get("dcr:ms-state:".concat(msState))
|
|
573
|
+
];
|
|
574
|
+
case 1:
|
|
575
|
+
dcrRequestState = _state.sent();
|
|
576
|
+
if (!dcrRequestState) {
|
|
577
|
+
return [
|
|
578
|
+
2,
|
|
579
|
+
res.status(400).json({
|
|
580
|
+
error: 'invalid_request',
|
|
581
|
+
error_description: 'Invalid or expired state parameter'
|
|
582
|
+
})
|
|
583
|
+
];
|
|
584
|
+
}
|
|
585
|
+
// Delete state (one-time use)
|
|
586
|
+
return [
|
|
587
|
+
4,
|
|
588
|
+
store.delete("dcr:ms-state:".concat(msState))
|
|
589
|
+
];
|
|
590
|
+
case 2:
|
|
591
|
+
_state.sent();
|
|
592
|
+
_state.label = 3;
|
|
593
|
+
case 3:
|
|
594
|
+
_state.trys.push([
|
|
595
|
+
3,
|
|
596
|
+
9,
|
|
597
|
+
,
|
|
598
|
+
10
|
|
599
|
+
]);
|
|
600
|
+
tokenUrl = "https://login.microsoftonline.com/".concat(clientConfig.tenantId || 'common', "/oauth2/v2.0/token");
|
|
601
|
+
tokenParams = new URLSearchParams({
|
|
602
|
+
grant_type: 'authorization_code',
|
|
603
|
+
code: msCode,
|
|
604
|
+
client_id: clientConfig.clientId,
|
|
605
|
+
redirect_uri: "".concat(baseUrl, "/oauth/callback"),
|
|
606
|
+
scope: dcrRequestState.scope
|
|
607
|
+
});
|
|
608
|
+
// Add client_secret if available (confidential client)
|
|
609
|
+
if (clientConfig.clientSecret) {
|
|
610
|
+
tokenParams.set('client_secret', clientConfig.clientSecret);
|
|
611
|
+
}
|
|
612
|
+
return [
|
|
613
|
+
4,
|
|
614
|
+
fetch(tokenUrl, {
|
|
615
|
+
method: 'POST',
|
|
616
|
+
headers: {
|
|
617
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
618
|
+
},
|
|
619
|
+
body: tokenParams.toString()
|
|
620
|
+
})
|
|
621
|
+
];
|
|
622
|
+
case 4:
|
|
623
|
+
tokenResponse = _state.sent();
|
|
624
|
+
if (!!tokenResponse.ok) return [
|
|
625
|
+
3,
|
|
626
|
+
6
|
|
627
|
+
];
|
|
628
|
+
return [
|
|
629
|
+
4,
|
|
630
|
+
tokenResponse.json()
|
|
631
|
+
];
|
|
632
|
+
case 5:
|
|
633
|
+
errorData = _state.sent();
|
|
634
|
+
throw new Error("Microsoft token exchange failed: ".concat(errorData.error_description || errorData.error));
|
|
635
|
+
case 6:
|
|
636
|
+
return [
|
|
637
|
+
4,
|
|
638
|
+
tokenResponse.json()
|
|
639
|
+
];
|
|
640
|
+
case 7:
|
|
641
|
+
tokenData = _state.sent();
|
|
642
|
+
// Create provider tokens from Microsoft response
|
|
643
|
+
providerTokens = _object_spread_props(_object_spread({
|
|
644
|
+
accessToken: tokenData.access_token
|
|
645
|
+
}, tokenData.refresh_token && {
|
|
646
|
+
refreshToken: tokenData.refresh_token
|
|
647
|
+
}), {
|
|
648
|
+
expiresAt: Date.now() + tokenData.expires_in * 1000,
|
|
649
|
+
scope: tokenData.scope
|
|
650
|
+
});
|
|
651
|
+
// Generate DCR authorization code with real provider tokens
|
|
652
|
+
dcrCode = (0, _crypto.randomUUID)();
|
|
653
|
+
authCode = _object_spread_props(_object_spread({
|
|
654
|
+
code: dcrCode,
|
|
655
|
+
client_id: dcrRequestState.client_id,
|
|
656
|
+
redirect_uri: dcrRequestState.redirect_uri,
|
|
657
|
+
scope: dcrRequestState.scope
|
|
658
|
+
}, dcrRequestState.code_challenge && {
|
|
659
|
+
code_challenge: dcrRequestState.code_challenge
|
|
660
|
+
}, dcrRequestState.code_challenge_method && {
|
|
661
|
+
code_challenge_method: dcrRequestState.code_challenge_method
|
|
662
|
+
}), {
|
|
663
|
+
providerTokens: providerTokens,
|
|
664
|
+
created_at: Date.now(),
|
|
665
|
+
expires_at: Date.now() + 600000
|
|
666
|
+
});
|
|
667
|
+
return [
|
|
668
|
+
4,
|
|
669
|
+
_dcrutilsts.setAuthCode(store, dcrCode, authCode)
|
|
670
|
+
];
|
|
671
|
+
case 8:
|
|
672
|
+
_state.sent();
|
|
673
|
+
// Redirect back to MCP client with DCR authorization code
|
|
674
|
+
clientRedirectUrl = new URL(dcrRequestState.redirect_uri);
|
|
675
|
+
clientRedirectUrl.searchParams.set('code', dcrCode);
|
|
676
|
+
if (dcrRequestState.state) {
|
|
677
|
+
clientRedirectUrl.searchParams.set('state', dcrRequestState.state);
|
|
678
|
+
}
|
|
679
|
+
return [
|
|
680
|
+
2,
|
|
681
|
+
res.redirect(clientRedirectUrl.toString())
|
|
682
|
+
];
|
|
683
|
+
case 9:
|
|
684
|
+
error = _state.sent();
|
|
685
|
+
return [
|
|
686
|
+
2,
|
|
687
|
+
res.status(500).json({
|
|
688
|
+
error: 'server_error',
|
|
689
|
+
error_description: _instanceof(error, Error) ? error.message : 'Failed to exchange authorization code'
|
|
690
|
+
})
|
|
691
|
+
];
|
|
692
|
+
case 10:
|
|
693
|
+
return [
|
|
694
|
+
2
|
|
695
|
+
];
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
})();
|
|
699
|
+
});
|
|
700
|
+
/**
|
|
701
|
+
* OAuth Token Endpoint (RFC 6749 Section 3.2)
|
|
702
|
+
* POST /oauth/token
|
|
703
|
+
*/ router.post('/oauth/token', function(req, res) {
|
|
704
|
+
return _async_to_generator(function() {
|
|
705
|
+
var client_id, client_secret, authHeader, base64Credentials, credentials, _credentials_split, id, secret, _req_body, grant_type, code, redirect_uri, refresh_token, code_verifier, isValidClient, authCode, _authCode_code_challenge_method, method, computedChallenge, accessToken, refreshTokenValue, tokenData, isValidClient1, tokenData1, refreshedProviderTokens, _clientConfig_tenantId, provider, error, newAccessToken, newTokenData;
|
|
706
|
+
return _ts_generator(this, function(_state) {
|
|
707
|
+
switch(_state.label){
|
|
708
|
+
case 0:
|
|
709
|
+
// Extract client credentials from either body or Basic Auth header
|
|
710
|
+
client_id = req.body.client_id;
|
|
711
|
+
client_secret = req.body.client_secret;
|
|
712
|
+
// Support client_secret_basic authentication (RFC 6749 Section 2.3.1)
|
|
713
|
+
authHeader = req.headers.authorization;
|
|
714
|
+
if (authHeader && authHeader.startsWith('Basic ')) {
|
|
715
|
+
base64Credentials = authHeader.substring(6);
|
|
716
|
+
credentials = Buffer.from(base64Credentials, 'base64').toString('utf-8');
|
|
717
|
+
_credentials_split = _sliced_to_array(credentials.split(':'), 2), id = _credentials_split[0], secret = _credentials_split[1];
|
|
718
|
+
client_id = id;
|
|
719
|
+
client_secret = secret;
|
|
720
|
+
}
|
|
721
|
+
_req_body = req.body, grant_type = _req_body.grant_type, code = _req_body.code, redirect_uri = _req_body.redirect_uri, refresh_token = _req_body.refresh_token, code_verifier = _req_body.code_verifier;
|
|
722
|
+
// Validate grant_type
|
|
723
|
+
if (!grant_type) {
|
|
724
|
+
return [
|
|
725
|
+
2,
|
|
726
|
+
res.status(400).json({
|
|
727
|
+
error: 'invalid_request',
|
|
728
|
+
error_description: 'grant_type is required'
|
|
729
|
+
})
|
|
730
|
+
];
|
|
731
|
+
}
|
|
732
|
+
if (!(grant_type === 'authorization_code')) return [
|
|
733
|
+
3,
|
|
734
|
+
9
|
|
735
|
+
];
|
|
736
|
+
// Authorization Code Grant
|
|
737
|
+
if (!code || !client_id || !redirect_uri) {
|
|
738
|
+
return [
|
|
739
|
+
2,
|
|
740
|
+
res.status(400).json({
|
|
741
|
+
error: 'invalid_request',
|
|
742
|
+
error_description: 'code, client_id, and redirect_uri are required'
|
|
743
|
+
})
|
|
744
|
+
];
|
|
745
|
+
}
|
|
746
|
+
return [
|
|
747
|
+
4,
|
|
748
|
+
_dcrutilsts.validateClient(store, client_id, client_secret !== null && client_secret !== void 0 ? client_secret : '')
|
|
749
|
+
];
|
|
750
|
+
case 1:
|
|
751
|
+
isValidClient = _state.sent();
|
|
752
|
+
if (!isValidClient) {
|
|
753
|
+
return [
|
|
754
|
+
2,
|
|
755
|
+
res.status(401).json({
|
|
756
|
+
error: 'invalid_client',
|
|
757
|
+
error_description: 'Invalid client credentials'
|
|
758
|
+
})
|
|
759
|
+
];
|
|
760
|
+
}
|
|
761
|
+
return [
|
|
762
|
+
4,
|
|
763
|
+
_dcrutilsts.getAuthCode(store, code)
|
|
764
|
+
];
|
|
765
|
+
case 2:
|
|
766
|
+
authCode = _state.sent();
|
|
767
|
+
if (!authCode) {
|
|
768
|
+
return [
|
|
769
|
+
2,
|
|
770
|
+
res.status(400).json({
|
|
771
|
+
error: 'invalid_grant',
|
|
772
|
+
error_description: 'Invalid or expired authorization code'
|
|
773
|
+
})
|
|
774
|
+
];
|
|
775
|
+
}
|
|
776
|
+
// Validate authorization code
|
|
777
|
+
if (authCode.client_id !== client_id || authCode.redirect_uri !== redirect_uri) {
|
|
778
|
+
return [
|
|
779
|
+
2,
|
|
780
|
+
res.status(400).json({
|
|
781
|
+
error: 'invalid_grant',
|
|
782
|
+
error_description: 'Authorization code mismatch'
|
|
783
|
+
})
|
|
784
|
+
];
|
|
785
|
+
}
|
|
786
|
+
if (!(Date.now() > authCode.expires_at)) return [
|
|
787
|
+
3,
|
|
788
|
+
4
|
|
789
|
+
];
|
|
790
|
+
return [
|
|
791
|
+
4,
|
|
792
|
+
_dcrutilsts.deleteAuthCode(store, code)
|
|
793
|
+
];
|
|
794
|
+
case 3:
|
|
795
|
+
_state.sent();
|
|
796
|
+
return [
|
|
797
|
+
2,
|
|
798
|
+
res.status(400).json({
|
|
799
|
+
error: 'invalid_grant',
|
|
800
|
+
error_description: 'Authorization code expired'
|
|
801
|
+
})
|
|
802
|
+
];
|
|
803
|
+
case 4:
|
|
804
|
+
// Validate PKCE if used
|
|
805
|
+
if (authCode.code_challenge) {
|
|
806
|
+
;
|
|
807
|
+
if (!code_verifier) {
|
|
808
|
+
return [
|
|
809
|
+
2,
|
|
810
|
+
res.status(400).json({
|
|
811
|
+
error: 'invalid_request',
|
|
812
|
+
error_description: 'code_verifier is required for PKCE'
|
|
813
|
+
})
|
|
814
|
+
];
|
|
815
|
+
}
|
|
816
|
+
// Validate code_verifier against code_challenge
|
|
817
|
+
method = (_authCode_code_challenge_method = authCode.code_challenge_method) !== null && _authCode_code_challenge_method !== void 0 ? _authCode_code_challenge_method : 'plain';
|
|
818
|
+
computedChallenge = method === 'S256' ? (0, _crypto.createHash)('sha256').update(code_verifier).digest('base64url') : code_verifier;
|
|
819
|
+
if (computedChallenge !== authCode.code_challenge) {
|
|
820
|
+
return [
|
|
821
|
+
2,
|
|
822
|
+
res.status(400).json({
|
|
823
|
+
error: 'invalid_grant',
|
|
824
|
+
error_description: 'Invalid code_verifier'
|
|
825
|
+
})
|
|
826
|
+
];
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
// Delete authorization code (one-time use)
|
|
830
|
+
return [
|
|
831
|
+
4,
|
|
832
|
+
_dcrutilsts.deleteAuthCode(store, code)
|
|
833
|
+
];
|
|
834
|
+
case 5:
|
|
835
|
+
_state.sent();
|
|
836
|
+
// Generate DCR access token
|
|
837
|
+
accessToken = (0, _crypto.randomUUID)();
|
|
838
|
+
refreshTokenValue = (0, _crypto.randomUUID)();
|
|
839
|
+
tokenData = {
|
|
840
|
+
access_token: accessToken,
|
|
841
|
+
token_type: 'Bearer',
|
|
842
|
+
expires_in: 3600,
|
|
843
|
+
refresh_token: refreshTokenValue,
|
|
844
|
+
scope: authCode.scope,
|
|
845
|
+
client_id: client_id,
|
|
846
|
+
providerTokens: authCode.providerTokens,
|
|
847
|
+
created_at: Date.now()
|
|
848
|
+
};
|
|
849
|
+
return [
|
|
850
|
+
4,
|
|
851
|
+
_dcrutilsts.setAccessToken(store, accessToken, tokenData)
|
|
852
|
+
];
|
|
853
|
+
case 6:
|
|
854
|
+
_state.sent();
|
|
855
|
+
return [
|
|
856
|
+
4,
|
|
857
|
+
_dcrutilsts.setRefreshToken(store, refreshTokenValue, tokenData)
|
|
858
|
+
];
|
|
859
|
+
case 7:
|
|
860
|
+
_state.sent();
|
|
861
|
+
// Store provider tokens indexed by DCR access token
|
|
862
|
+
return [
|
|
863
|
+
4,
|
|
864
|
+
_dcrutilsts.setProviderTokens(store, accessToken, authCode.providerTokens)
|
|
865
|
+
];
|
|
866
|
+
case 8:
|
|
867
|
+
_state.sent();
|
|
868
|
+
// Return token response
|
|
869
|
+
return [
|
|
870
|
+
2,
|
|
871
|
+
res.json({
|
|
872
|
+
access_token: tokenData.access_token,
|
|
873
|
+
token_type: tokenData.token_type,
|
|
874
|
+
expires_in: tokenData.expires_in,
|
|
875
|
+
refresh_token: tokenData.refresh_token,
|
|
876
|
+
scope: tokenData.scope
|
|
877
|
+
})
|
|
878
|
+
];
|
|
879
|
+
case 9:
|
|
880
|
+
if (!(grant_type === 'refresh_token')) return [
|
|
881
|
+
3,
|
|
882
|
+
18
|
|
883
|
+
];
|
|
884
|
+
// Refresh Token Grant
|
|
885
|
+
if (!refresh_token || !client_id) {
|
|
886
|
+
return [
|
|
887
|
+
2,
|
|
888
|
+
res.status(400).json({
|
|
889
|
+
error: 'invalid_request',
|
|
890
|
+
error_description: 'refresh_token and client_id are required'
|
|
891
|
+
})
|
|
892
|
+
];
|
|
893
|
+
}
|
|
894
|
+
return [
|
|
895
|
+
4,
|
|
896
|
+
_dcrutilsts.validateClient(store, client_id, client_secret !== null && client_secret !== void 0 ? client_secret : '')
|
|
897
|
+
];
|
|
898
|
+
case 10:
|
|
899
|
+
isValidClient1 = _state.sent();
|
|
900
|
+
if (!isValidClient1) {
|
|
901
|
+
return [
|
|
902
|
+
2,
|
|
903
|
+
res.status(401).json({
|
|
904
|
+
error: 'invalid_client',
|
|
905
|
+
error_description: 'Invalid client credentials'
|
|
906
|
+
})
|
|
907
|
+
];
|
|
908
|
+
}
|
|
909
|
+
return [
|
|
910
|
+
4,
|
|
911
|
+
_dcrutilsts.getRefreshToken(store, refresh_token)
|
|
912
|
+
];
|
|
913
|
+
case 11:
|
|
914
|
+
tokenData1 = _state.sent();
|
|
915
|
+
if (!tokenData1 || tokenData1.client_id !== client_id) {
|
|
916
|
+
return [
|
|
917
|
+
2,
|
|
918
|
+
res.status(400).json({
|
|
919
|
+
error: 'invalid_grant',
|
|
920
|
+
error_description: 'Invalid refresh token'
|
|
921
|
+
})
|
|
922
|
+
];
|
|
923
|
+
}
|
|
924
|
+
// Refresh provider tokens if available
|
|
925
|
+
refreshedProviderTokens = tokenData1.providerTokens;
|
|
926
|
+
if (!tokenData1.providerTokens.refreshToken) return [
|
|
927
|
+
3,
|
|
928
|
+
15
|
|
929
|
+
];
|
|
930
|
+
_state.label = 12;
|
|
931
|
+
case 12:
|
|
932
|
+
_state.trys.push([
|
|
933
|
+
12,
|
|
934
|
+
14,
|
|
935
|
+
,
|
|
936
|
+
15
|
|
937
|
+
]);
|
|
938
|
+
// Create DcrOAuthProvider instance to refresh Microsoft tokens
|
|
939
|
+
provider = new _dcrts.DcrOAuthProvider(_object_spread_props(_object_spread({
|
|
940
|
+
clientId: clientConfig.clientId
|
|
941
|
+
}, clientConfig.clientSecret && {
|
|
942
|
+
clientSecret: clientConfig.clientSecret
|
|
943
|
+
}), {
|
|
944
|
+
tenantId: (_clientConfig_tenantId = clientConfig.tenantId) !== null && _clientConfig_tenantId !== void 0 ? _clientConfig_tenantId : 'common',
|
|
945
|
+
scope: tokenData1.scope,
|
|
946
|
+
verifyEndpoint: "".concat(baseUrl, "/oauth/verify"),
|
|
947
|
+
logger: {
|
|
948
|
+
info: console.log,
|
|
949
|
+
error: console.error,
|
|
950
|
+
warn: console.warn,
|
|
951
|
+
debug: function() {}
|
|
952
|
+
}
|
|
953
|
+
}));
|
|
954
|
+
return [
|
|
955
|
+
4,
|
|
956
|
+
provider.refreshAccessToken(tokenData1.providerTokens.refreshToken)
|
|
957
|
+
];
|
|
958
|
+
case 13:
|
|
959
|
+
// Refresh the Microsoft access token
|
|
960
|
+
refreshedProviderTokens = _state.sent();
|
|
961
|
+
return [
|
|
962
|
+
3,
|
|
963
|
+
15
|
|
964
|
+
];
|
|
965
|
+
case 14:
|
|
966
|
+
error = _state.sent();
|
|
967
|
+
// If refresh fails, continue with existing tokens (they may still be valid)
|
|
968
|
+
console.warn('Provider token refresh failed, using existing tokens:', _instanceof(error, Error) ? error.message : String(error));
|
|
969
|
+
return [
|
|
970
|
+
3,
|
|
971
|
+
15
|
|
972
|
+
];
|
|
973
|
+
case 15:
|
|
974
|
+
// Generate new DCR access token
|
|
975
|
+
newAccessToken = (0, _crypto.randomUUID)();
|
|
976
|
+
newTokenData = _object_spread_props(_object_spread({}, tokenData1), {
|
|
977
|
+
access_token: newAccessToken,
|
|
978
|
+
created_at: Date.now()
|
|
979
|
+
});
|
|
980
|
+
return [
|
|
981
|
+
4,
|
|
982
|
+
_dcrutilsts.setAccessToken(store, newAccessToken, newTokenData)
|
|
983
|
+
];
|
|
984
|
+
case 16:
|
|
985
|
+
_state.sent();
|
|
986
|
+
// Store refreshed provider tokens indexed by new DCR access token
|
|
987
|
+
return [
|
|
988
|
+
4,
|
|
989
|
+
_dcrutilsts.setProviderTokens(store, newAccessToken, refreshedProviderTokens)
|
|
990
|
+
];
|
|
991
|
+
case 17:
|
|
992
|
+
_state.sent();
|
|
993
|
+
return [
|
|
994
|
+
2,
|
|
995
|
+
res.json({
|
|
996
|
+
access_token: newTokenData.access_token,
|
|
997
|
+
token_type: newTokenData.token_type,
|
|
998
|
+
expires_in: newTokenData.expires_in,
|
|
999
|
+
scope: newTokenData.scope
|
|
1000
|
+
})
|
|
1001
|
+
];
|
|
1002
|
+
case 18:
|
|
1003
|
+
return [
|
|
1004
|
+
2,
|
|
1005
|
+
res.status(400).json({
|
|
1006
|
+
error: 'unsupported_grant_type',
|
|
1007
|
+
error_description: 'Only authorization_code and refresh_token grants are supported'
|
|
1008
|
+
})
|
|
1009
|
+
];
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1012
|
+
})();
|
|
1013
|
+
});
|
|
1014
|
+
/**
|
|
1015
|
+
* OAuth Token Revocation (RFC 7009)
|
|
1016
|
+
* POST /oauth/revoke
|
|
1017
|
+
*/ router.post('/oauth/revoke', function(req, res) {
|
|
1018
|
+
return _async_to_generator(function() {
|
|
1019
|
+
var _req_body, token, token_type_hint, client_id, client_secret, isValidClient;
|
|
1020
|
+
return _ts_generator(this, function(_state) {
|
|
1021
|
+
switch(_state.label){
|
|
1022
|
+
case 0:
|
|
1023
|
+
_req_body = req.body, token = _req_body.token, token_type_hint = _req_body.token_type_hint, client_id = _req_body.client_id, client_secret = _req_body.client_secret;
|
|
1024
|
+
if (!token) {
|
|
1025
|
+
return [
|
|
1026
|
+
2,
|
|
1027
|
+
res.status(400).json({
|
|
1028
|
+
error: 'invalid_request',
|
|
1029
|
+
error_description: 'token is required'
|
|
1030
|
+
})
|
|
1031
|
+
];
|
|
1032
|
+
}
|
|
1033
|
+
if (!(client_id && client_secret)) return [
|
|
1034
|
+
3,
|
|
1035
|
+
2
|
|
1036
|
+
];
|
|
1037
|
+
return [
|
|
1038
|
+
4,
|
|
1039
|
+
_dcrutilsts.validateClient(store, client_id, client_secret)
|
|
1040
|
+
];
|
|
1041
|
+
case 1:
|
|
1042
|
+
isValidClient = _state.sent();
|
|
1043
|
+
if (!isValidClient) {
|
|
1044
|
+
return [
|
|
1045
|
+
2,
|
|
1046
|
+
res.status(401).json({
|
|
1047
|
+
error: 'invalid_client',
|
|
1048
|
+
error_description: 'Invalid client credentials'
|
|
1049
|
+
})
|
|
1050
|
+
];
|
|
1051
|
+
}
|
|
1052
|
+
_state.label = 2;
|
|
1053
|
+
case 2:
|
|
1054
|
+
if (!(token_type_hint === 'refresh_token')) return [
|
|
1055
|
+
3,
|
|
1056
|
+
4
|
|
1057
|
+
];
|
|
1058
|
+
return [
|
|
1059
|
+
4,
|
|
1060
|
+
_dcrutilsts.deleteRefreshToken(store, token)
|
|
1061
|
+
];
|
|
1062
|
+
case 3:
|
|
1063
|
+
_state.sent();
|
|
1064
|
+
return [
|
|
1065
|
+
3,
|
|
1066
|
+
11
|
|
1067
|
+
];
|
|
1068
|
+
case 4:
|
|
1069
|
+
if (!(token_type_hint === 'access_token')) return [
|
|
1070
|
+
3,
|
|
1071
|
+
7
|
|
1072
|
+
];
|
|
1073
|
+
return [
|
|
1074
|
+
4,
|
|
1075
|
+
_dcrutilsts.deleteAccessToken(store, token)
|
|
1076
|
+
];
|
|
1077
|
+
case 5:
|
|
1078
|
+
_state.sent();
|
|
1079
|
+
return [
|
|
1080
|
+
4,
|
|
1081
|
+
_dcrutilsts.deleteProviderTokens(store, token)
|
|
1082
|
+
];
|
|
1083
|
+
case 6:
|
|
1084
|
+
_state.sent();
|
|
1085
|
+
return [
|
|
1086
|
+
3,
|
|
1087
|
+
11
|
|
1088
|
+
];
|
|
1089
|
+
case 7:
|
|
1090
|
+
// No hint - try both
|
|
1091
|
+
return [
|
|
1092
|
+
4,
|
|
1093
|
+
_dcrutilsts.deleteRefreshToken(store, token)
|
|
1094
|
+
];
|
|
1095
|
+
case 8:
|
|
1096
|
+
_state.sent();
|
|
1097
|
+
return [
|
|
1098
|
+
4,
|
|
1099
|
+
_dcrutilsts.deleteAccessToken(store, token)
|
|
1100
|
+
];
|
|
1101
|
+
case 9:
|
|
1102
|
+
_state.sent();
|
|
1103
|
+
return [
|
|
1104
|
+
4,
|
|
1105
|
+
_dcrutilsts.deleteProviderTokens(store, token)
|
|
1106
|
+
];
|
|
1107
|
+
case 10:
|
|
1108
|
+
_state.sent();
|
|
1109
|
+
_state.label = 11;
|
|
1110
|
+
case 11:
|
|
1111
|
+
// RFC 7009: Return 200 even if token not found
|
|
1112
|
+
return [
|
|
1113
|
+
2,
|
|
1114
|
+
res.status(200).send()
|
|
1115
|
+
];
|
|
1116
|
+
}
|
|
1117
|
+
});
|
|
1118
|
+
})();
|
|
1119
|
+
});
|
|
1120
|
+
/**
|
|
1121
|
+
* Token Verification Endpoint
|
|
1122
|
+
* GET /oauth/verify
|
|
1123
|
+
*
|
|
1124
|
+
* Validates bearer tokens for Resource Server.
|
|
1125
|
+
* Returns AuthInfo with provider tokens for stateless DCR pattern.
|
|
1126
|
+
*/ router.get('/oauth/verify', function(req, res) {
|
|
1127
|
+
return _async_to_generator(function() {
|
|
1128
|
+
var authHeader, token, tokenData, now, expiresAt, authInfo;
|
|
1129
|
+
return _ts_generator(this, function(_state) {
|
|
1130
|
+
switch(_state.label){
|
|
1131
|
+
case 0:
|
|
1132
|
+
// Extract bearer token from Authorization header
|
|
1133
|
+
authHeader = req.headers.authorization;
|
|
1134
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
1135
|
+
return [
|
|
1136
|
+
2,
|
|
1137
|
+
res.status(401).json({
|
|
1138
|
+
error: 'invalid_request',
|
|
1139
|
+
error_description: 'Missing or invalid Authorization header'
|
|
1140
|
+
})
|
|
1141
|
+
];
|
|
1142
|
+
}
|
|
1143
|
+
token = authHeader.substring(7); // Remove 'Bearer ' prefix
|
|
1144
|
+
return [
|
|
1145
|
+
4,
|
|
1146
|
+
_dcrutilsts.getAccessToken(store, token)
|
|
1147
|
+
];
|
|
1148
|
+
case 1:
|
|
1149
|
+
tokenData = _state.sent();
|
|
1150
|
+
if (!tokenData) {
|
|
1151
|
+
return [
|
|
1152
|
+
2,
|
|
1153
|
+
res.status(401).json({
|
|
1154
|
+
error: 'invalid_token',
|
|
1155
|
+
error_description: 'Unknown or expired access token'
|
|
1156
|
+
})
|
|
1157
|
+
];
|
|
1158
|
+
}
|
|
1159
|
+
// Check if token is expired
|
|
1160
|
+
now = Date.now();
|
|
1161
|
+
expiresAt = tokenData.created_at + tokenData.expires_in * 1000;
|
|
1162
|
+
if (!(now > expiresAt)) return [
|
|
1163
|
+
3,
|
|
1164
|
+
4
|
|
1165
|
+
];
|
|
1166
|
+
// Remove expired token
|
|
1167
|
+
return [
|
|
1168
|
+
4,
|
|
1169
|
+
_dcrutilsts.deleteAccessToken(store, token)
|
|
1170
|
+
];
|
|
1171
|
+
case 2:
|
|
1172
|
+
_state.sent();
|
|
1173
|
+
return [
|
|
1174
|
+
4,
|
|
1175
|
+
_dcrutilsts.deleteProviderTokens(store, token)
|
|
1176
|
+
];
|
|
1177
|
+
case 3:
|
|
1178
|
+
_state.sent();
|
|
1179
|
+
return [
|
|
1180
|
+
2,
|
|
1181
|
+
res.status(401).json({
|
|
1182
|
+
error: 'invalid_token',
|
|
1183
|
+
error_description: 'Access token has expired'
|
|
1184
|
+
})
|
|
1185
|
+
];
|
|
1186
|
+
case 4:
|
|
1187
|
+
// Return AuthInfo with provider tokens for stateless DCR
|
|
1188
|
+
authInfo = {
|
|
1189
|
+
token: token,
|
|
1190
|
+
clientId: tokenData.client_id,
|
|
1191
|
+
scopes: tokenData.scope ? tokenData.scope.split(' ') : [],
|
|
1192
|
+
expiresAt: expiresAt,
|
|
1193
|
+
providerTokens: tokenData.providerTokens
|
|
1194
|
+
};
|
|
1195
|
+
return [
|
|
1196
|
+
2,
|
|
1197
|
+
res.json(authInfo)
|
|
1198
|
+
];
|
|
1199
|
+
}
|
|
1200
|
+
});
|
|
1201
|
+
})();
|
|
1202
|
+
});
|
|
1203
|
+
/**
|
|
1204
|
+
* Debug endpoint to list registered clients (development only)
|
|
1205
|
+
*/ router.get('/debug/clients', function(_req, res) {
|
|
1206
|
+
return _async_to_generator(function() {
|
|
1207
|
+
var clients;
|
|
1208
|
+
return _ts_generator(this, function(_state) {
|
|
1209
|
+
switch(_state.label){
|
|
1210
|
+
case 0:
|
|
1211
|
+
return [
|
|
1212
|
+
4,
|
|
1213
|
+
_dcrutilsts.listClients(store)
|
|
1214
|
+
];
|
|
1215
|
+
case 1:
|
|
1216
|
+
clients = _state.sent();
|
|
1217
|
+
res.json(clients);
|
|
1218
|
+
return [
|
|
1219
|
+
2
|
|
1220
|
+
];
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1223
|
+
})();
|
|
1224
|
+
});
|
|
1225
|
+
return router;
|
|
1226
|
+
}
|
|
1227
|
+
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|