acuity-mcp-server 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/README.md +541 -0
- package/dist/auth/device-flow.d.ts +46 -0
- package/dist/auth/device-flow.d.ts.map +1 -0
- package/dist/auth/device-flow.js +141 -0
- package/dist/auth/device-flow.js.map +1 -0
- package/dist/auth/http-auth.d.ts +25 -0
- package/dist/auth/http-auth.d.ts.map +1 -0
- package/dist/auth/http-auth.js +101 -0
- package/dist/auth/http-auth.js.map +1 -0
- package/dist/auth/jwt-validator.d.ts +20 -0
- package/dist/auth/jwt-validator.d.ts.map +1 -0
- package/dist/auth/jwt-validator.js +83 -0
- package/dist/auth/jwt-validator.js.map +1 -0
- package/dist/auth/token-storage.d.ts +88 -0
- package/dist/auth/token-storage.d.ts.map +1 -0
- package/dist/auth/token-storage.js +273 -0
- package/dist/auth/token-storage.js.map +1 -0
- package/dist/clients/hasura-client.d.ts +33 -0
- package/dist/clients/hasura-client.d.ts.map +1 -0
- package/dist/clients/hasura-client.js +79 -0
- package/dist/clients/hasura-client.js.map +1 -0
- package/dist/config/environments.d.ts +51 -0
- package/dist/config/environments.d.ts.map +1 -0
- package/dist/config/environments.js +183 -0
- package/dist/config/environments.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +593 -0
- package/dist/index.js.map +1 -0
- package/dist/server/http-server.d.ts +14 -0
- package/dist/server/http-server.d.ts.map +1 -0
- package/dist/server/http-server.js +167 -0
- package/dist/server/http-server.js.map +1 -0
- package/dist/server/mcp-core.d.ts +12 -0
- package/dist/server/mcp-core.d.ts.map +1 -0
- package/dist/server/mcp-core.js +200 -0
- package/dist/server/mcp-core.js.map +1 -0
- package/dist/tools/acuity-init.d.ts +84 -0
- package/dist/tools/acuity-init.d.ts.map +1 -0
- package/dist/tools/acuity-init.js +239 -0
- package/dist/tools/acuity-init.js.map +1 -0
- package/dist/tools/get-dashboard-summary.d.ts +96 -0
- package/dist/tools/get-dashboard-summary.d.ts.map +1 -0
- package/dist/tools/get-dashboard-summary.js +264 -0
- package/dist/tools/get-dashboard-summary.js.map +1 -0
- package/dist/tools/get-issue.d.ts +62 -0
- package/dist/tools/get-issue.d.ts.map +1 -0
- package/dist/tools/get-issue.js +150 -0
- package/dist/tools/get-issue.js.map +1 -0
- package/dist/tools/get-lesson-learned.d.ts +53 -0
- package/dist/tools/get-lesson-learned.d.ts.map +1 -0
- package/dist/tools/get-lesson-learned.js +117 -0
- package/dist/tools/get-lesson-learned.js.map +1 -0
- package/dist/tools/get-lookup-values.d.ts +41 -0
- package/dist/tools/get-lookup-values.d.ts.map +1 -0
- package/dist/tools/get-lookup-values.js +127 -0
- package/dist/tools/get-lookup-values.js.map +1 -0
- package/dist/tools/get-project.d.ts +131 -0
- package/dist/tools/get-project.d.ts.map +1 -0
- package/dist/tools/get-project.js +340 -0
- package/dist/tools/get-project.js.map +1 -0
- package/dist/tools/get-risk.d.ts +65 -0
- package/dist/tools/get-risk.d.ts.map +1 -0
- package/dist/tools/get-risk.js +173 -0
- package/dist/tools/get-risk.js.map +1 -0
- package/dist/tools/get-status-reports.d.ts +46 -0
- package/dist/tools/get-status-reports.d.ts.map +1 -0
- package/dist/tools/get-status-reports.js +151 -0
- package/dist/tools/get-status-reports.js.map +1 -0
- package/dist/tools/init-auth.d.ts +47 -0
- package/dist/tools/init-auth.d.ts.map +1 -0
- package/dist/tools/init-auth.js +213 -0
- package/dist/tools/init-auth.js.map +1 -0
- package/dist/tools/list-issues.d.ts +134 -0
- package/dist/tools/list-issues.d.ts.map +1 -0
- package/dist/tools/list-issues.js +285 -0
- package/dist/tools/list-issues.js.map +1 -0
- package/dist/tools/list-lessons-learned.d.ts +79 -0
- package/dist/tools/list-lessons-learned.d.ts.map +1 -0
- package/dist/tools/list-lessons-learned.js +155 -0
- package/dist/tools/list-lessons-learned.js.map +1 -0
- package/dist/tools/list-projects.d.ts +200 -0
- package/dist/tools/list-projects.d.ts.map +1 -0
- package/dist/tools/list-projects.js +396 -0
- package/dist/tools/list-projects.js.map +1 -0
- package/dist/tools/list-risks.d.ts +166 -0
- package/dist/tools/list-risks.d.ts.map +1 -0
- package/dist/tools/list-risks.js +356 -0
- package/dist/tools/list-risks.js.map +1 -0
- package/dist/tools/search-projects.d.ts +90 -0
- package/dist/tools/search-projects.d.ts.map +1 -0
- package/dist/tools/search-projects.js +191 -0
- package/dist/tools/search-projects.js.map +1 -0
- package/dist/utils/formatters.d.ts +12 -0
- package/dist/utils/formatters.d.ts.map +1 -0
- package/dist/utils/formatters.js +28 -0
- package/dist/utils/formatters.js.map +1 -0
- package/openapi.yaml +194 -0
- package/package.json +68 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 2.0 Device Authorization Flow for Auth0
|
|
3
|
+
*
|
|
4
|
+
* Implements the Device Code flow for CLI/MCP authentication
|
|
5
|
+
* Reference: https://auth0.com/docs/get-started/authentication-and-authorization-flow/device-authorization-flow
|
|
6
|
+
*/
|
|
7
|
+
import open from 'open';
|
|
8
|
+
/**
|
|
9
|
+
* Request a device code from Auth0
|
|
10
|
+
*/
|
|
11
|
+
export async function requestDeviceCode(config) {
|
|
12
|
+
const url = `https://${config.domain}/oauth/device/code`;
|
|
13
|
+
const body = new URLSearchParams({
|
|
14
|
+
client_id: config.clientId,
|
|
15
|
+
scope: config.scope || 'openid profile email offline_access',
|
|
16
|
+
});
|
|
17
|
+
if (config.audience) {
|
|
18
|
+
body.append('audience', config.audience);
|
|
19
|
+
}
|
|
20
|
+
const response = await fetch(url, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
24
|
+
},
|
|
25
|
+
body: body.toString(),
|
|
26
|
+
});
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
const error = await response.json().catch(() => ({}));
|
|
29
|
+
throw new Error(`Failed to get device code: ${error.error_description || response.statusText}`);
|
|
30
|
+
}
|
|
31
|
+
return response.json();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Poll for access token
|
|
35
|
+
* Returns token when user completes authorization, or throws on timeout/error
|
|
36
|
+
*/
|
|
37
|
+
export async function pollForToken(config, deviceCode, interval, expiresIn, onPoll) {
|
|
38
|
+
const url = `https://${config.domain}/oauth/token`;
|
|
39
|
+
const startTime = Date.now();
|
|
40
|
+
const timeout = expiresIn * 1000;
|
|
41
|
+
while (Date.now() - startTime < timeout) {
|
|
42
|
+
// Wait for the specified interval before polling
|
|
43
|
+
await sleep(interval * 1000);
|
|
44
|
+
if (onPoll) {
|
|
45
|
+
onPoll();
|
|
46
|
+
}
|
|
47
|
+
const body = new URLSearchParams({
|
|
48
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
49
|
+
device_code: deviceCode,
|
|
50
|
+
client_id: config.clientId,
|
|
51
|
+
});
|
|
52
|
+
const response = await fetch(url, {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
headers: {
|
|
55
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
56
|
+
},
|
|
57
|
+
body: body.toString(),
|
|
58
|
+
});
|
|
59
|
+
const data = await response.json();
|
|
60
|
+
if (response.ok) {
|
|
61
|
+
return data;
|
|
62
|
+
}
|
|
63
|
+
// Handle expected errors during polling
|
|
64
|
+
switch (data.error) {
|
|
65
|
+
case 'authorization_pending':
|
|
66
|
+
// User hasn't authorized yet, continue polling
|
|
67
|
+
continue;
|
|
68
|
+
case 'slow_down':
|
|
69
|
+
// Increase polling interval
|
|
70
|
+
interval += 5;
|
|
71
|
+
continue;
|
|
72
|
+
case 'expired_token':
|
|
73
|
+
throw new Error('Device code expired. Please try again.');
|
|
74
|
+
case 'access_denied':
|
|
75
|
+
throw new Error('Authorization was denied by the user.');
|
|
76
|
+
default:
|
|
77
|
+
throw new Error(`Token request failed: ${data.error_description || data.error || 'Unknown error'}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
throw new Error('Authorization timed out. Please try again.');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Refresh an access token using a refresh token
|
|
84
|
+
*/
|
|
85
|
+
export async function refreshAccessToken(config, refreshToken) {
|
|
86
|
+
const url = `https://${config.domain}/oauth/token`;
|
|
87
|
+
const body = new URLSearchParams({
|
|
88
|
+
grant_type: 'refresh_token',
|
|
89
|
+
client_id: config.clientId,
|
|
90
|
+
refresh_token: refreshToken,
|
|
91
|
+
});
|
|
92
|
+
const response = await fetch(url, {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
headers: {
|
|
95
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
96
|
+
},
|
|
97
|
+
body: body.toString(),
|
|
98
|
+
});
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
const error = await response.json().catch(() => ({}));
|
|
101
|
+
throw new Error(`Failed to refresh token: ${error.error_description || response.statusText}`);
|
|
102
|
+
}
|
|
103
|
+
return response.json();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Run the complete Device Authorization Flow
|
|
107
|
+
*/
|
|
108
|
+
export async function runDeviceFlow(config) {
|
|
109
|
+
// Step 1: Request device code
|
|
110
|
+
console.error('\n[Auth] Initiating Device Authorization Flow...\n');
|
|
111
|
+
const deviceCodeResponse = await requestDeviceCode(config);
|
|
112
|
+
// Step 2: Display instructions to user
|
|
113
|
+
console.error('To authorize this device, please:');
|
|
114
|
+
console.error(`\n 1. Visit: ${deviceCodeResponse.verification_uri}`);
|
|
115
|
+
console.error(` 2. Enter code: ${deviceCodeResponse.user_code}\n`);
|
|
116
|
+
console.error(`Or open this URL directly: ${deviceCodeResponse.verification_uri_complete}\n`);
|
|
117
|
+
// Step 3: Open browser automatically
|
|
118
|
+
console.error('[Auth] Opening browser...\n');
|
|
119
|
+
try {
|
|
120
|
+
await open(deviceCodeResponse.verification_uri_complete);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
console.error('[Auth] Could not open browser automatically. Please visit the URL manually.\n');
|
|
124
|
+
}
|
|
125
|
+
// Step 4: Poll for token
|
|
126
|
+
console.error('[Auth] Waiting for authorization...');
|
|
127
|
+
let dots = 0;
|
|
128
|
+
const token = await pollForToken(config, deviceCodeResponse.device_code, deviceCodeResponse.interval, deviceCodeResponse.expires_in, () => {
|
|
129
|
+
dots = (dots + 1) % 4;
|
|
130
|
+
process.stderr.write(`\r[Auth] Waiting for authorization${'.'.repeat(dots)}${' '.repeat(3 - dots)}`);
|
|
131
|
+
});
|
|
132
|
+
console.error('\n\n[Auth] Authorization successful!\n');
|
|
133
|
+
return token;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Helper: Sleep for specified milliseconds
|
|
137
|
+
*/
|
|
138
|
+
function sleep(ms) {
|
|
139
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=device-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-flow.js","sourceRoot":"","sources":["../../src/auth/device-flow.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AAgCxB;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAwB;IAC9D,MAAM,GAAG,GAAG,WAAW,MAAM,CAAC,MAAM,oBAAoB,CAAC;IAEzD,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;QAC/B,SAAS,EAAE,MAAM,CAAC,QAAQ;QAC1B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,qCAAqC;KAC7D,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,mCAAmC;SACpD;QACD,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;KACtB,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAuB,CAAC;QAC5E,MAAM,IAAI,KAAK,CAAC,8BAA8B,KAAK,CAAC,iBAAiB,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAiC,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAwB,EACxB,UAAkB,EAClB,QAAgB,EAChB,SAAiB,EACjB,MAAmB;IAEnB,MAAM,GAAG,GAAG,WAAW,MAAM,CAAC,MAAM,cAAc,CAAC;IACnD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IAEjC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,OAAO,EAAE,CAAC;QACxC,iDAAiD;QACjD,MAAM,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;QAE7B,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,EAAE,CAAC;QACX,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;YAC/B,UAAU,EAAE,8CAA8C;YAC1D,WAAW,EAAE,UAAU;YACvB,SAAS,EAAE,MAAM,CAAC,QAAQ;SAC3B,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,mCAAmC;aACpD;YACD,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;SACtB,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA0C,CAAC;QAE3E,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,OAAO,IAAqB,CAAC;QAC/B,CAAC;QAED,wCAAwC;QACxC,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;YACnB,KAAK,uBAAuB;gBAC1B,+CAA+C;gBAC/C,SAAS;YAEX,KAAK,WAAW;gBACd,4BAA4B;gBAC5B,QAAQ,IAAI,CAAC,CAAC;gBACd,SAAS;YAEX,KAAK,eAAe;gBAClB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAE5D,KAAK,eAAe;gBAClB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAE3D;gBACE,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,KAAK,IAAI,eAAe,EAAE,CAAC,CAAC;QACxG,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;AAChE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAwB,EACxB,YAAoB;IAEpB,MAAM,GAAG,GAAG,WAAW,MAAM,CAAC,MAAM,cAAc,CAAC;IAEnD,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;QAC/B,UAAU,EAAE,eAAe;QAC3B,SAAS,EAAE,MAAM,CAAC,QAAQ;QAC1B,aAAa,EAAE,YAAY;KAC5B,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,mCAAmC;SACpD;QACD,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;KACtB,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAuB,CAAC;QAC5E,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,CAAC,iBAAiB,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAA4B,CAAC;AACnD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAwB;IAC1D,8BAA8B;IAC9B,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;IAEpE,MAAM,kBAAkB,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE3D,uCAAuC;IACvC,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACnD,OAAO,CAAC,KAAK,CAAC,iBAAiB,kBAAkB,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACtE,OAAO,CAAC,KAAK,CAAC,oBAAoB,kBAAkB,CAAC,SAAS,IAAI,CAAC,CAAC;IACpE,OAAO,CAAC,KAAK,CAAC,8BAA8B,kBAAkB,CAAC,yBAAyB,IAAI,CAAC,CAAC;IAE9F,qCAAqC;IACrC,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,KAAK,CAAC,+EAA+E,CAAC,CAAC;IACjG,CAAC;IAED,yBAAyB;IACzB,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;IAErD,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,KAAK,GAAG,MAAM,YAAY,CAC9B,MAAM,EACN,kBAAkB,CAAC,WAAW,EAC9B,kBAAkB,CAAC,QAAQ,EAC3B,kBAAkB,CAAC,UAAU,EAC7B,GAAG,EAAE;QACH,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qCAAqC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;IACvG,CAAC,CACF,CAAC;IAEF,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAExD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Authentication Middleware
|
|
3
|
+
* Validates OAuth 2.0 Bearer tokens for HTTP requests
|
|
4
|
+
*/
|
|
5
|
+
import { Request, Response, NextFunction } from 'express';
|
|
6
|
+
/**
|
|
7
|
+
* Extended Request type with authenticated user info
|
|
8
|
+
*/
|
|
9
|
+
export interface AuthenticatedRequest extends Request {
|
|
10
|
+
userEmail: string;
|
|
11
|
+
userToken: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Express middleware to validate OAuth 2.0 Bearer tokens
|
|
15
|
+
*
|
|
16
|
+
* Extracts JWT from Authorization header, validates it using Auth0 JWKS,
|
|
17
|
+
* and attaches user email to the request for downstream use.
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateHttpAuth(req: Request, res: Response, next: NextFunction): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Optional middleware for endpoints that don't require auth
|
|
22
|
+
* but should use auth if provided
|
|
23
|
+
*/
|
|
24
|
+
export declare function optionalHttpAuth(req: Request, _res: Response, next: NextFunction): Promise<void>;
|
|
25
|
+
//# sourceMappingURL=http-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-auth.d.ts","sourceRoot":"","sources":["../../src/auth/http-auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAkBD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CA8Df;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAgBf"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Authentication Middleware
|
|
3
|
+
* Validates OAuth 2.0 Bearer tokens for HTTP requests
|
|
4
|
+
*/
|
|
5
|
+
import { validateJWT } from './jwt-validator.js';
|
|
6
|
+
/**
|
|
7
|
+
* Extract Bearer token from Authorization header
|
|
8
|
+
*/
|
|
9
|
+
function extractBearerToken(authHeader) {
|
|
10
|
+
if (!authHeader) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
const parts = authHeader.split(' ');
|
|
14
|
+
if (parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return parts[1];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Express middleware to validate OAuth 2.0 Bearer tokens
|
|
21
|
+
*
|
|
22
|
+
* Extracts JWT from Authorization header, validates it using Auth0 JWKS,
|
|
23
|
+
* and attaches user email to the request for downstream use.
|
|
24
|
+
*/
|
|
25
|
+
export async function validateHttpAuth(req, res, next) {
|
|
26
|
+
try {
|
|
27
|
+
// Check for API key first (simpler auth for testing/internal use)
|
|
28
|
+
const apiKey = req.headers['x-api-key'];
|
|
29
|
+
if (apiKey && process.env.MCP_API_KEY && apiKey === process.env.MCP_API_KEY) {
|
|
30
|
+
// API key auth - use configured service account email
|
|
31
|
+
const serviceEmail = process.env.MCP_SERVICE_EMAIL || 'mcp-service@acuityppm.com';
|
|
32
|
+
req.userEmail = serviceEmail;
|
|
33
|
+
req.userToken = apiKey;
|
|
34
|
+
next();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Extract Bearer token
|
|
38
|
+
const token = extractBearerToken(req.headers.authorization);
|
|
39
|
+
if (!token) {
|
|
40
|
+
res.status(401).json({
|
|
41
|
+
jsonrpc: '2.0',
|
|
42
|
+
error: {
|
|
43
|
+
code: -32001,
|
|
44
|
+
message: 'Authentication required. Provide Authorization: Bearer <token> header.'
|
|
45
|
+
},
|
|
46
|
+
id: null
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// Validate JWT and extract email
|
|
51
|
+
const { email } = await validateJWT(token);
|
|
52
|
+
if (!email) {
|
|
53
|
+
res.status(401).json({
|
|
54
|
+
jsonrpc: '2.0',
|
|
55
|
+
error: {
|
|
56
|
+
code: -32001,
|
|
57
|
+
message: 'Invalid token: could not extract user email.'
|
|
58
|
+
},
|
|
59
|
+
id: null
|
|
60
|
+
});
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Attach user info to request
|
|
64
|
+
req.userEmail = email;
|
|
65
|
+
req.userToken = token;
|
|
66
|
+
next();
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error('[HTTP Auth] Token validation failed:', error);
|
|
70
|
+
const message = error instanceof Error ? error.message : 'Token validation failed';
|
|
71
|
+
res.status(401).json({
|
|
72
|
+
jsonrpc: '2.0',
|
|
73
|
+
error: {
|
|
74
|
+
code: -32001,
|
|
75
|
+
message: `Authentication failed: ${message}`
|
|
76
|
+
},
|
|
77
|
+
id: null
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Optional middleware for endpoints that don't require auth
|
|
83
|
+
* but should use auth if provided
|
|
84
|
+
*/
|
|
85
|
+
export async function optionalHttpAuth(req, _res, next) {
|
|
86
|
+
try {
|
|
87
|
+
const token = extractBearerToken(req.headers.authorization);
|
|
88
|
+
if (token) {
|
|
89
|
+
const { email } = await validateJWT(token);
|
|
90
|
+
if (email) {
|
|
91
|
+
req.userEmail = email;
|
|
92
|
+
req.userToken = token;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Ignore auth errors for optional auth
|
|
98
|
+
}
|
|
99
|
+
next();
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=http-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-auth.js","sourceRoot":"","sources":["../../src/auth/http-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT Validator for Auth0 tokens
|
|
3
|
+
* Based on rails_api/app/lib/json_web_token.rb
|
|
4
|
+
*/
|
|
5
|
+
export interface JWTPayload {
|
|
6
|
+
email: string;
|
|
7
|
+
sub?: string;
|
|
8
|
+
aud?: string;
|
|
9
|
+
iss?: string;
|
|
10
|
+
exp?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Validates a JWT token from Auth0
|
|
14
|
+
*
|
|
15
|
+
* @param token - The JWT token string
|
|
16
|
+
* @returns Promise resolving to payload with email
|
|
17
|
+
* @throws Error if token is invalid or email is missing
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateJWT(token: string): Promise<JWTPayload>;
|
|
20
|
+
//# sourceMappingURL=jwt-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt-validator.d.ts","sourceRoot":"","sources":["../../src/auth/jwt-validator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAwCD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAkDpE"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT Validator for Auth0 tokens
|
|
3
|
+
* Based on rails_api/app/lib/json_web_token.rb
|
|
4
|
+
*/
|
|
5
|
+
import jwt from 'jsonwebtoken';
|
|
6
|
+
import jwksClient from 'jwks-rsa';
|
|
7
|
+
/**
|
|
8
|
+
* Creates a JWKS client for Auth0 public key retrieval
|
|
9
|
+
*/
|
|
10
|
+
function createJWKSClient() {
|
|
11
|
+
const managementDomain = process.env.AUTH0_MANAGEMENT_DOMAIN;
|
|
12
|
+
if (!managementDomain) {
|
|
13
|
+
throw new Error('AUTH0_MANAGEMENT_DOMAIN environment variable is required');
|
|
14
|
+
}
|
|
15
|
+
return jwksClient({
|
|
16
|
+
jwksUri: `https://${managementDomain}/.well-known/jwks.json`,
|
|
17
|
+
cache: true,
|
|
18
|
+
cacheMaxAge: 86400000, // 24 hours
|
|
19
|
+
rateLimit: true,
|
|
20
|
+
jwksRequestsPerMinute: 10
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get signing key from Auth0 JWKS
|
|
25
|
+
*/
|
|
26
|
+
function getKey(header, callback) {
|
|
27
|
+
const client = createJWKSClient();
|
|
28
|
+
client.getSigningKey(header.kid, (err, key) => {
|
|
29
|
+
if (err) {
|
|
30
|
+
callback(err);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const signingKey = key?.getPublicKey();
|
|
34
|
+
callback(null, signingKey);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Validates a JWT token from Auth0
|
|
39
|
+
*
|
|
40
|
+
* @param token - The JWT token string
|
|
41
|
+
* @returns Promise resolving to payload with email
|
|
42
|
+
* @throws Error if token is invalid or email is missing
|
|
43
|
+
*/
|
|
44
|
+
export async function validateJWT(token) {
|
|
45
|
+
const auth0Domain = process.env.REACT_APP_AUTH0_DOMAIN || process.env.AUTH0_DOMAIN;
|
|
46
|
+
const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID;
|
|
47
|
+
if (!auth0Domain) {
|
|
48
|
+
throw new Error('AUTH0_DOMAIN or REACT_APP_AUTH0_DOMAIN environment variable is required');
|
|
49
|
+
}
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
jwt.verify(token, getKey, {
|
|
52
|
+
algorithms: ['RS256', 'RS512'],
|
|
53
|
+
issuer: `https://${auth0Domain}/`,
|
|
54
|
+
audience: clientId,
|
|
55
|
+
ignoreExpiration: false
|
|
56
|
+
}, (err, decoded) => {
|
|
57
|
+
if (err) {
|
|
58
|
+
reject(new Error(`Invalid JWT token: ${err.message}`));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (!decoded || typeof decoded === 'string') {
|
|
62
|
+
reject(new Error('Invalid JWT token payload'));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
// Extract email from various possible claim locations
|
|
66
|
+
const email = decoded.email ||
|
|
67
|
+
decoded['https://acuity.com/email'] ||
|
|
68
|
+
decoded['https://acuityppm.com/email'];
|
|
69
|
+
if (!email || typeof email !== 'string') {
|
|
70
|
+
reject(new Error('Email not found in JWT token claims'));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
resolve({
|
|
74
|
+
email: email.toLowerCase(),
|
|
75
|
+
sub: decoded.sub,
|
|
76
|
+
aud: decoded.aud,
|
|
77
|
+
iss: decoded.iss,
|
|
78
|
+
exp: decoded.exp
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=jwt-validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jwt-validator.js","sourceRoot":"","sources":["../../src/auth/jwt-validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure Token Storage using System Keychain
|
|
3
|
+
*
|
|
4
|
+
* Uses keytar for cross-platform keychain access:
|
|
5
|
+
* - macOS: Keychain Access
|
|
6
|
+
* - Windows: Credential Manager
|
|
7
|
+
* - Linux: libsecret
|
|
8
|
+
*
|
|
9
|
+
* If keytar is not available (e.g., no native build tools),
|
|
10
|
+
* falls back to no-op storage and users must use USER_JWT env var.
|
|
11
|
+
*/
|
|
12
|
+
import type { TokenResponse } from './device-flow.js';
|
|
13
|
+
/**
|
|
14
|
+
* Check if keytar is available
|
|
15
|
+
*/
|
|
16
|
+
export declare function isKeytarAvailable(): Promise<boolean>;
|
|
17
|
+
/**
|
|
18
|
+
* Get the error message if keytar failed to load
|
|
19
|
+
*/
|
|
20
|
+
export declare function getKeytarLoadError(): string | null;
|
|
21
|
+
export interface PendingDeviceCode {
|
|
22
|
+
deviceCode: string;
|
|
23
|
+
userCode: string;
|
|
24
|
+
verificationUri: string;
|
|
25
|
+
interval: number;
|
|
26
|
+
expiresAt: number;
|
|
27
|
+
}
|
|
28
|
+
export interface StoredCredentials {
|
|
29
|
+
accessToken: string;
|
|
30
|
+
refreshToken?: string;
|
|
31
|
+
idToken?: string;
|
|
32
|
+
expiresAt: number;
|
|
33
|
+
email?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Save credentials to the system keychain
|
|
37
|
+
* Returns false if keytar is not available
|
|
38
|
+
*/
|
|
39
|
+
export declare function saveCredentials(credentials: StoredCredentials): Promise<boolean>;
|
|
40
|
+
/**
|
|
41
|
+
* Load credentials from the system keychain
|
|
42
|
+
* Returns null if keytar is not available or no credentials stored
|
|
43
|
+
*/
|
|
44
|
+
export declare function loadCredentials(): Promise<StoredCredentials | null>;
|
|
45
|
+
/**
|
|
46
|
+
* Clear credentials from the system keychain
|
|
47
|
+
* Returns false if keytar is not available
|
|
48
|
+
*/
|
|
49
|
+
export declare function clearCredentials(): Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* Check if credentials exist in the keychain
|
|
52
|
+
*/
|
|
53
|
+
export declare function hasCredentials(): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* Check if the stored access token is expired
|
|
56
|
+
* Returns true if expired or no credentials exist
|
|
57
|
+
*/
|
|
58
|
+
export declare function isTokenExpired(bufferSeconds?: number): Promise<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Convert TokenResponse from Device Flow to StoredCredentials
|
|
61
|
+
*/
|
|
62
|
+
export declare function tokenResponseToCredentials(token: TokenResponse, email?: string): StoredCredentials;
|
|
63
|
+
/**
|
|
64
|
+
* Get the access token, refreshing if necessary
|
|
65
|
+
* Throws if no valid token available and refresh fails
|
|
66
|
+
*/
|
|
67
|
+
export declare function getValidAccessToken(refreshFn?: (refreshToken: string) => Promise<TokenResponse>): Promise<string>;
|
|
68
|
+
/**
|
|
69
|
+
* Save pending device code during two-phase login
|
|
70
|
+
* Returns false if keytar is not available
|
|
71
|
+
*/
|
|
72
|
+
export declare function savePendingDeviceCode(pending: PendingDeviceCode): Promise<boolean>;
|
|
73
|
+
/**
|
|
74
|
+
* Load pending device code
|
|
75
|
+
* Returns null if keytar is not available or no pending code
|
|
76
|
+
*/
|
|
77
|
+
export declare function loadPendingDeviceCode(): Promise<PendingDeviceCode | null>;
|
|
78
|
+
/**
|
|
79
|
+
* Clear pending device code
|
|
80
|
+
* Returns false if keytar is not available
|
|
81
|
+
*/
|
|
82
|
+
export declare function clearPendingDeviceCode(): Promise<boolean>;
|
|
83
|
+
/**
|
|
84
|
+
* Get the ID token (JWT) for Hasura authentication, refreshing if necessary
|
|
85
|
+
* Hasura requires a JWT, not an opaque access token
|
|
86
|
+
*/
|
|
87
|
+
export declare function getValidIdToken(refreshFn?: (refreshToken: string) => Promise<TokenResponse>): Promise<string>;
|
|
88
|
+
//# sourceMappingURL=token-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-storage.d.ts","sourceRoot":"","sources":["../../src/auth/token-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA4CtD;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAG1D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAElD;AAUD,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAStF;AAED;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAezE;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAOzD;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAGvD;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,aAAa,GAAE,MAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAQjF;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,aAAa,EACpB,KAAK,CAAC,EAAE,MAAM,GACb,iBAAiB,CAUnB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,CAAC,GAC3D,OAAO,CAAC,MAAM,CAAC,CA0CjB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CASxF;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAwB/E;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO/D;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,SAAS,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,CAAC,GAC3D,OAAO,CAAC,MAAM,CAAC,CAkDjB"}
|