@grantex/sdk 0.1.0 → 0.1.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 +604 -0
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
# @grantex/sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for the [Grantex](https://grantex.dev) delegated authorization protocol — OAuth 2.0 for AI agents.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@grantex/sdk)
|
|
6
|
+
[](https://github.com/mishrasanjeev/grantex/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @grantex/sdk
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { Grantex } from '@grantex/sdk';
|
|
18
|
+
|
|
19
|
+
const grantex = new Grantex({ apiKey: 'YOUR_API_KEY' });
|
|
20
|
+
|
|
21
|
+
// 1. Register an agent
|
|
22
|
+
const agent = await grantex.agents.register({
|
|
23
|
+
name: 'Email Assistant',
|
|
24
|
+
description: 'Reads and sends email on behalf of users',
|
|
25
|
+
scopes: ['email:read', 'email:send'],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// 2. Request authorization
|
|
29
|
+
const { consentUrl } = await grantex.authorize({
|
|
30
|
+
agentId: agent.id,
|
|
31
|
+
userId: 'usr_01J...',
|
|
32
|
+
scopes: ['email:read', 'email:send'],
|
|
33
|
+
});
|
|
34
|
+
// Redirect the user to consentUrl — they approve in plain language
|
|
35
|
+
|
|
36
|
+
// 3. Verify a grant token (offline, no network call)
|
|
37
|
+
import { verifyGrantToken } from '@grantex/sdk';
|
|
38
|
+
|
|
39
|
+
const grant = await verifyGrantToken(token, {
|
|
40
|
+
jwksUri: 'https://api.grantex.dev/.well-known/jwks.json',
|
|
41
|
+
});
|
|
42
|
+
console.log(grant.scopes); // ['email:read', 'email:send']
|
|
43
|
+
console.log(grant.principalId); // 'usr_01J...'
|
|
44
|
+
|
|
45
|
+
// 4. Revoke when done
|
|
46
|
+
await grantex.tokens.revoke(grant.tokenId);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Configuration
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
const grantex = new Grantex({
|
|
53
|
+
apiKey: 'gx_....', // or set GRANTEX_API_KEY env var
|
|
54
|
+
baseUrl: 'https://api.grantex.dev', // default
|
|
55
|
+
timeout: 30000, // request timeout in ms (default: 30s)
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
| Option | Type | Default | Description |
|
|
60
|
+
|--------|------|---------|-------------|
|
|
61
|
+
| `apiKey` | `string` | `process.env.GRANTEX_API_KEY` | API key for authentication |
|
|
62
|
+
| `baseUrl` | `string` | `https://api.grantex.dev` | Base URL of the Grantex API |
|
|
63
|
+
| `timeout` | `number` | `30000` | Request timeout in milliseconds |
|
|
64
|
+
|
|
65
|
+
## API Reference
|
|
66
|
+
|
|
67
|
+
### Authorization
|
|
68
|
+
|
|
69
|
+
#### `grantex.authorize(params)`
|
|
70
|
+
|
|
71
|
+
Initiate the delegated authorization flow. Returns a consent URL to redirect the user to.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
const request = await grantex.authorize({
|
|
75
|
+
agentId: 'ag_01J...',
|
|
76
|
+
userId: 'usr_01J...',
|
|
77
|
+
scopes: ['files:read', 'email:send'],
|
|
78
|
+
expiresIn: '24h', // optional
|
|
79
|
+
redirectUri: 'https://...' // optional
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
console.log(request.consentUrl); // redirect user here
|
|
83
|
+
console.log(request.authRequestId); // track the request
|
|
84
|
+
console.log(request.expiresAt); // ISO 8601 timestamp
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Returns**: `AuthorizationRequest`
|
|
88
|
+
|
|
89
|
+
| Field | Type | Description |
|
|
90
|
+
|-------|------|-------------|
|
|
91
|
+
| `authRequestId` | `string` | Unique ID for this authorization request |
|
|
92
|
+
| `consentUrl` | `string` | URL to redirect the user to for consent |
|
|
93
|
+
| `agentId` | `string` | The agent requesting authorization |
|
|
94
|
+
| `principalId` | `string` | The user being asked for consent |
|
|
95
|
+
| `scopes` | `string[]` | Requested scopes |
|
|
96
|
+
| `expiresAt` | `string` | When the request expires (ISO 8601) |
|
|
97
|
+
| `status` | `string` | `'pending'`, `'approved'`, `'denied'`, or `'expired'` |
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### Agents
|
|
102
|
+
|
|
103
|
+
#### `grantex.agents.register(params)`
|
|
104
|
+
|
|
105
|
+
Register a new AI agent.
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const agent = await grantex.agents.register({
|
|
109
|
+
name: 'Code Review Bot',
|
|
110
|
+
description: 'Reviews pull requests and suggests improvements',
|
|
111
|
+
scopes: ['repo:read', 'pr:comment'],
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### `grantex.agents.get(agentId)`
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const agent = await grantex.agents.get('ag_01J...');
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### `grantex.agents.list()`
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const { agents, total } = await grantex.agents.list();
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### `grantex.agents.update(agentId, params)`
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const agent = await grantex.agents.update('ag_01J...', {
|
|
131
|
+
name: 'Updated Name',
|
|
132
|
+
scopes: ['repo:read', 'pr:comment', 'pr:approve'],
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### `grantex.agents.delete(agentId)`
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
await grantex.agents.delete('ag_01J...');
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### Grants
|
|
145
|
+
|
|
146
|
+
#### `grantex.grants.get(grantId)`
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const grant = await grantex.grants.get('grnt_01J...');
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
#### `grantex.grants.list(params?)`
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
const { grants, total } = await grantex.grants.list({
|
|
156
|
+
agentId: 'ag_01J...', // optional filter
|
|
157
|
+
principalId: 'usr_01J...', // optional filter
|
|
158
|
+
status: 'active', // 'active' | 'revoked' | 'expired'
|
|
159
|
+
page: 1,
|
|
160
|
+
pageSize: 20,
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### `grantex.grants.revoke(grantId)`
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
await grantex.grants.revoke('grnt_01J...');
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### `grantex.grants.delegate(params)`
|
|
171
|
+
|
|
172
|
+
Create a delegated sub-agent grant (per [SPEC Section 9](https://github.com/mishrasanjeev/grantex/blob/main/SPEC.md)).
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
const delegation = await grantex.grants.delegate({
|
|
176
|
+
parentGrantToken: 'eyJhbG...',
|
|
177
|
+
subAgentId: 'ag_02K...',
|
|
178
|
+
scopes: ['files:read'], // must be subset of parent scopes
|
|
179
|
+
expiresIn: '1h', // optional, cannot exceed parent
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
console.log(delegation.grantToken); // new JWT for the sub-agent
|
|
183
|
+
console.log(delegation.grantId);
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### `grantex.grants.verify(token)`
|
|
187
|
+
|
|
188
|
+
Verify a grant token via the API (online verification with real-time revocation check).
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
const verified = await grantex.grants.verify('eyJhbG...');
|
|
192
|
+
console.log(verified.principalId);
|
|
193
|
+
console.log(verified.scopes);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
### Tokens
|
|
199
|
+
|
|
200
|
+
#### `grantex.tokens.verify(token)`
|
|
201
|
+
|
|
202
|
+
Online token verification with revocation status.
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const result = await grantex.tokens.verify('eyJhbG...');
|
|
206
|
+
if (result.valid) {
|
|
207
|
+
console.log(result.scopes); // ['files:read']
|
|
208
|
+
console.log(result.principal); // 'usr_01J...'
|
|
209
|
+
console.log(result.agent); // 'ag_01J...'
|
|
210
|
+
console.log(result.grantId);
|
|
211
|
+
console.log(result.expiresAt);
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### `grantex.tokens.revoke(tokenId)`
|
|
216
|
+
|
|
217
|
+
Revoke a token by its JTI. Blocklisted in Redis immediately; all sub-delegated tokens are also invalidated.
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
await grantex.tokens.revoke('tok_01J...');
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
### Offline Token Verification
|
|
226
|
+
|
|
227
|
+
#### `verifyGrantToken(token, options)`
|
|
228
|
+
|
|
229
|
+
Verify a grant token offline using the published JWKS. No API call needed — signature is verified locally using RS256.
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
import { verifyGrantToken } from '@grantex/sdk';
|
|
233
|
+
|
|
234
|
+
const grant = await verifyGrantToken('eyJhbG...', {
|
|
235
|
+
jwksUri: 'https://api.grantex.dev/.well-known/jwks.json',
|
|
236
|
+
requiredScopes: ['files:read'], // optional — rejects if missing
|
|
237
|
+
audience: 'https://myapp.com', // optional — validates aud claim
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Returns**: `VerifiedGrant`
|
|
242
|
+
|
|
243
|
+
| Field | Type | Description |
|
|
244
|
+
|-------|------|-------------|
|
|
245
|
+
| `tokenId` | `string` | Unique token ID (JWT `jti` claim) |
|
|
246
|
+
| `grantId` | `string` | Grant record ID |
|
|
247
|
+
| `principalId` | `string` | User who authorized the grant (`sub` claim) |
|
|
248
|
+
| `agentDid` | `string` | Agent's DID (`agt` claim) |
|
|
249
|
+
| `developerId` | `string` | Developer org ID (`dev` claim) |
|
|
250
|
+
| `scopes` | `string[]` | Granted scopes (`scp` claim) |
|
|
251
|
+
| `issuedAt` | `number` | Issued-at timestamp (seconds since epoch) |
|
|
252
|
+
| `expiresAt` | `number` | Expiry timestamp (seconds since epoch) |
|
|
253
|
+
| `parentAgentDid` | `string?` | Parent agent DID (delegation only) |
|
|
254
|
+
| `parentGrantId` | `string?` | Parent grant ID (delegation only) |
|
|
255
|
+
| `delegationDepth` | `number?` | Delegation depth (0 = root) |
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
### Audit
|
|
260
|
+
|
|
261
|
+
#### `grantex.audit.log(params)`
|
|
262
|
+
|
|
263
|
+
Log an auditable action taken by an agent.
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
const entry = await grantex.audit.log({
|
|
267
|
+
agentId: 'ag_01J...',
|
|
268
|
+
grantId: 'grnt_01J...',
|
|
269
|
+
action: 'email:send',
|
|
270
|
+
metadata: { to: 'user@example.com', subject: 'Hello' },
|
|
271
|
+
status: 'success', // 'success' | 'failure' | 'blocked'
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
#### `grantex.audit.list(params?)`
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
const { entries, total } = await grantex.audit.list({
|
|
279
|
+
agentId: 'ag_01J...',
|
|
280
|
+
action: 'email:send',
|
|
281
|
+
since: '2026-01-01T00:00:00Z',
|
|
282
|
+
until: '2026-02-28T23:59:59Z',
|
|
283
|
+
page: 1,
|
|
284
|
+
pageSize: 50,
|
|
285
|
+
});
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
#### `grantex.audit.get(entryId)`
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
const entry = await grantex.audit.get('aud_01J...');
|
|
292
|
+
console.log(entry.hash); // SHA-256 hash for tamper evidence
|
|
293
|
+
console.log(entry.prevHash); // previous entry hash (chain integrity)
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
### Webhooks
|
|
299
|
+
|
|
300
|
+
#### `grantex.webhooks.create(params)`
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
const webhook = await grantex.webhooks.create({
|
|
304
|
+
url: 'https://myapp.com/webhooks/grantex',
|
|
305
|
+
events: ['grant.created', 'grant.revoked', 'token.issued'],
|
|
306
|
+
});
|
|
307
|
+
console.log(webhook.secret); // HMAC secret for signature verification
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### `grantex.webhooks.list()`
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
const { webhooks } = await grantex.webhooks.list();
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
#### `grantex.webhooks.delete(webhookId)`
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
await grantex.webhooks.delete('wh_01J...');
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
#### Webhook Signature Verification
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
import { verifyWebhookSignature } from '@grantex/sdk';
|
|
326
|
+
|
|
327
|
+
// In your webhook handler
|
|
328
|
+
verifyWebhookSignature(requestBody, signatureHeader, webhookSecret);
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
### Policies
|
|
334
|
+
|
|
335
|
+
Define fine-grained access control rules for agents.
|
|
336
|
+
|
|
337
|
+
#### `grantex.policies.create(params)`
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
const policy = await grantex.policies.create({
|
|
341
|
+
name: 'Block after hours',
|
|
342
|
+
effect: 'deny',
|
|
343
|
+
priority: 10,
|
|
344
|
+
scopes: ['email:send'],
|
|
345
|
+
timeOfDayStart: '18:00',
|
|
346
|
+
timeOfDayEnd: '08:00',
|
|
347
|
+
});
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
#### `grantex.policies.list()`
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
const { policies, total } = await grantex.policies.list();
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
#### `grantex.policies.get(policyId)` / `update(policyId, params)` / `delete(policyId)`
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
const policy = await grantex.policies.get('pol_01J...');
|
|
360
|
+
|
|
361
|
+
await grantex.policies.update('pol_01J...', { effect: 'allow' });
|
|
362
|
+
|
|
363
|
+
await grantex.policies.delete('pol_01J...');
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
### Compliance
|
|
369
|
+
|
|
370
|
+
#### `grantex.compliance.getSummary(params?)`
|
|
371
|
+
|
|
372
|
+
```typescript
|
|
373
|
+
const summary = await grantex.compliance.getSummary({
|
|
374
|
+
since: '2026-01-01T00:00:00Z',
|
|
375
|
+
until: '2026-02-28T23:59:59Z',
|
|
376
|
+
});
|
|
377
|
+
console.log(summary.agents); // { total, active, suspended, revoked }
|
|
378
|
+
console.log(summary.grants); // { total, active, revoked, expired }
|
|
379
|
+
console.log(summary.auditEntries); // { total, success, failure, blocked }
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
#### `grantex.compliance.exportGrants(params?)`
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
const { grants, total } = await grantex.compliance.exportGrants({
|
|
386
|
+
status: 'active',
|
|
387
|
+
});
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
#### `grantex.compliance.exportAudit(params?)`
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
const { entries, total } = await grantex.compliance.exportAudit({
|
|
394
|
+
since: '2026-01-01T00:00:00Z',
|
|
395
|
+
agentId: 'ag_01J...',
|
|
396
|
+
});
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
#### `grantex.compliance.evidencePack(params?)`
|
|
400
|
+
|
|
401
|
+
Generate a full SOC 2 / GDPR evidence pack with audit chain integrity verification.
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
const pack = await grantex.compliance.evidencePack({
|
|
405
|
+
framework: 'soc2', // 'soc2' | 'gdpr' | 'all'
|
|
406
|
+
since: '2026-01-01T00:00:00Z',
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
console.log(pack.chainIntegrity.valid); // true
|
|
410
|
+
console.log(pack.chainIntegrity.checkedEntries); // 1042
|
|
411
|
+
console.log(pack.summary);
|
|
412
|
+
console.log(pack.grants);
|
|
413
|
+
console.log(pack.auditEntries);
|
|
414
|
+
console.log(pack.policies);
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
### Anomaly Detection
|
|
420
|
+
|
|
421
|
+
#### `grantex.anomalies.detect()`
|
|
422
|
+
|
|
423
|
+
Run anomaly detection across all agents.
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
const { anomalies, total } = await grantex.anomalies.detect();
|
|
427
|
+
// anomaly types: 'rate_spike' | 'high_failure_rate' | 'new_principal' | 'off_hours_activity'
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
#### `grantex.anomalies.list(params?)`
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
const { anomalies } = await grantex.anomalies.list({
|
|
434
|
+
unacknowledged: true, // only open anomalies
|
|
435
|
+
});
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
#### `grantex.anomalies.acknowledge(anomalyId)`
|
|
439
|
+
|
|
440
|
+
```typescript
|
|
441
|
+
const anomaly = await grantex.anomalies.acknowledge('anom_01J...');
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
### Billing
|
|
447
|
+
|
|
448
|
+
#### `grantex.billing.getSubscription()`
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
const sub = await grantex.billing.getSubscription();
|
|
452
|
+
console.log(sub.plan); // 'free' | 'pro' | 'enterprise'
|
|
453
|
+
console.log(sub.status); // 'active' | 'past_due' | 'canceled'
|
|
454
|
+
console.log(sub.currentPeriodEnd); // ISO 8601 or null
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
#### `grantex.billing.createCheckout(params)`
|
|
458
|
+
|
|
459
|
+
```typescript
|
|
460
|
+
const { checkoutUrl } = await grantex.billing.createCheckout({
|
|
461
|
+
plan: 'pro',
|
|
462
|
+
successUrl: 'https://myapp.com/billing/success',
|
|
463
|
+
cancelUrl: 'https://myapp.com/billing/cancel',
|
|
464
|
+
});
|
|
465
|
+
// Redirect user to checkoutUrl
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
#### `grantex.billing.createPortal(params)`
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
const { portalUrl } = await grantex.billing.createPortal({
|
|
472
|
+
returnUrl: 'https://myapp.com/settings',
|
|
473
|
+
});
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
478
|
+
### SCIM 2.0 Provisioning
|
|
479
|
+
|
|
480
|
+
Sync users from your identity provider.
|
|
481
|
+
|
|
482
|
+
#### Token Management
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
// Create a SCIM bearer token
|
|
486
|
+
const { token, id, label } = await grantex.scim.createToken({
|
|
487
|
+
label: 'Okta SCIM integration',
|
|
488
|
+
});
|
|
489
|
+
// token is returned once — store it securely
|
|
490
|
+
|
|
491
|
+
const { tokens } = await grantex.scim.listTokens();
|
|
492
|
+
|
|
493
|
+
await grantex.scim.revokeToken('scimtok_01J...');
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
#### User Operations
|
|
497
|
+
|
|
498
|
+
```typescript
|
|
499
|
+
// List provisioned users
|
|
500
|
+
const { Resources, totalResults } = await grantex.scim.listUsers({
|
|
501
|
+
startIndex: 1,
|
|
502
|
+
count: 100,
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
// Create a user
|
|
506
|
+
const user = await grantex.scim.createUser({
|
|
507
|
+
userName: 'alice@example.com',
|
|
508
|
+
displayName: 'Alice',
|
|
509
|
+
emails: [{ value: 'alice@example.com', primary: true }],
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
// Get / Replace / Patch / Delete
|
|
513
|
+
const user = await grantex.scim.getUser('scimusr_01J...');
|
|
514
|
+
|
|
515
|
+
await grantex.scim.replaceUser('scimusr_01J...', { userName: 'alice@new.com' });
|
|
516
|
+
|
|
517
|
+
await grantex.scim.updateUser('scimusr_01J...', [
|
|
518
|
+
{ op: 'replace', path: 'active', value: false },
|
|
519
|
+
]);
|
|
520
|
+
|
|
521
|
+
await grantex.scim.deleteUser('scimusr_01J...');
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
### SSO (OIDC)
|
|
527
|
+
|
|
528
|
+
#### `grantex.sso.createConfig(params)`
|
|
529
|
+
|
|
530
|
+
```typescript
|
|
531
|
+
const config = await grantex.sso.createConfig({
|
|
532
|
+
issuerUrl: 'https://accounts.google.com',
|
|
533
|
+
clientId: 'xxx.apps.googleusercontent.com',
|
|
534
|
+
clientSecret: 'GOCSPX-...',
|
|
535
|
+
redirectUri: 'https://myapp.com/auth/callback',
|
|
536
|
+
});
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
#### `grantex.sso.getConfig()` / `deleteConfig()`
|
|
540
|
+
|
|
541
|
+
```typescript
|
|
542
|
+
const config = await grantex.sso.getConfig();
|
|
543
|
+
await grantex.sso.deleteConfig();
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
#### `grantex.sso.getLoginUrl(org)`
|
|
547
|
+
|
|
548
|
+
```typescript
|
|
549
|
+
const { authorizeUrl } = await grantex.sso.getLoginUrl('dev_01J...');
|
|
550
|
+
// Redirect user to authorizeUrl
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
#### `grantex.sso.handleCallback(code, state)`
|
|
554
|
+
|
|
555
|
+
```typescript
|
|
556
|
+
const { email, name, sub, developerId } = await grantex.sso.handleCallback(code, state);
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## Error Handling
|
|
562
|
+
|
|
563
|
+
All errors extend `GrantexError`:
|
|
564
|
+
|
|
565
|
+
```typescript
|
|
566
|
+
import {
|
|
567
|
+
GrantexError, // base class
|
|
568
|
+
GrantexApiError, // API returned an error (has statusCode, body, requestId)
|
|
569
|
+
GrantexAuthError, // 401/403 — invalid or missing API key
|
|
570
|
+
GrantexTokenError, // token verification failed (invalid signature, expired, etc.)
|
|
571
|
+
GrantexNetworkError, // network failure (timeout, DNS, connection refused)
|
|
572
|
+
} from '@grantex/sdk';
|
|
573
|
+
|
|
574
|
+
try {
|
|
575
|
+
await grantex.agents.get('ag_invalid');
|
|
576
|
+
} catch (err) {
|
|
577
|
+
if (err instanceof GrantexAuthError) {
|
|
578
|
+
console.error('Auth failed:', err.statusCode); // 401 or 403
|
|
579
|
+
console.error('Request ID:', err.requestId);
|
|
580
|
+
} else if (err instanceof GrantexApiError) {
|
|
581
|
+
console.error('API error:', err.statusCode, err.body);
|
|
582
|
+
} else if (err instanceof GrantexNetworkError) {
|
|
583
|
+
console.error('Network error:', err.message, err.cause);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
## Requirements
|
|
591
|
+
|
|
592
|
+
- Node.js 18+
|
|
593
|
+
- ESM (`"type": "module"` in your package.json, or use dynamic `import()`)
|
|
594
|
+
|
|
595
|
+
## Links
|
|
596
|
+
|
|
597
|
+
- [GitHub](https://github.com/mishrasanjeev/grantex)
|
|
598
|
+
- [Protocol Specification](https://github.com/mishrasanjeev/grantex/blob/main/SPEC.md)
|
|
599
|
+
- [Python SDK](https://pypi.org/project/grantex/)
|
|
600
|
+
- [API Reference](https://api.grantex.dev/.well-known/jwks.json)
|
|
601
|
+
|
|
602
|
+
## License
|
|
603
|
+
|
|
604
|
+
[Apache 2.0](https://github.com/mishrasanjeev/grantex/blob/main/LICENSE)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grantex/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "TypeScript SDK for the Grantex delegated authorization protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"main": "./dist/index.js",
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"files": [
|
|
15
|
-
"dist"
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md"
|
|
16
17
|
],
|
|
17
18
|
"scripts": {
|
|
18
19
|
"build": "tsc -p tsconfig.build.json",
|