@vfarcic/dot-ai 1.4.0 → 1.6.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.
Files changed (65) hide show
  1. package/dist/core/schema.d.ts.map +1 -1
  2. package/dist/core/schema.js +27 -0
  3. package/dist/core/user-prompts-loader.d.ts.map +1 -1
  4. package/dist/core/user-prompts-loader.js +95 -8
  5. package/dist/interfaces/error-response.d.ts +2 -1
  6. package/dist/interfaces/error-response.d.ts.map +1 -1
  7. package/dist/interfaces/error-response.js +6 -2
  8. package/dist/interfaces/mcp.d.ts +32 -12
  9. package/dist/interfaces/mcp.d.ts.map +1 -1
  10. package/dist/interfaces/mcp.js +328 -231
  11. package/dist/interfaces/oauth/dex-api.proto +304 -0
  12. package/dist/interfaces/oauth/dex-client.d.ts +41 -0
  13. package/dist/interfaces/oauth/dex-client.d.ts.map +1 -0
  14. package/dist/interfaces/oauth/dex-client.js +145 -0
  15. package/dist/interfaces/oauth/index.d.ts +6 -0
  16. package/dist/interfaces/oauth/index.d.ts.map +1 -0
  17. package/dist/interfaces/oauth/index.js +16 -0
  18. package/dist/interfaces/oauth/jwt.d.ts +37 -0
  19. package/dist/interfaces/oauth/jwt.d.ts.map +1 -0
  20. package/dist/interfaces/oauth/jwt.js +106 -0
  21. package/dist/interfaces/oauth/middleware.d.ts +27 -0
  22. package/dist/interfaces/oauth/middleware.d.ts.map +1 -0
  23. package/dist/interfaces/oauth/middleware.js +106 -0
  24. package/dist/interfaces/oauth/provider.d.ts +94 -0
  25. package/dist/interfaces/oauth/provider.d.ts.map +1 -0
  26. package/dist/interfaces/oauth/provider.js +373 -0
  27. package/dist/interfaces/oauth/types.d.ts +98 -0
  28. package/dist/interfaces/oauth/types.d.ts.map +1 -0
  29. package/dist/interfaces/oauth/types.js +8 -0
  30. package/dist/interfaces/oauth/user-management.d.ts +36 -0
  31. package/dist/interfaces/oauth/user-management.d.ts.map +1 -0
  32. package/dist/interfaces/oauth/user-management.js +156 -0
  33. package/dist/interfaces/request-context.d.ts +19 -0
  34. package/dist/interfaces/request-context.d.ts.map +1 -0
  35. package/dist/interfaces/request-context.js +20 -0
  36. package/dist/interfaces/rest-api.d.ts +12 -0
  37. package/dist/interfaces/rest-api.d.ts.map +1 -1
  38. package/dist/interfaces/rest-api.js +107 -0
  39. package/dist/interfaces/routes/index.d.ts.map +1 -1
  40. package/dist/interfaces/routes/index.js +38 -0
  41. package/dist/interfaces/schemas/common.d.ts +1 -0
  42. package/dist/interfaces/schemas/common.d.ts.map +1 -1
  43. package/dist/interfaces/schemas/common.js +1 -0
  44. package/dist/interfaces/schemas/index.d.ts +2 -1
  45. package/dist/interfaces/schemas/index.d.ts.map +1 -1
  46. package/dist/interfaces/schemas/index.js +18 -2
  47. package/dist/interfaces/schemas/prompts.d.ts +16 -0
  48. package/dist/interfaces/schemas/prompts.d.ts.map +1 -1
  49. package/dist/interfaces/schemas/prompts.js +9 -1
  50. package/dist/interfaces/schemas/users.d.ts +128 -0
  51. package/dist/interfaces/schemas/users.d.ts.map +1 -0
  52. package/dist/interfaces/schemas/users.js +64 -0
  53. package/dist/tools/prompts.d.ts +8 -1
  54. package/dist/tools/prompts.d.ts.map +1 -1
  55. package/dist/tools/prompts.js +15 -3
  56. package/dist/tools/remediate.d.ts +1 -1
  57. package/dist/tools/remediate.d.ts.map +1 -1
  58. package/dist/tools/remediate.js +38 -26
  59. package/dist/tools/version.d.ts.map +1 -1
  60. package/dist/tools/version.js +4 -0
  61. package/package.json +7 -2
  62. package/shared-prompts/prd-start.md +13 -0
  63. package/dist/interfaces/auth.d.ts +0 -26
  64. package/dist/interfaces/auth.d.ts.map +0 -1
  65. package/dist/interfaces/auth.js +0 -82
@@ -0,0 +1,304 @@
1
+ syntax = "proto3";
2
+
3
+ package api;
4
+
5
+ option java_package = "com.coreos.dex.api";
6
+ option go_package = "github.com/dexidp/dex/api/v2;api";
7
+
8
+ // Client represents an OAuth2 client.
9
+ message Client {
10
+ string id = 1;
11
+ string secret = 2;
12
+ repeated string redirect_uris = 3;
13
+ repeated string trusted_peers = 4;
14
+ bool public = 5;
15
+ string name = 6;
16
+ string logo_url = 7;
17
+ }
18
+
19
+ // ClientInfo represents an OAuth2 client without sensitive information.
20
+ message ClientInfo {
21
+ string id = 1;
22
+ repeated string redirect_uris = 2;
23
+ repeated string trusted_peers = 3;
24
+ bool public = 4;
25
+ string name = 5;
26
+ string logo_url = 6;
27
+ }
28
+
29
+ // GetClientReq is a request to retrieve client details.
30
+ message GetClientReq {
31
+ // The ID of the client.
32
+ string id = 1;
33
+ }
34
+
35
+ // GetClientResp returns the client details.
36
+ message GetClientResp {
37
+ Client client = 1;
38
+ }
39
+
40
+ // CreateClientReq is a request to make a client.
41
+ message CreateClientReq {
42
+ Client client = 1;
43
+ }
44
+
45
+ // CreateClientResp returns the response from creating a client.
46
+ message CreateClientResp {
47
+ bool already_exists = 1;
48
+ Client client = 2;
49
+ }
50
+
51
+ // DeleteClientReq is a request to delete a client.
52
+ message DeleteClientReq {
53
+ // The ID of the client.
54
+ string id = 1;
55
+ }
56
+
57
+ // DeleteClientResp determines if the client is deleted successfully.
58
+ message DeleteClientResp {
59
+ bool not_found = 1;
60
+ }
61
+
62
+ // UpdateClientReq is a request to update an existing client.
63
+ message UpdateClientReq {
64
+ string id = 1;
65
+ repeated string redirect_uris = 2;
66
+ repeated string trusted_peers = 3;
67
+ string name = 4;
68
+ string logo_url = 5;
69
+ }
70
+
71
+ // UpdateClientResp returns the response from updating a client.
72
+ message UpdateClientResp {
73
+ bool not_found = 1;
74
+ }
75
+
76
+ // ListClientReq is a request to enumerate clients.
77
+ message ListClientReq {}
78
+
79
+ // ListClientResp returns a list of clients.
80
+ message ListClientResp {
81
+ repeated ClientInfo clients = 1;
82
+ }
83
+
84
+ // TODO(ericchiang): expand this.
85
+
86
+ // Password is an email for password mapping managed by the storage.
87
+ message Password {
88
+ string email = 1;
89
+
90
+ // Currently we do not accept plain text passwords. Could be an option in the future.
91
+ bytes hash = 2;
92
+ string username = 3;
93
+ string user_id = 4;
94
+ }
95
+
96
+ // CreatePasswordReq is a request to make a password.
97
+ message CreatePasswordReq {
98
+ Password password = 1;
99
+ }
100
+
101
+ // CreatePasswordResp returns the response from creating a password.
102
+ message CreatePasswordResp {
103
+ bool already_exists = 1;
104
+ }
105
+
106
+ // UpdatePasswordReq is a request to modify an existing password.
107
+ message UpdatePasswordReq {
108
+ // The email used to lookup the password. This field cannot be modified
109
+ string email = 1;
110
+ bytes new_hash = 2;
111
+ string new_username = 3;
112
+ }
113
+
114
+ // UpdatePasswordResp returns the response from modifying an existing password.
115
+ message UpdatePasswordResp {
116
+ bool not_found = 1;
117
+ }
118
+
119
+ // DeletePasswordReq is a request to delete a password.
120
+ message DeletePasswordReq {
121
+ string email = 1;
122
+ }
123
+
124
+ // DeletePasswordResp returns the response from deleting a password.
125
+ message DeletePasswordResp {
126
+ bool not_found = 1;
127
+ }
128
+
129
+ // ListPasswordReq is a request to enumerate passwords.
130
+ message ListPasswordReq {}
131
+
132
+ // ListPasswordResp returns a list of passwords.
133
+ message ListPasswordResp {
134
+ repeated Password passwords = 1;
135
+ }
136
+
137
+ // Connector is a strategy used by Dex for authenticating a user against another identity provider
138
+ message Connector {
139
+ string id = 1;
140
+ string type = 2;
141
+ string name = 3;
142
+ bytes config = 4;
143
+ }
144
+
145
+ // CreateConnectorReq is a request to make a connector.
146
+ message CreateConnectorReq {
147
+ Connector connector = 1;
148
+ }
149
+
150
+ // CreateConnectorResp returns the response from creating a connector.
151
+ message CreateConnectorResp {
152
+ bool already_exists = 1;
153
+ }
154
+
155
+ // UpdateConnectorReq is a request to modify an existing connector.
156
+ message UpdateConnectorReq {
157
+ // The id used to lookup the connector. This field cannot be modified
158
+ string id = 1;
159
+ string new_type = 2;
160
+ string new_name = 3;
161
+ bytes new_config = 4;
162
+ }
163
+
164
+ // UpdateConnectorResp returns the response from modifying an existing connector.
165
+ message UpdateConnectorResp {
166
+ bool not_found = 1;
167
+ }
168
+
169
+ // DeleteConnectorReq is a request to delete a connector.
170
+ message DeleteConnectorReq {
171
+ string id = 1;
172
+ }
173
+
174
+ // DeleteConnectorResp returns the response from deleting a connector.
175
+ message DeleteConnectorResp {
176
+ bool not_found = 1;
177
+ }
178
+
179
+ // ListConnectorReq is a request to enumerate connectors.
180
+ message ListConnectorReq {}
181
+
182
+ // ListConnectorResp returns a list of connectors.
183
+ message ListConnectorResp {
184
+ repeated Connector connectors = 1;
185
+ }
186
+
187
+ // VersionReq is a request to fetch version info.
188
+ message VersionReq {}
189
+
190
+ // VersionResp holds the version info of components.
191
+ message VersionResp {
192
+ // Semantic version of the server.
193
+ string server = 1;
194
+ // Numeric version of the API. It increases every time a new call is added to the API.
195
+ // Clients should use this info to determine if the server supports specific features.
196
+ int32 api = 2;
197
+ }
198
+
199
+ // DiscoveryReq is a request to fetch discover information.
200
+ message DiscoveryReq {}
201
+
202
+ //DiscoverResp holds the version oidc disovery info.
203
+ message DiscoveryResp {
204
+ string issuer = 1;
205
+ string authorization_endpoint = 2;
206
+ string token_endpoint = 3;
207
+ string jwks_uri = 4;
208
+ string userinfo_endpoint = 5;
209
+ string device_authorization_endpoint = 6;
210
+ string introspection_endpoint = 7;
211
+ repeated string grant_types_supported = 8;
212
+ repeated string response_types_supported = 9;
213
+ repeated string subject_types_supported = 10;
214
+ repeated string id_token_signing_alg_values_supported = 11;
215
+ repeated string code_challenge_methods_supported = 12;
216
+ repeated string scopes_supported = 13;
217
+ repeated string token_endpoint_auth_methods_supported = 14;
218
+ repeated string claims_supported = 15;
219
+ }
220
+
221
+ // RefreshTokenRef contains the metadata for a refresh token that is managed by the storage.
222
+ message RefreshTokenRef {
223
+ // ID of the refresh token.
224
+ string id = 1;
225
+ string client_id = 2;
226
+ int64 created_at = 5;
227
+ int64 last_used = 6;
228
+ }
229
+
230
+ // ListRefreshReq is a request to enumerate the refresh tokens of a user.
231
+ message ListRefreshReq {
232
+ // The "sub" claim returned in the ID Token.
233
+ string user_id = 1;
234
+ }
235
+
236
+ // ListRefreshResp returns a list of refresh tokens for a user.
237
+ message ListRefreshResp {
238
+ repeated RefreshTokenRef refresh_tokens = 1;
239
+ }
240
+
241
+ // RevokeRefreshReq is a request to revoke the refresh token of the user-client pair.
242
+ message RevokeRefreshReq {
243
+ // The "sub" claim returned in the ID Token.
244
+ string user_id = 1;
245
+ string client_id = 2;
246
+ }
247
+
248
+ // RevokeRefreshResp determines if the refresh token is revoked successfully.
249
+ message RevokeRefreshResp {
250
+ // Set to true is refresh token was not found and token could not be revoked.
251
+ bool not_found = 1;
252
+ }
253
+
254
+ message VerifyPasswordReq {
255
+ string email = 1;
256
+ string password = 2;
257
+ }
258
+
259
+ message VerifyPasswordResp {
260
+ bool verified = 1;
261
+ bool not_found = 2;
262
+ }
263
+
264
+ // Dex represents the dex gRPC service.
265
+ service Dex {
266
+ // GetClient gets a client.
267
+ rpc GetClient(GetClientReq) returns (GetClientResp) {};
268
+ // CreateClient creates a client.
269
+ rpc CreateClient(CreateClientReq) returns (CreateClientResp) {};
270
+ // UpdateClient updates an existing client
271
+ rpc UpdateClient(UpdateClientReq) returns (UpdateClientResp) {};
272
+ // DeleteClient deletes the provided client.
273
+ rpc DeleteClient(DeleteClientReq) returns (DeleteClientResp) {};
274
+ // ListClients lists all client entries.
275
+ rpc ListClients(ListClientReq) returns (ListClientResp) {};
276
+ // CreatePassword creates a password.
277
+ rpc CreatePassword(CreatePasswordReq) returns (CreatePasswordResp) {};
278
+ // UpdatePassword modifies existing password.
279
+ rpc UpdatePassword(UpdatePasswordReq) returns (UpdatePasswordResp) {};
280
+ // DeletePassword deletes the password.
281
+ rpc DeletePassword(DeletePasswordReq) returns (DeletePasswordResp) {};
282
+ // ListPassword lists all password entries.
283
+ rpc ListPasswords(ListPasswordReq) returns (ListPasswordResp) {};
284
+ // CreateConnector creates a connector.
285
+ rpc CreateConnector(CreateConnectorReq) returns (CreateConnectorResp) {};
286
+ // UpdateConnector modifies existing connector.
287
+ rpc UpdateConnector(UpdateConnectorReq) returns (UpdateConnectorResp) {};
288
+ // DeleteConnector deletes the connector.
289
+ rpc DeleteConnector(DeleteConnectorReq) returns (DeleteConnectorResp) {};
290
+ // ListConnectors lists all connector entries.
291
+ rpc ListConnectors(ListConnectorReq) returns (ListConnectorResp) {};
292
+ // GetVersion returns version information of the server.
293
+ rpc GetVersion(VersionReq) returns (VersionResp) {};
294
+ // GetDiscovery returns discovery information of the server.
295
+ rpc GetDiscovery(DiscoveryReq) returns (DiscoveryResp) {};
296
+ // ListRefresh lists all the refresh token entries for a particular user.
297
+ rpc ListRefresh(ListRefreshReq) returns (ListRefreshResp) {};
298
+ // RevokeRefresh revokes the refresh token for the provided user-client pair.
299
+ //
300
+ // Note that each user-client pair can have only one refresh token at a time.
301
+ rpc RevokeRefresh(RevokeRefreshReq) returns (RevokeRefreshResp) {};
302
+ // VerifyPassword returns whether a password matches a hash for a specific email or not.
303
+ rpc VerifyPassword(VerifyPasswordReq) returns (VerifyPasswordResp) {};
304
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Lightweight Dex OIDC client for PRD #380, Task 2.3.
3
+ *
4
+ * Three pure utility functions using only node:http/node:https.
5
+ * No external dependencies. Dex is trusted in-cluster, so ID tokens
6
+ * are decoded without signature verification.
7
+ */
8
+ import type { DexConfig } from './types';
9
+ /**
10
+ * Build the Dex OIDC authorization URL for the browser redirect.
11
+ *
12
+ * Uses dexConfig.issuerUrl (the external Dex URL) because this URL
13
+ * is followed by the user's browser, not the MCP server.
14
+ */
15
+ export declare function buildAuthorizeUrl(dexConfig: DexConfig, params: {
16
+ redirectUri: string;
17
+ state: string;
18
+ scope?: string;
19
+ }): string;
20
+ /**
21
+ * Exchange a Dex authorization code for tokens.
22
+ *
23
+ * Uses dexConfig.tokenEndpoint (the in-cluster URL) for server-to-server
24
+ * communication. Posts application/x-www-form-urlencoded with client credentials.
25
+ */
26
+ export declare function exchangeDexCode(dexConfig: DexConfig, code: string, redirectUri: string): Promise<{
27
+ idToken: string;
28
+ accessToken: string;
29
+ }>;
30
+ /**
31
+ * Decode a Dex ID token payload without signature verification.
32
+ *
33
+ * Dex is trusted in-cluster — the token was received directly from
34
+ * Dex's token endpoint over the internal network. No JWKS needed.
35
+ */
36
+ export declare function parseIdToken(idToken: string): {
37
+ sub: string;
38
+ email?: string;
39
+ groups?: string[];
40
+ };
41
+ //# sourceMappingURL=dex-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dex-client.d.ts","sourceRoot":"","sources":["../../../src/interfaces/oauth/dex-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE;IACN,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,MAAM,CASR;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAqDnD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CA0BA"}
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ /**
3
+ * Lightweight Dex OIDC client for PRD #380, Task 2.3.
4
+ *
5
+ * Three pure utility functions using only node:http/node:https.
6
+ * No external dependencies. Dex is trusted in-cluster, so ID tokens
7
+ * are decoded without signature verification.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.buildAuthorizeUrl = buildAuthorizeUrl;
44
+ exports.exchangeDexCode = exchangeDexCode;
45
+ exports.parseIdToken = parseIdToken;
46
+ const http = __importStar(require("node:http"));
47
+ const https = __importStar(require("node:https"));
48
+ /**
49
+ * Build the Dex OIDC authorization URL for the browser redirect.
50
+ *
51
+ * Uses dexConfig.issuerUrl (the external Dex URL) because this URL
52
+ * is followed by the user's browser, not the MCP server.
53
+ */
54
+ function buildAuthorizeUrl(dexConfig, params) {
55
+ const base = dexConfig.issuerUrl.replace(/\/$/, '');
56
+ const url = new URL(`${base}/auth`);
57
+ url.searchParams.set('client_id', dexConfig.clientId);
58
+ url.searchParams.set('redirect_uri', params.redirectUri);
59
+ url.searchParams.set('response_type', 'code');
60
+ url.searchParams.set('scope', params.scope ?? 'openid email profile groups');
61
+ url.searchParams.set('state', params.state);
62
+ return url.toString();
63
+ }
64
+ /**
65
+ * Exchange a Dex authorization code for tokens.
66
+ *
67
+ * Uses dexConfig.tokenEndpoint (the in-cluster URL) for server-to-server
68
+ * communication. Posts application/x-www-form-urlencoded with client credentials.
69
+ */
70
+ async function exchangeDexCode(dexConfig, code, redirectUri) {
71
+ const body = new URLSearchParams({
72
+ grant_type: 'authorization_code',
73
+ code,
74
+ redirect_uri: redirectUri,
75
+ client_id: dexConfig.clientId,
76
+ client_secret: dexConfig.clientSecret,
77
+ }).toString();
78
+ const tokenUrl = new URL(dexConfig.tokenEndpoint);
79
+ const transport = tokenUrl.protocol === 'https:' ? https : http;
80
+ const response = await new Promise((resolve, reject) => {
81
+ const req = transport.request(tokenUrl, {
82
+ method: 'POST',
83
+ headers: {
84
+ 'Content-Type': 'application/x-www-form-urlencoded',
85
+ 'Content-Length': Buffer.byteLength(body).toString(),
86
+ },
87
+ }, (res) => {
88
+ let data = '';
89
+ res.on('data', (chunk) => { data += chunk.toString(); });
90
+ res.on('end', () => {
91
+ resolve({ statusCode: res.statusCode ?? 0, body: data });
92
+ });
93
+ });
94
+ req.setTimeout(10_000, () => {
95
+ req.destroy(new Error('Dex token exchange timed out'));
96
+ });
97
+ req.on('error', reject);
98
+ req.write(body);
99
+ req.end();
100
+ });
101
+ if (response.statusCode !== 200) {
102
+ throw new Error(`Dex token exchange failed (HTTP ${response.statusCode}): ${response.body}`);
103
+ }
104
+ const parsed = JSON.parse(response.body);
105
+ if (!parsed.id_token) {
106
+ throw new Error('Dex token response missing id_token');
107
+ }
108
+ return {
109
+ idToken: parsed.id_token,
110
+ accessToken: parsed.access_token ?? '',
111
+ };
112
+ }
113
+ /**
114
+ * Decode a Dex ID token payload without signature verification.
115
+ *
116
+ * Dex is trusted in-cluster — the token was received directly from
117
+ * Dex's token endpoint over the internal network. No JWKS needed.
118
+ */
119
+ function parseIdToken(idToken) {
120
+ const parts = idToken.split('.');
121
+ if (parts.length !== 3) {
122
+ throw new Error('Invalid JWT format — expected 3 segments');
123
+ }
124
+ const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf8'));
125
+ const now = Math.floor(Date.now() / 1000);
126
+ if (typeof payload.exp !== 'number' || payload.exp <= now) {
127
+ throw new Error('ID token is expired or missing exp claim');
128
+ }
129
+ if (typeof payload.sub !== 'string' || payload.sub.length === 0) {
130
+ throw new Error('ID token missing sub claim');
131
+ }
132
+ if (payload.email !== undefined && typeof payload.email !== 'string') {
133
+ throw new Error('ID token email claim must be a string');
134
+ }
135
+ if (payload.groups !== undefined) {
136
+ if (!Array.isArray(payload.groups) || !payload.groups.every((g) => typeof g === 'string')) {
137
+ throw new Error('ID token groups claim must be an array of strings');
138
+ }
139
+ }
140
+ return {
141
+ sub: payload.sub,
142
+ email: payload.email,
143
+ groups: payload.groups,
144
+ };
145
+ }
@@ -0,0 +1,6 @@
1
+ export type { UserIdentity, AuthResult, JwtClaims } from './types';
2
+ export { signJwt, verifyJwt, getJwtSecret } from './jwt';
3
+ export { checkBearerAuth, isAuthEnabled } from './middleware';
4
+ export { DotAIOAuthProvider } from './provider';
5
+ export { createUser, listUsers, deleteUser, type UserResult, type UserEntry, } from './user-management';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/interfaces/oauth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EACL,UAAU,EACV,SAAS,EACT,UAAU,EACV,KAAK,UAAU,EACf,KAAK,SAAS,GACf,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteUser = exports.listUsers = exports.createUser = exports.DotAIOAuthProvider = exports.isAuthEnabled = exports.checkBearerAuth = exports.getJwtSecret = exports.verifyJwt = exports.signJwt = void 0;
4
+ var jwt_1 = require("./jwt");
5
+ Object.defineProperty(exports, "signJwt", { enumerable: true, get: function () { return jwt_1.signJwt; } });
6
+ Object.defineProperty(exports, "verifyJwt", { enumerable: true, get: function () { return jwt_1.verifyJwt; } });
7
+ Object.defineProperty(exports, "getJwtSecret", { enumerable: true, get: function () { return jwt_1.getJwtSecret; } });
8
+ var middleware_1 = require("./middleware");
9
+ Object.defineProperty(exports, "checkBearerAuth", { enumerable: true, get: function () { return middleware_1.checkBearerAuth; } });
10
+ Object.defineProperty(exports, "isAuthEnabled", { enumerable: true, get: function () { return middleware_1.isAuthEnabled; } });
11
+ var provider_1 = require("./provider");
12
+ Object.defineProperty(exports, "DotAIOAuthProvider", { enumerable: true, get: function () { return provider_1.DotAIOAuthProvider; } });
13
+ var user_management_1 = require("./user-management");
14
+ Object.defineProperty(exports, "createUser", { enumerable: true, get: function () { return user_management_1.createUser; } });
15
+ Object.defineProperty(exports, "listUsers", { enumerable: true, get: function () { return user_management_1.listUsers; } });
16
+ Object.defineProperty(exports, "deleteUser", { enumerable: true, get: function () { return user_management_1.deleteUser; } });
@@ -0,0 +1,37 @@
1
+ /**
2
+ * JWT signing and verification using node:crypto HMAC-SHA256.
3
+ *
4
+ * No external libraries — implements the minimal JWT subset needed
5
+ * for dot-ai access tokens (HS256 only).
6
+ */
7
+ import type { JwtClaims } from './types';
8
+ /**
9
+ * Returns the JWT signing secret.
10
+ * Uses DOT_AI_JWT_SECRET env var if set, otherwise generates
11
+ * a random 32-byte hex secret cached for the process lifetime.
12
+ */
13
+ export declare function getJwtSecret(): string;
14
+ /**
15
+ * Reset the cached secret. Only for testing.
16
+ * @internal
17
+ */
18
+ export declare function _resetCachedSecret(): void;
19
+ /**
20
+ * Sign a JWT with HMAC-SHA256.
21
+ *
22
+ * @param claims - The JWT payload claims
23
+ * @param secret - The signing secret
24
+ * @returns Encoded JWT string (header.payload.signature)
25
+ */
26
+ export declare function signJwt(claims: JwtClaims, secret: string): string;
27
+ /**
28
+ * Verify a JWT signed with HMAC-SHA256.
29
+ *
30
+ * Performs timing-safe signature comparison and expiry check.
31
+ *
32
+ * @param token - The JWT string to verify
33
+ * @param secret - The signing secret
34
+ * @returns Decoded claims if valid, null otherwise
35
+ */
36
+ export declare function verifyJwt(token: string, secret: string): JwtClaims | null;
37
+ //# sourceMappingURL=jwt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../src/interfaces/oauth/jwt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AASzC;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,MAAM,CASrC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOjE;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAmDzE"}
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ /**
3
+ * JWT signing and verification using node:crypto HMAC-SHA256.
4
+ *
5
+ * No external libraries — implements the minimal JWT subset needed
6
+ * for dot-ai access tokens (HS256 only).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getJwtSecret = getJwtSecret;
10
+ exports._resetCachedSecret = _resetCachedSecret;
11
+ exports.signJwt = signJwt;
12
+ exports.verifyJwt = verifyJwt;
13
+ const node_crypto_1 = require("node:crypto");
14
+ const JWT_HEADER = Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64url');
15
+ /** Cached auto-generated secret (per-process). */
16
+ let cachedSecret;
17
+ /**
18
+ * Returns the JWT signing secret.
19
+ * Uses DOT_AI_JWT_SECRET env var if set, otherwise generates
20
+ * a random 32-byte hex secret cached for the process lifetime.
21
+ */
22
+ function getJwtSecret() {
23
+ const envSecret = process.env.DOT_AI_JWT_SECRET;
24
+ if (envSecret) {
25
+ return envSecret;
26
+ }
27
+ if (!cachedSecret) {
28
+ cachedSecret = (0, node_crypto_1.randomBytes)(32).toString('hex');
29
+ }
30
+ return cachedSecret;
31
+ }
32
+ /**
33
+ * Reset the cached secret. Only for testing.
34
+ * @internal
35
+ */
36
+ function _resetCachedSecret() {
37
+ cachedSecret = undefined;
38
+ }
39
+ /**
40
+ * Sign a JWT with HMAC-SHA256.
41
+ *
42
+ * @param claims - The JWT payload claims
43
+ * @param secret - The signing secret
44
+ * @returns Encoded JWT string (header.payload.signature)
45
+ */
46
+ function signJwt(claims, secret) {
47
+ const payload = Buffer.from(JSON.stringify(claims)).toString('base64url');
48
+ const data = `${JWT_HEADER}.${payload}`;
49
+ const signature = (0, node_crypto_1.createHmac)('sha256', secret)
50
+ .update(data)
51
+ .digest('base64url');
52
+ return `${data}.${signature}`;
53
+ }
54
+ /**
55
+ * Verify a JWT signed with HMAC-SHA256.
56
+ *
57
+ * Performs timing-safe signature comparison and expiry check.
58
+ *
59
+ * @param token - The JWT string to verify
60
+ * @param secret - The signing secret
61
+ * @returns Decoded claims if valid, null otherwise
62
+ */
63
+ function verifyJwt(token, secret) {
64
+ const parts = token.split('.');
65
+ if (parts.length !== 3) {
66
+ return null;
67
+ }
68
+ const [header, payload, signature] = parts;
69
+ // Recompute expected signature
70
+ const data = `${header}.${payload}`;
71
+ const expectedSignature = (0, node_crypto_1.createHmac)('sha256', secret)
72
+ .update(data)
73
+ .digest('base64url');
74
+ // Timing-safe comparison
75
+ const sigBuffer = Buffer.from(signature, 'base64url');
76
+ const expectedBuffer = Buffer.from(expectedSignature, 'base64url');
77
+ if (sigBuffer.length !== expectedBuffer.length) {
78
+ // Dummy comparison to maintain constant time
79
+ (0, node_crypto_1.timingSafeEqual)(expectedBuffer, expectedBuffer);
80
+ return null;
81
+ }
82
+ if (!(0, node_crypto_1.timingSafeEqual)(sigBuffer, expectedBuffer)) {
83
+ return null;
84
+ }
85
+ // Decode and validate claims
86
+ let claims;
87
+ try {
88
+ claims = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
89
+ }
90
+ catch {
91
+ return null;
92
+ }
93
+ // Validate identity claims
94
+ if (typeof claims.sub !== 'string' || claims.sub.length === 0) {
95
+ return null;
96
+ }
97
+ if (claims.groups !== undefined && !Array.isArray(claims.groups)) {
98
+ return null;
99
+ }
100
+ // Check expiration (strict: exp === now is treated as expired)
101
+ const now = Math.floor(Date.now() / 1000);
102
+ if (typeof claims.exp !== 'number' || claims.exp <= now) {
103
+ return null;
104
+ }
105
+ return claims;
106
+ }