@aaronsb/kg-cli 0.6.1
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 +112 -0
- package/dist/api/client.d.ts +867 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +1362 -0
- package/dist/api/client.js.map +1 -0
- package/dist/cli/admin/backup.d.ts +9 -0
- package/dist/cli/admin/backup.d.ts.map +1 -0
- package/dist/cli/admin/backup.js +363 -0
- package/dist/cli/admin/backup.js.map +1 -0
- package/dist/cli/admin/index.d.ts +7 -0
- package/dist/cli/admin/index.d.ts.map +1 -0
- package/dist/cli/admin/index.js +52 -0
- package/dist/cli/admin/index.js.map +1 -0
- package/dist/cli/admin/scheduler.d.ts +7 -0
- package/dist/cli/admin/scheduler.d.ts.map +1 -0
- package/dist/cli/admin/scheduler.js +125 -0
- package/dist/cli/admin/scheduler.js.map +1 -0
- package/dist/cli/admin/status.d.ts +7 -0
- package/dist/cli/admin/status.d.ts.map +1 -0
- package/dist/cli/admin/status.js +134 -0
- package/dist/cli/admin/status.js.map +1 -0
- package/dist/cli/admin/utils.d.ts +34 -0
- package/dist/cli/admin/utils.d.ts.map +1 -0
- package/dist/cli/admin/utils.js +441 -0
- package/dist/cli/admin/utils.js.map +1 -0
- package/dist/cli/ai-config/embedding.d.ts +11 -0
- package/dist/cli/ai-config/embedding.d.ts.map +1 -0
- package/dist/cli/ai-config/embedding.js +598 -0
- package/dist/cli/ai-config/embedding.js.map +1 -0
- package/dist/cli/ai-config/extraction.d.ts +11 -0
- package/dist/cli/ai-config/extraction.d.ts.map +1 -0
- package/dist/cli/ai-config/extraction.js +206 -0
- package/dist/cli/ai-config/extraction.js.map +1 -0
- package/dist/cli/ai-config/index.d.ts +21 -0
- package/dist/cli/ai-config/index.d.ts.map +1 -0
- package/dist/cli/ai-config/index.js +27 -0
- package/dist/cli/ai-config/index.js.map +1 -0
- package/dist/cli/ai-config/keys.d.ts +11 -0
- package/dist/cli/ai-config/keys.d.ts.map +1 -0
- package/dist/cli/ai-config/keys.js +182 -0
- package/dist/cli/ai-config/keys.js.map +1 -0
- package/dist/cli/ai-config/utils.d.ts +13 -0
- package/dist/cli/ai-config/utils.d.ts.map +1 -0
- package/dist/cli/ai-config/utils.js +84 -0
- package/dist/cli/ai-config/utils.js.map +1 -0
- package/dist/cli/artifact.d.ts +8 -0
- package/dist/cli/artifact.d.ts.map +1 -0
- package/dist/cli/artifact.js +296 -0
- package/dist/cli/artifact.js.map +1 -0
- package/dist/cli/auth-admin.d.ts +11 -0
- package/dist/cli/auth-admin.d.ts.map +1 -0
- package/dist/cli/auth-admin.js +415 -0
- package/dist/cli/auth-admin.js.map +1 -0
- package/dist/cli/colors.d.ts +105 -0
- package/dist/cli/colors.d.ts.map +1 -0
- package/dist/cli/colors.js +164 -0
- package/dist/cli/colors.js.map +1 -0
- package/dist/cli/commands.d.ts +6 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +164 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/config.d.ts +6 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +694 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/curve-viz.d.ts +89 -0
- package/dist/cli/curve-viz.d.ts.map +1 -0
- package/dist/cli/curve-viz.js +228 -0
- package/dist/cli/curve-viz.js.map +1 -0
- package/dist/cli/database.d.ts +6 -0
- package/dist/cli/database.d.ts.map +1 -0
- package/dist/cli/database.js +324 -0
- package/dist/cli/database.js.map +1 -0
- package/dist/cli/document.d.ts +6 -0
- package/dist/cli/document.d.ts.map +1 -0
- package/dist/cli/document.js +458 -0
- package/dist/cli/document.js.map +1 -0
- package/dist/cli/group.d.ts +8 -0
- package/dist/cli/group.d.ts.map +1 -0
- package/dist/cli/group.js +174 -0
- package/dist/cli/group.js.map +1 -0
- package/dist/cli/health.d.ts +6 -0
- package/dist/cli/health.d.ts.map +1 -0
- package/dist/cli/health.js +34 -0
- package/dist/cli/health.js.map +1 -0
- package/dist/cli/help-formatter.d.ts +16 -0
- package/dist/cli/help-formatter.d.ts.map +1 -0
- package/dist/cli/help-formatter.js +248 -0
- package/dist/cli/help-formatter.js.map +1 -0
- package/dist/cli/help.d.ts +9 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +227 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/ingest.d.ts +6 -0
- package/dist/cli/ingest.d.ts.map +1 -0
- package/dist/cli/ingest.js +722 -0
- package/dist/cli/ingest.js.map +1 -0
- package/dist/cli/jobs.d.ts +6 -0
- package/dist/cli/jobs.d.ts.map +1 -0
- package/dist/cli/jobs.js +663 -0
- package/dist/cli/jobs.js.map +1 -0
- package/dist/cli/login.d.ts +21 -0
- package/dist/cli/login.d.ts.map +1 -0
- package/dist/cli/login.js +221 -0
- package/dist/cli/login.js.map +1 -0
- package/dist/cli/logout.d.ts +16 -0
- package/dist/cli/logout.d.ts.map +1 -0
- package/dist/cli/logout.js +141 -0
- package/dist/cli/logout.js.map +1 -0
- package/dist/cli/mcp-config.d.ts +10 -0
- package/dist/cli/mcp-config.d.ts.map +1 -0
- package/dist/cli/mcp-config.js +358 -0
- package/dist/cli/mcp-config.js.map +1 -0
- package/dist/cli/oauth.d.ts +15 -0
- package/dist/cli/oauth.d.ts.map +1 -0
- package/dist/cli/oauth.js +296 -0
- package/dist/cli/oauth.js.map +1 -0
- package/dist/cli/ontology.d.ts +6 -0
- package/dist/cli/ontology.d.ts.map +1 -0
- package/dist/cli/ontology.js +231 -0
- package/dist/cli/ontology.js.map +1 -0
- package/dist/cli/polarity.d.ts +6 -0
- package/dist/cli/polarity.d.ts.map +1 -0
- package/dist/cli/polarity.js +295 -0
- package/dist/cli/polarity.js.map +1 -0
- package/dist/cli/projection.d.ts +8 -0
- package/dist/cli/projection.d.ts.map +1 -0
- package/dist/cli/projection.js +297 -0
- package/dist/cli/projection.js.map +1 -0
- package/dist/cli/query-def.d.ts +8 -0
- package/dist/cli/query-def.d.ts.map +1 -0
- package/dist/cli/query-def.js +163 -0
- package/dist/cli/query-def.js.map +1 -0
- package/dist/cli/rbac.d.ts +12 -0
- package/dist/cli/rbac.d.ts.map +1 -0
- package/dist/cli/rbac.js +615 -0
- package/dist/cli/rbac.js.map +1 -0
- package/dist/cli/search.d.ts +6 -0
- package/dist/cli/search.d.ts.map +1 -0
- package/dist/cli/search.js +829 -0
- package/dist/cli/search.js.map +1 -0
- package/dist/cli/source.d.ts +6 -0
- package/dist/cli/source.d.ts.map +1 -0
- package/dist/cli/source.js +202 -0
- package/dist/cli/source.js.map +1 -0
- package/dist/cli/verb-router.d.ts +25 -0
- package/dist/cli/verb-router.d.ts.map +1 -0
- package/dist/cli/verb-router.js +415 -0
- package/dist/cli/verb-router.js.map +1 -0
- package/dist/cli/vocabulary/config.d.ts +7 -0
- package/dist/cli/vocabulary/config.d.ts.map +1 -0
- package/dist/cli/vocabulary/config.js +201 -0
- package/dist/cli/vocabulary/config.js.map +1 -0
- package/dist/cli/vocabulary/consolidate.d.ts +8 -0
- package/dist/cli/vocabulary/consolidate.d.ts.map +1 -0
- package/dist/cli/vocabulary/consolidate.js +192 -0
- package/dist/cli/vocabulary/consolidate.js.map +1 -0
- package/dist/cli/vocabulary/embeddings.d.ts +9 -0
- package/dist/cli/vocabulary/embeddings.d.ts.map +1 -0
- package/dist/cli/vocabulary/embeddings.js +205 -0
- package/dist/cli/vocabulary/embeddings.js.map +1 -0
- package/dist/cli/vocabulary/epistemic.d.ts +7 -0
- package/dist/cli/vocabulary/epistemic.d.ts.map +1 -0
- package/dist/cli/vocabulary/epistemic.js +315 -0
- package/dist/cli/vocabulary/epistemic.js.map +1 -0
- package/dist/cli/vocabulary/index.d.ts +7 -0
- package/dist/cli/vocabulary/index.d.ts.map +1 -0
- package/dist/cli/vocabulary/index.js +45 -0
- package/dist/cli/vocabulary/index.js.map +1 -0
- package/dist/cli/vocabulary/profiles.d.ts +7 -0
- package/dist/cli/vocabulary/profiles.d.ts.map +1 -0
- package/dist/cli/vocabulary/profiles.js +171 -0
- package/dist/cli/vocabulary/profiles.js.map +1 -0
- package/dist/cli/vocabulary/similarity.d.ts +9 -0
- package/dist/cli/vocabulary/similarity.d.ts.map +1 -0
- package/dist/cli/vocabulary/similarity.js +199 -0
- package/dist/cli/vocabulary/similarity.js.map +1 -0
- package/dist/cli/vocabulary/status.d.ts +8 -0
- package/dist/cli/vocabulary/status.d.ts.map +1 -0
- package/dist/cli/vocabulary/status.js +280 -0
- package/dist/cli/vocabulary/status.js.map +1 -0
- package/dist/cli/vocabulary/sync.d.ts +7 -0
- package/dist/cli/vocabulary/sync.d.ts.map +1 -0
- package/dist/cli/vocabulary/sync.js +111 -0
- package/dist/cli/vocabulary/sync.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/auth/auth-client.d.ts +247 -0
- package/dist/lib/auth/auth-client.d.ts.map +1 -0
- package/dist/lib/auth/auth-client.js +305 -0
- package/dist/lib/auth/auth-client.js.map +1 -0
- package/dist/lib/auth/challenge.d.ts +39 -0
- package/dist/lib/auth/challenge.d.ts.map +1 -0
- package/dist/lib/auth/challenge.js +125 -0
- package/dist/lib/auth/challenge.js.map +1 -0
- package/dist/lib/auth/client-credentials-flow.d.ts +58 -0
- package/dist/lib/auth/client-credentials-flow.d.ts.map +1 -0
- package/dist/lib/auth/client-credentials-flow.js +118 -0
- package/dist/lib/auth/client-credentials-flow.js.map +1 -0
- package/dist/lib/auth/device-flow.d.ts +75 -0
- package/dist/lib/auth/device-flow.d.ts.map +1 -0
- package/dist/lib/auth/device-flow.js +177 -0
- package/dist/lib/auth/device-flow.js.map +1 -0
- package/dist/lib/auth/index.d.ts +14 -0
- package/dist/lib/auth/index.d.ts.map +1 -0
- package/dist/lib/auth/index.js +34 -0
- package/dist/lib/auth/index.js.map +1 -0
- package/dist/lib/auth/oauth-types.d.ts +69 -0
- package/dist/lib/auth/oauth-types.d.ts.map +1 -0
- package/dist/lib/auth/oauth-types.js +10 -0
- package/dist/lib/auth/oauth-types.js.map +1 -0
- package/dist/lib/auth/oauth-utils.d.ts +51 -0
- package/dist/lib/auth/oauth-utils.d.ts.map +1 -0
- package/dist/lib/auth/oauth-utils.js +110 -0
- package/dist/lib/auth/oauth-utils.js.map +1 -0
- package/dist/lib/auth/token-manager.d.ts +87 -0
- package/dist/lib/auth/token-manager.d.ts.map +1 -0
- package/dist/lib/auth/token-manager.js +139 -0
- package/dist/lib/auth/token-manager.js.map +1 -0
- package/dist/lib/auth/token-refresh.d.ts +63 -0
- package/dist/lib/auth/token-refresh.d.ts.map +1 -0
- package/dist/lib/auth/token-refresh.js +141 -0
- package/dist/lib/auth/token-refresh.js.map +1 -0
- package/dist/lib/config.d.ts +286 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +537 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/job-stream.d.ts +53 -0
- package/dist/lib/job-stream.d.ts.map +1 -0
- package/dist/lib/job-stream.js +153 -0
- package/dist/lib/job-stream.js.map +1 -0
- package/dist/lib/mcp-allowlist.d.ts +101 -0
- package/dist/lib/mcp-allowlist.d.ts.map +1 -0
- package/dist/lib/mcp-allowlist.js +340 -0
- package/dist/lib/mcp-allowlist.js.map +1 -0
- package/dist/lib/table-example.d.ts +7 -0
- package/dist/lib/table-example.d.ts.map +1 -0
- package/dist/lib/table-example.js +105 -0
- package/dist/lib/table-example.js.map +1 -0
- package/dist/lib/table.d.ts +95 -0
- package/dist/lib/table.d.ts.map +1 -0
- package/dist/lib/table.js +263 -0
- package/dist/lib/table.js.map +1 -0
- package/dist/lib/terminal-images.d.ts +66 -0
- package/dist/lib/terminal-images.d.ts.map +1 -0
- package/dist/lib/terminal-images.js +268 -0
- package/dist/lib/terminal-images.js.map +1 -0
- package/dist/mcp/formatters.d.ts +100 -0
- package/dist/mcp/formatters.d.ts.map +1 -0
- package/dist/mcp/formatters.js +1411 -0
- package/dist/mcp/formatters.js.map +1 -0
- package/dist/mcp-server.d.ts +9 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +1810 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/types/index.d.ts +742 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/version.d.ts +10 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +13 -0
- package/dist/version.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Authentication Client
|
|
4
|
+
*
|
|
5
|
+
* HTTP client for authentication endpoints.
|
|
6
|
+
* Wraps REST API calls to /auth/* endpoints.
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AuthClient = void 0;
|
|
13
|
+
const axios_1 = __importDefault(require("axios"));
|
|
14
|
+
// Note: OAuthTokenResponse is imported from './oauth-types.js'
|
|
15
|
+
// ========== Auth Client Class ==========
|
|
16
|
+
class AuthClient {
|
|
17
|
+
constructor(baseUrl) {
|
|
18
|
+
this.client = axios_1.default.create({
|
|
19
|
+
baseURL: baseUrl,
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json'
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
// ========== Public Endpoints (No Auth) ==========
|
|
26
|
+
/**
|
|
27
|
+
* Login with username/password (OAuth2 password flow)
|
|
28
|
+
*
|
|
29
|
+
* @deprecated Use createPersonalOAuthClient() instead (ADR-054 unified OAuth)
|
|
30
|
+
* @param request Username and password
|
|
31
|
+
* @returns JWT token and user details
|
|
32
|
+
* @throws 401 if credentials invalid, 400 if validation fails
|
|
33
|
+
*/
|
|
34
|
+
async login(request) {
|
|
35
|
+
// OAuth2 password flow requires application/x-www-form-urlencoded
|
|
36
|
+
const formData = new URLSearchParams();
|
|
37
|
+
formData.append('username', request.username);
|
|
38
|
+
formData.append('password', request.password);
|
|
39
|
+
const response = await this.client.post('/auth/login', formData, {
|
|
40
|
+
headers: {
|
|
41
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
return response.data;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Create a personal OAuth client (ADR-054 - GitHub CLI-style authentication)
|
|
48
|
+
*
|
|
49
|
+
* This is the preferred authentication method for CLI tools.
|
|
50
|
+
* Flow:
|
|
51
|
+
* 1. User provides username + password
|
|
52
|
+
* 2. Server creates long-lived OAuth client credentials
|
|
53
|
+
* 3. Client stores client_id + client_secret
|
|
54
|
+
* 4. Future requests use client credentials grant
|
|
55
|
+
*
|
|
56
|
+
* @param request Username, password, and optional client name/scope
|
|
57
|
+
* @returns OAuth client credentials (client_secret shown only once!)
|
|
58
|
+
* @throws 401 if credentials invalid, 400 if validation fails
|
|
59
|
+
*/
|
|
60
|
+
async createPersonalOAuthClient(request) {
|
|
61
|
+
// OAuth endpoint requires application/x-www-form-urlencoded
|
|
62
|
+
const formData = new URLSearchParams();
|
|
63
|
+
formData.append('username', request.username);
|
|
64
|
+
formData.append('password', request.password);
|
|
65
|
+
if (request.client_name) {
|
|
66
|
+
formData.append('client_name', request.client_name);
|
|
67
|
+
}
|
|
68
|
+
if (request.scope) {
|
|
69
|
+
formData.append('scope', request.scope);
|
|
70
|
+
}
|
|
71
|
+
const response = await this.client.post('/auth/oauth/clients/personal', formData, {
|
|
72
|
+
headers: {
|
|
73
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return response.data;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get OAuth access token using client credentials grant (ADR-054)
|
|
80
|
+
*
|
|
81
|
+
* Use this after creating a personal OAuth client to get access tokens.
|
|
82
|
+
* Access tokens are short-lived and should be refreshed as needed.
|
|
83
|
+
*
|
|
84
|
+
* @param request Client credentials (client_id, client_secret)
|
|
85
|
+
* @returns OAuth access token
|
|
86
|
+
* @throws 401 if client credentials invalid
|
|
87
|
+
*/
|
|
88
|
+
async getOAuthToken(request) {
|
|
89
|
+
const formData = new URLSearchParams();
|
|
90
|
+
formData.append('grant_type', 'client_credentials');
|
|
91
|
+
formData.append('client_id', request.client_id);
|
|
92
|
+
formData.append('client_secret', request.client_secret);
|
|
93
|
+
if (request.scope) {
|
|
94
|
+
formData.append('scope', request.scope);
|
|
95
|
+
}
|
|
96
|
+
const response = await this.client.post('/auth/oauth/token', formData, {
|
|
97
|
+
headers: {
|
|
98
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return response.data;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Delete a personal OAuth client (ADR-054)
|
|
105
|
+
*
|
|
106
|
+
* Called by `kg logout` to revoke OAuth credentials.
|
|
107
|
+
* Requires authentication with a valid access token.
|
|
108
|
+
*
|
|
109
|
+
* @param token Access token for authentication
|
|
110
|
+
* @param clientId Client ID to delete
|
|
111
|
+
* @throws 401 if token invalid, 403 if not owner, 404 if client not found
|
|
112
|
+
*/
|
|
113
|
+
async deletePersonalOAuthClient(token, clientId) {
|
|
114
|
+
await this.client.delete(`/auth/oauth/clients/personal/${clientId}`, {
|
|
115
|
+
headers: {
|
|
116
|
+
Authorization: `Bearer ${token}`
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Register new user
|
|
122
|
+
*
|
|
123
|
+
* Note: In production, this endpoint may be restricted to admins.
|
|
124
|
+
* For now, it's public to allow initial user creation.
|
|
125
|
+
*
|
|
126
|
+
* @param request User creation details
|
|
127
|
+
* @returns Created user details
|
|
128
|
+
* @throws 400 if validation fails, 409 if username taken
|
|
129
|
+
*/
|
|
130
|
+
async register(request) {
|
|
131
|
+
const response = await this.client.post('/auth/register', request);
|
|
132
|
+
return response.data;
|
|
133
|
+
}
|
|
134
|
+
// ========== Authenticated Endpoints (JWT Required) ==========
|
|
135
|
+
/**
|
|
136
|
+
* Validate current token and get user profile
|
|
137
|
+
*
|
|
138
|
+
* @param token JWT access token
|
|
139
|
+
* @returns Current user details
|
|
140
|
+
* @throws 401 if token invalid/expired
|
|
141
|
+
*/
|
|
142
|
+
async validateToken(token) {
|
|
143
|
+
const response = await this.client.get('/auth/me', {
|
|
144
|
+
headers: {
|
|
145
|
+
Authorization: `Bearer ${token}`
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
return response.data;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Update current user profile
|
|
152
|
+
*
|
|
153
|
+
* @param token JWT access token
|
|
154
|
+
* @param updates Fields to update (username, password)
|
|
155
|
+
* @returns Updated user details
|
|
156
|
+
* @throws 401 if token invalid/expired, 400 if validation fails
|
|
157
|
+
*/
|
|
158
|
+
async updateCurrentUser(token, updates) {
|
|
159
|
+
const response = await this.client.put('/auth/me', updates, {
|
|
160
|
+
headers: {
|
|
161
|
+
Authorization: `Bearer ${token}`
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
return response.data;
|
|
165
|
+
}
|
|
166
|
+
// ========== API Key Management ==========
|
|
167
|
+
/**
|
|
168
|
+
* Create API key for current user
|
|
169
|
+
*
|
|
170
|
+
* @param token JWT access token
|
|
171
|
+
* @param request API key details
|
|
172
|
+
* @returns API key response (includes plaintext key, shown only once!)
|
|
173
|
+
* @throws 401 if token invalid/expired
|
|
174
|
+
*/
|
|
175
|
+
async createAPIKey(token, request) {
|
|
176
|
+
const response = await this.client.post('/auth/api-keys', request, {
|
|
177
|
+
headers: {
|
|
178
|
+
Authorization: `Bearer ${token}`
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
return response.data;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* List API keys for current user
|
|
185
|
+
*
|
|
186
|
+
* @param token JWT access token
|
|
187
|
+
* @returns List of API keys
|
|
188
|
+
* @throws 401 if token invalid/expired
|
|
189
|
+
*/
|
|
190
|
+
async listAPIKeys(token) {
|
|
191
|
+
const response = await this.client.get('/auth/api-keys', {
|
|
192
|
+
headers: {
|
|
193
|
+
Authorization: `Bearer ${token}`
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
return response.data;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Revoke API key
|
|
200
|
+
*
|
|
201
|
+
* @param token JWT access token
|
|
202
|
+
* @param keyId API key ID to revoke
|
|
203
|
+
* @throws 401 if token invalid/expired, 404 if key not found
|
|
204
|
+
*/
|
|
205
|
+
async revokeAPIKey(token, keyId) {
|
|
206
|
+
await this.client.delete(`/auth/api-keys/${keyId}`, {
|
|
207
|
+
headers: {
|
|
208
|
+
Authorization: `Bearer ${token}`
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
// ========== Admin Endpoints (Role Check) ==========
|
|
213
|
+
/**
|
|
214
|
+
* List all users (admin only)
|
|
215
|
+
*
|
|
216
|
+
* @param token JWT access token (must be admin role)
|
|
217
|
+
* @param skip Number of users to skip (pagination)
|
|
218
|
+
* @param limit Maximum number of users to return
|
|
219
|
+
* @param role Filter by role
|
|
220
|
+
* @returns Paginated list of users
|
|
221
|
+
* @throws 401 if token invalid/expired, 403 if not admin
|
|
222
|
+
*/
|
|
223
|
+
async listUsers(token, skip = 0, limit = 50, role) {
|
|
224
|
+
const params = { skip, limit };
|
|
225
|
+
if (role) {
|
|
226
|
+
params.role = role;
|
|
227
|
+
}
|
|
228
|
+
const response = await this.client.get('/users', {
|
|
229
|
+
params,
|
|
230
|
+
headers: {
|
|
231
|
+
Authorization: `Bearer ${token}`
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
return response.data;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Get user by ID (admin only)
|
|
238
|
+
*
|
|
239
|
+
* @param token JWT access token (must be admin role)
|
|
240
|
+
* @param userId User ID
|
|
241
|
+
* @returns User details
|
|
242
|
+
* @throws 401 if token invalid/expired, 403 if not admin, 404 if user not found
|
|
243
|
+
*/
|
|
244
|
+
async getUser(token, userId) {
|
|
245
|
+
const response = await this.client.get(`/users/${userId}`, {
|
|
246
|
+
headers: {
|
|
247
|
+
Authorization: `Bearer ${token}`
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
return response.data;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Create user (admin only)
|
|
254
|
+
*
|
|
255
|
+
* Note: Uses /auth/register endpoint since there's no dedicated admin create endpoint.
|
|
256
|
+
* Admins can create users with any role.
|
|
257
|
+
*
|
|
258
|
+
* @param token JWT access token (must be admin role)
|
|
259
|
+
* @param request User creation details
|
|
260
|
+
* @returns Created user details
|
|
261
|
+
* @throws 401 if token invalid/expired, 403 if not admin, 400 if validation fails
|
|
262
|
+
*/
|
|
263
|
+
async createUser(token, request) {
|
|
264
|
+
const response = await this.client.post('/auth/register', request, {
|
|
265
|
+
headers: {
|
|
266
|
+
Authorization: `Bearer ${token}`
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
return response.data;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Update user (admin only)
|
|
273
|
+
*
|
|
274
|
+
* @param token JWT access token (must be admin role)
|
|
275
|
+
* @param userId User ID to update
|
|
276
|
+
* @param request Fields to update
|
|
277
|
+
* @returns Updated user details
|
|
278
|
+
* @throws 401 if token invalid/expired, 403 if not admin, 404 if user not found
|
|
279
|
+
*/
|
|
280
|
+
async updateUser(token, userId, request) {
|
|
281
|
+
const response = await this.client.put(`/users/${userId}`, request, {
|
|
282
|
+
headers: {
|
|
283
|
+
Authorization: `Bearer ${token}`
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
return response.data;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Delete user (admin only, cannot delete self)
|
|
290
|
+
*
|
|
291
|
+
* @param token JWT access token (must be admin role)
|
|
292
|
+
* @param userId User ID to delete
|
|
293
|
+
* @throws 401 if token invalid/expired, 403 if not admin, 404 if user not found
|
|
294
|
+
* @throws 400 if trying to delete self
|
|
295
|
+
*/
|
|
296
|
+
async deleteUser(token, userId) {
|
|
297
|
+
await this.client.delete(`/users/${userId}`, {
|
|
298
|
+
headers: {
|
|
299
|
+
Authorization: `Bearer ${token}`
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
exports.AuthClient = AuthClient;
|
|
305
|
+
//# sourceMappingURL=auth-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-client.js","sourceRoot":"","sources":["../../../src/lib/auth/auth-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication Challenge
|
|
3
|
+
*
|
|
4
|
+
* Re-authentication prompt for sensitive operations (e.g., delete user, reset database).
|
|
5
|
+
* Requires user to re-enter password before proceeding.
|
|
6
|
+
*/
|
|
7
|
+
import { AuthClient } from './auth-client.js';
|
|
8
|
+
import { TokenManager, TokenInfo } from './token-manager.js';
|
|
9
|
+
export interface ChallengeOptions {
|
|
10
|
+
reason: string;
|
|
11
|
+
username?: string;
|
|
12
|
+
allowCancel?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare class AuthChallenge {
|
|
15
|
+
private authClient;
|
|
16
|
+
private tokenManager;
|
|
17
|
+
constructor(authClient: AuthClient, tokenManager: TokenManager);
|
|
18
|
+
/**
|
|
19
|
+
* Prompt user to re-authenticate for sensitive operation
|
|
20
|
+
*
|
|
21
|
+
* @param options Challenge options
|
|
22
|
+
* @returns New token on success, null on cancel
|
|
23
|
+
* @throws Error if authentication fails
|
|
24
|
+
*/
|
|
25
|
+
challenge(options: ChallengeOptions): Promise<TokenInfo | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Prompt for username
|
|
28
|
+
*/
|
|
29
|
+
private promptUsername;
|
|
30
|
+
/**
|
|
31
|
+
* Prompt for password (hidden input)
|
|
32
|
+
*/
|
|
33
|
+
private promptPassword;
|
|
34
|
+
/**
|
|
35
|
+
* Prompt to retry after failed authentication
|
|
36
|
+
*/
|
|
37
|
+
private promptRetry;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=challenge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"challenge.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/challenge.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,UAAU,EAAgB,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,qBAAa,aAAa;IAEtB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,YAAY;gBADZ,UAAU,EAAE,UAAU,EACtB,YAAY,EAAE,YAAY;IAGpC;;;;;;OAMG;IACG,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAsDrE;;OAEG;YACW,cAAc;IAgB5B;;OAEG;YACW,cAAc;IAgB5B;;OAEG;YACW,WAAW;CAe1B"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Authentication Challenge
|
|
4
|
+
*
|
|
5
|
+
* Re-authentication prompt for sensitive operations (e.g., delete user, reset database).
|
|
6
|
+
* Requires user to re-enter password before proceeding.
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AuthChallenge = void 0;
|
|
13
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
14
|
+
const token_manager_js_1 = require("./token-manager.js");
|
|
15
|
+
class AuthChallenge {
|
|
16
|
+
constructor(authClient, tokenManager) {
|
|
17
|
+
this.authClient = authClient;
|
|
18
|
+
this.tokenManager = tokenManager;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Prompt user to re-authenticate for sensitive operation
|
|
22
|
+
*
|
|
23
|
+
* @param options Challenge options
|
|
24
|
+
* @returns New token on success, null on cancel
|
|
25
|
+
* @throws Error if authentication fails
|
|
26
|
+
*/
|
|
27
|
+
async challenge(options) {
|
|
28
|
+
const allowCancel = options.allowCancel !== false;
|
|
29
|
+
console.log('');
|
|
30
|
+
console.log(`\x1b[33m⚠️ Authentication Challenge\x1b[0m`);
|
|
31
|
+
console.log(` Reason: ${options.reason}`);
|
|
32
|
+
console.log('');
|
|
33
|
+
console.log(' For security, please re-enter your password to continue.');
|
|
34
|
+
if (allowCancel) {
|
|
35
|
+
console.log(' Press Ctrl+C to cancel.');
|
|
36
|
+
}
|
|
37
|
+
console.log('');
|
|
38
|
+
// Get username (use provided or prompt)
|
|
39
|
+
let username = options.username;
|
|
40
|
+
if (!username) {
|
|
41
|
+
username = await this.promptUsername();
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log(` Username: ${username}`);
|
|
45
|
+
}
|
|
46
|
+
// Get password (always prompt, never pre-fill for security)
|
|
47
|
+
const password = await this.promptPassword();
|
|
48
|
+
// Validate credentials
|
|
49
|
+
try {
|
|
50
|
+
const loginResponse = await this.authClient.login({ username, password });
|
|
51
|
+
const tokenInfo = token_manager_js_1.TokenManager.fromLoginResponse(loginResponse);
|
|
52
|
+
console.log(' \x1b[32m✅ Authentication successful\x1b[0m');
|
|
53
|
+
console.log('');
|
|
54
|
+
return tokenInfo;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error.response?.status === 401) {
|
|
58
|
+
console.error(' \x1b[31m❌ Authentication failed: Invalid username or password\x1b[0m');
|
|
59
|
+
console.log('');
|
|
60
|
+
// Allow retry
|
|
61
|
+
if (allowCancel) {
|
|
62
|
+
const retry = await this.promptRetry();
|
|
63
|
+
if (retry) {
|
|
64
|
+
return this.challenge(options);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
console.error(' \x1b[31m❌ Authentication failed:', error.message, '\x1b[0m');
|
|
70
|
+
console.log('');
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Prompt for username
|
|
77
|
+
*/
|
|
78
|
+
async promptUsername() {
|
|
79
|
+
const response = await (0, prompts_1.default)({
|
|
80
|
+
type: 'text',
|
|
81
|
+
name: 'username',
|
|
82
|
+
message: 'Username',
|
|
83
|
+
});
|
|
84
|
+
// Handle Ctrl+C
|
|
85
|
+
if (response.username === undefined) {
|
|
86
|
+
console.log('\nChallenge cancelled.');
|
|
87
|
+
process.exit(0);
|
|
88
|
+
}
|
|
89
|
+
return response.username;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Prompt for password (hidden input)
|
|
93
|
+
*/
|
|
94
|
+
async promptPassword() {
|
|
95
|
+
const response = await (0, prompts_1.default)({
|
|
96
|
+
type: 'password',
|
|
97
|
+
name: 'password',
|
|
98
|
+
message: 'Password',
|
|
99
|
+
});
|
|
100
|
+
// Handle Ctrl+C
|
|
101
|
+
if (response.password === undefined) {
|
|
102
|
+
console.log('\nChallenge cancelled.');
|
|
103
|
+
process.exit(0);
|
|
104
|
+
}
|
|
105
|
+
return response.password;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Prompt to retry after failed authentication
|
|
109
|
+
*/
|
|
110
|
+
async promptRetry() {
|
|
111
|
+
const response = await (0, prompts_1.default)({
|
|
112
|
+
type: 'confirm',
|
|
113
|
+
name: 'retry',
|
|
114
|
+
message: 'Retry?',
|
|
115
|
+
initial: false,
|
|
116
|
+
});
|
|
117
|
+
// Handle Ctrl+C
|
|
118
|
+
if (response.retry === undefined) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return response.retry;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
exports.AuthChallenge = AuthChallenge;
|
|
125
|
+
//# sourceMappingURL=challenge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"challenge.js","sourceRoot":"","sources":["../../../src/lib/auth/challenge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth Client Credentials Grant Flow (ADR-054)
|
|
3
|
+
*
|
|
4
|
+
* Implements RFC 6749 Client Credentials Grant for machine-to-machine authentication (MCP server).
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. Exchange client_id + client_secret for access token
|
|
8
|
+
* 2. Use access token for API requests
|
|
9
|
+
* 3. Re-authenticate when token expires (no refresh token)
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* const flow = new ClientCredentialsFlow(apiUrl, clientId, clientSecret);
|
|
13
|
+
* const tokenInfo = await flow.authenticate();
|
|
14
|
+
* // Use tokenInfo.access_token for API requests
|
|
15
|
+
*/
|
|
16
|
+
import type { OAuthTokenInfo } from './oauth-types';
|
|
17
|
+
export interface ClientCredentialsCallbacks {
|
|
18
|
+
onSuccess?: (tokenInfo: OAuthTokenInfo) => void;
|
|
19
|
+
onError?: (error: Error) => void;
|
|
20
|
+
}
|
|
21
|
+
export declare class ClientCredentialsFlow {
|
|
22
|
+
private client;
|
|
23
|
+
private clientId;
|
|
24
|
+
private clientSecret;
|
|
25
|
+
constructor(apiUrl: string, clientId: string | undefined, clientSecret: string);
|
|
26
|
+
/**
|
|
27
|
+
* Authenticate using client credentials
|
|
28
|
+
*
|
|
29
|
+
* POST /auth/oauth/token
|
|
30
|
+
* Body: grant_type=client_credentials&client_id=kg-mcp&client_secret=<secret>&scope=read:* write:*
|
|
31
|
+
*
|
|
32
|
+
* Returns access token (no refresh token for client_credentials grant)
|
|
33
|
+
*
|
|
34
|
+
* @param scope - OAuth scopes to request (default: "read:* write:*")
|
|
35
|
+
* @param callbacks - Optional callbacks for success/error handling
|
|
36
|
+
* @returns OAuth token information
|
|
37
|
+
*/
|
|
38
|
+
authenticate(scope?: string, callbacks?: ClientCredentialsCallbacks): Promise<OAuthTokenInfo>;
|
|
39
|
+
/**
|
|
40
|
+
* Check if client credentials are valid
|
|
41
|
+
*
|
|
42
|
+
* Attempts to authenticate with the provided credentials.
|
|
43
|
+
* Returns true if successful, false otherwise.
|
|
44
|
+
*
|
|
45
|
+
* @returns true if credentials are valid
|
|
46
|
+
*/
|
|
47
|
+
validateCredentials(): Promise<boolean>;
|
|
48
|
+
/**
|
|
49
|
+
* Set new client secret
|
|
50
|
+
*
|
|
51
|
+
* Use this after rotating the client secret via:
|
|
52
|
+
* POST /auth/oauth/clients/{client_id}/rotate-secret
|
|
53
|
+
*
|
|
54
|
+
* @param newSecret - The new client secret
|
|
55
|
+
*/
|
|
56
|
+
setClientSecret(newSecret: string): void;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=client-credentials-flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-credentials-flow.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/client-credentials-flow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAsB,cAAc,EAAsB,MAAM,eAAe,CAAC;AAG5F,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,YAAY,CAAS;gBAEjB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAW,EAAE,YAAY,EAAE,MAAM;IAgB7E;;;;;;;;;;;OAWG;IACG,YAAY,CAChB,KAAK,GAAE,MAAyB,EAChC,SAAS,CAAC,EAAE,0BAA0B,GACrC,OAAO,CAAC,cAAc,CAAC;IA2C1B;;;;;;;OAOG;IACG,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC;IAS7C;;;;;;;OAOG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAMzC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OAuth Client Credentials Grant Flow (ADR-054)
|
|
4
|
+
*
|
|
5
|
+
* Implements RFC 6749 Client Credentials Grant for machine-to-machine authentication (MCP server).
|
|
6
|
+
*
|
|
7
|
+
* Flow:
|
|
8
|
+
* 1. Exchange client_id + client_secret for access token
|
|
9
|
+
* 2. Use access token for API requests
|
|
10
|
+
* 3. Re-authenticate when token expires (no refresh token)
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* const flow = new ClientCredentialsFlow(apiUrl, clientId, clientSecret);
|
|
14
|
+
* const tokenInfo = await flow.authenticate();
|
|
15
|
+
* // Use tokenInfo.access_token for API requests
|
|
16
|
+
*/
|
|
17
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
18
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.ClientCredentialsFlow = void 0;
|
|
22
|
+
const axios_1 = __importDefault(require("axios"));
|
|
23
|
+
const oauth_utils_1 = require("./oauth-utils");
|
|
24
|
+
class ClientCredentialsFlow {
|
|
25
|
+
constructor(apiUrl, clientId = 'kg-mcp', clientSecret) {
|
|
26
|
+
if (!clientSecret) {
|
|
27
|
+
throw new Error('Client secret is required for client credentials flow');
|
|
28
|
+
}
|
|
29
|
+
this.clientId = clientId;
|
|
30
|
+
this.clientSecret = clientSecret;
|
|
31
|
+
this.client = axios_1.default.create({
|
|
32
|
+
baseURL: apiUrl,
|
|
33
|
+
headers: {
|
|
34
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
35
|
+
},
|
|
36
|
+
timeout: 10000, // 10 seconds
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Authenticate using client credentials
|
|
41
|
+
*
|
|
42
|
+
* POST /auth/oauth/token
|
|
43
|
+
* Body: grant_type=client_credentials&client_id=kg-mcp&client_secret=<secret>&scope=read:* write:*
|
|
44
|
+
*
|
|
45
|
+
* Returns access token (no refresh token for client_credentials grant)
|
|
46
|
+
*
|
|
47
|
+
* @param scope - OAuth scopes to request (default: "read:* write:*")
|
|
48
|
+
* @param callbacks - Optional callbacks for success/error handling
|
|
49
|
+
* @returns OAuth token information
|
|
50
|
+
*/
|
|
51
|
+
async authenticate(scope = 'read:* write:*', callbacks) {
|
|
52
|
+
try {
|
|
53
|
+
const params = new URLSearchParams({
|
|
54
|
+
grant_type: 'client_credentials',
|
|
55
|
+
client_id: this.clientId,
|
|
56
|
+
client_secret: this.clientSecret,
|
|
57
|
+
scope: scope,
|
|
58
|
+
});
|
|
59
|
+
const response = await this.client.post('/auth/oauth/token', params.toString());
|
|
60
|
+
const tokenInfo = (0, oauth_utils_1.convertTokenResponse)(response.data, this.clientId);
|
|
61
|
+
callbacks?.onSuccess?.(tokenInfo);
|
|
62
|
+
return tokenInfo;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
66
|
+
const axiosError = error;
|
|
67
|
+
const errorMessage = axiosError.response?.data?.error_description ||
|
|
68
|
+
axiosError.response?.data?.error ||
|
|
69
|
+
axiosError.message;
|
|
70
|
+
// Check for authentication failure
|
|
71
|
+
if (axiosError.response?.status === 401) {
|
|
72
|
+
const err = new Error(`Authentication failed: Invalid client credentials`);
|
|
73
|
+
callbacks?.onError?.(err);
|
|
74
|
+
throw err;
|
|
75
|
+
}
|
|
76
|
+
const err = new Error(`Client credentials authentication failed: ${errorMessage}`);
|
|
77
|
+
callbacks?.onError?.(err);
|
|
78
|
+
throw err;
|
|
79
|
+
}
|
|
80
|
+
const err = error instanceof Error ? error : new Error('Unknown authentication error');
|
|
81
|
+
callbacks?.onError?.(err);
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if client credentials are valid
|
|
87
|
+
*
|
|
88
|
+
* Attempts to authenticate with the provided credentials.
|
|
89
|
+
* Returns true if successful, false otherwise.
|
|
90
|
+
*
|
|
91
|
+
* @returns true if credentials are valid
|
|
92
|
+
*/
|
|
93
|
+
async validateCredentials() {
|
|
94
|
+
try {
|
|
95
|
+
await this.authenticate();
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Set new client secret
|
|
104
|
+
*
|
|
105
|
+
* Use this after rotating the client secret via:
|
|
106
|
+
* POST /auth/oauth/clients/{client_id}/rotate-secret
|
|
107
|
+
*
|
|
108
|
+
* @param newSecret - The new client secret
|
|
109
|
+
*/
|
|
110
|
+
setClientSecret(newSecret) {
|
|
111
|
+
if (!newSecret) {
|
|
112
|
+
throw new Error('Client secret cannot be empty');
|
|
113
|
+
}
|
|
114
|
+
this.clientSecret = newSecret;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.ClientCredentialsFlow = ClientCredentialsFlow;
|
|
118
|
+
//# sourceMappingURL=client-credentials-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-credentials-flow.js","sourceRoot":"","sources":["../../../src/lib/auth/client-credentials-flow.ts"],"names":[],"mappings":"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"}
|