atp-sdk 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/CHANGELOG.md +111 -0
- package/LICENSE +201 -0
- package/README.md +633 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +55 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/client/atp.d.ts.map +1 -0
- package/dist/client/atp.js +90 -0
- package/dist/client/atp.js.map +1 -0
- package/dist/client/audit.d.ts.map +1 -0
- package/dist/client/audit.js +125 -0
- package/dist/client/audit.js.map +1 -0
- package/dist/client/base.d.ts.map +1 -0
- package/dist/client/base.js +190 -0
- package/dist/client/base.js.map +1 -0
- package/dist/client/credentials.d.ts.map +1 -0
- package/dist/client/credentials.js +112 -0
- package/dist/client/credentials.js.map +1 -0
- package/dist/client/gateway.d.ts.map +1 -0
- package/dist/client/gateway.js +214 -0
- package/dist/client/gateway.js.map +1 -0
- package/dist/client/identity.d.ts.map +1 -0
- package/dist/client/identity.js +94 -0
- package/dist/client/identity.js.map +1 -0
- package/dist/client/permissions.d.ts.map +1 -0
- package/dist/client/permissions.js +132 -0
- package/dist/client/permissions.js.map +1 -0
- package/dist/index.cjs +89 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/simple-agent.d.ts.map +1 -0
- package/dist/simple-agent.js +261 -0
- package/dist/simple-agent.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +48 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/crypto.js +100 -0
- package/dist/utils/crypto.js.map +1 -0
- package/dist/utils/did.d.ts.map +1 -0
- package/dist/utils/did.js +225 -0
- package/dist/utils/did.js.map +1 -0
- package/dist/utils/jwt.d.ts.map +1 -0
- package/dist/utils/jwt.js +235 -0
- package/dist/utils/jwt.js.map +1 -0
- package/docs/README.md +362 -0
- package/docs/api/README.md +1077 -0
- package/docs/guides/authentication.md +667 -0
- package/docs/guides/best-practices.md +1004 -0
- package/docs/guides/configuration.md +588 -0
- package/docs/guides/error-handling.md +1073 -0
- package/docs/guides/troubleshooting.md +850 -0
- package/examples/01-basic-setup.js +53 -0
- package/examples/02-identity-management.js +130 -0
- package/examples/03-verifiable-credentials.js +234 -0
- package/examples/04-permissions-and-access-control.js +326 -0
- package/examples/05-audit-logging.js +310 -0
- package/examples/06-real-time-monitoring.js +302 -0
- package/examples/07-advanced-use-cases.js +584 -0
- package/examples/README.md +211 -0
- package/examples/index.js +135 -0
- package/examples/simple-3-line.ts +51 -0
- package/package.json +108 -0
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
# Authentication Guide
|
|
2
|
+
|
|
3
|
+
This guide covers all authentication methods and patterns supported by the ATP™ SDK.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Authentication Overview](#authentication-overview)
|
|
8
|
+
2. [DID-based Authentication](#did-based-authentication)
|
|
9
|
+
3. [JWT Token Authentication](#jwt-token-authentication)
|
|
10
|
+
4. [Multi-Factor Authentication](#multi-factor-authentication)
|
|
11
|
+
5. [Service-to-Service Authentication](#service-to-service-authentication)
|
|
12
|
+
6. [Token Management](#token-management)
|
|
13
|
+
7. [Security Best Practices](#security-best-practices)
|
|
14
|
+
|
|
15
|
+
## Authentication Overview
|
|
16
|
+
|
|
17
|
+
The ATP™ SDK supports multiple authentication methods:
|
|
18
|
+
|
|
19
|
+
- **DID + Private Key**: Self-sovereign identity authentication
|
|
20
|
+
- **JWT Tokens**: Bearer token authentication
|
|
21
|
+
- **API Keys**: Simple API key authentication
|
|
22
|
+
- **Certificate-based**: X.509 client certificate authentication
|
|
23
|
+
- **Multi-Factor**: Additional security layers
|
|
24
|
+
|
|
25
|
+
## DID-based Authentication
|
|
26
|
+
|
|
27
|
+
### Basic DID Authentication
|
|
28
|
+
|
|
29
|
+
The primary authentication method uses Decentralized Identifiers (DIDs) with cryptographic key pairs:
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
import { ATPClient, DIDUtils } from '@atp/sdk';
|
|
33
|
+
|
|
34
|
+
// Generate a new DID and key pair
|
|
35
|
+
const { did, keyPair } = await DIDUtils.generateDID({
|
|
36
|
+
network: 'testnet',
|
|
37
|
+
method: 'atp'
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Configure client with DID authentication
|
|
41
|
+
const client = new ATPClient({
|
|
42
|
+
baseUrl: 'http://localhost',
|
|
43
|
+
auth: {
|
|
44
|
+
did: did,
|
|
45
|
+
privateKey: keyPair.privateKey
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Loading Existing DIDs
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
// Load from environment variables
|
|
54
|
+
const client = new ATPClient({
|
|
55
|
+
baseUrl: 'http://localhost',
|
|
56
|
+
auth: {
|
|
57
|
+
did: process.env.ATP_DID,
|
|
58
|
+
privateKey: process.env.ATP_PRIVATE_KEY
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Load from secure key storage
|
|
63
|
+
import { loadKeyFromVault } from './key-management';
|
|
64
|
+
|
|
65
|
+
const privateKey = await loadKeyFromVault(process.env.KEY_ID);
|
|
66
|
+
client.setAuthentication({
|
|
67
|
+
did: 'did:atp:mainnet:your-identifier',
|
|
68
|
+
privateKey: privateKey
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### DID Document Registration
|
|
73
|
+
|
|
74
|
+
Before using a DID for authentication, it must be registered:
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
// Generate DID and register with ATP network
|
|
78
|
+
const { did, document, keyPair } = await DIDUtils.generateDID();
|
|
79
|
+
|
|
80
|
+
// Register identity
|
|
81
|
+
await client.identity.register({
|
|
82
|
+
did: did,
|
|
83
|
+
document: document,
|
|
84
|
+
metadata: {
|
|
85
|
+
name: 'Your Application',
|
|
86
|
+
type: 'service',
|
|
87
|
+
purpose: 'API access'
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
console.log(`DID registered: ${did}`);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### DID Key Rotation
|
|
95
|
+
|
|
96
|
+
Regularly rotate cryptographic keys for security:
|
|
97
|
+
|
|
98
|
+
```javascript
|
|
99
|
+
// Generate new key pair
|
|
100
|
+
const newKeyPair = await CryptoUtils.generateKeyPair();
|
|
101
|
+
|
|
102
|
+
// Add new verification method to DID document
|
|
103
|
+
const updatedDocument = DIDUtils.addVerificationMethod(
|
|
104
|
+
currentDocument,
|
|
105
|
+
newKeyPair.publicKey,
|
|
106
|
+
['authentication', 'assertionMethod']
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// Update DID document
|
|
110
|
+
await client.identity.update(did, {
|
|
111
|
+
document: updatedDocument
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Update client authentication
|
|
115
|
+
client.setAuthentication({
|
|
116
|
+
did: did,
|
|
117
|
+
privateKey: newKeyPair.privateKey
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
console.log('DID key rotated successfully');
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## JWT Token Authentication
|
|
124
|
+
|
|
125
|
+
### Using Pre-issued Tokens
|
|
126
|
+
|
|
127
|
+
If you have a JWT token from another system:
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
const client = new ATPClient({
|
|
131
|
+
baseUrl: 'http://localhost',
|
|
132
|
+
auth: {
|
|
133
|
+
token: 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...'
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Creating JWT Tokens
|
|
139
|
+
|
|
140
|
+
Create JWT tokens programmatically:
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
import { JWTUtils } from '@atp/sdk';
|
|
144
|
+
|
|
145
|
+
// Create authentication token
|
|
146
|
+
const token = await JWTUtils.createAuthToken(
|
|
147
|
+
'did:atp:testnet:user',
|
|
148
|
+
privateKey,
|
|
149
|
+
{
|
|
150
|
+
audience: 'atp:services',
|
|
151
|
+
expiresIn: '1h',
|
|
152
|
+
permissions: ['read', 'write'],
|
|
153
|
+
trustLevel: 'VERIFIED'
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Use token with client
|
|
158
|
+
client.setAuthentication({ token });
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Token Verification
|
|
162
|
+
|
|
163
|
+
Verify incoming tokens:
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
// Verify token authenticity
|
|
167
|
+
const verification = await JWTUtils.verifyDIDJWT(
|
|
168
|
+
token,
|
|
169
|
+
publicKey,
|
|
170
|
+
{
|
|
171
|
+
audience: 'atp:services',
|
|
172
|
+
issuer: 'did:atp:testnet:trusted-issuer'
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
if (verification.valid) {
|
|
177
|
+
console.log('Token is valid');
|
|
178
|
+
console.log('Payload:', verification.payload);
|
|
179
|
+
} else {
|
|
180
|
+
console.error('Token verification failed:', verification.error);
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Capability Tokens
|
|
185
|
+
|
|
186
|
+
Use capability tokens for delegation:
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
// Create capability token
|
|
190
|
+
const capabilityToken = await JWTUtils.createCapabilityToken(
|
|
191
|
+
'did:atp:testnet:issuer', // Issuer
|
|
192
|
+
'did:atp:testnet:delegate', // Subject/delegate
|
|
193
|
+
['document:read', 'report:generate'], // Capabilities
|
|
194
|
+
issuerPrivateKey,
|
|
195
|
+
{
|
|
196
|
+
expiresIn: '24h',
|
|
197
|
+
audience: 'atp:services',
|
|
198
|
+
restrictions: {
|
|
199
|
+
ipRange: '192.168.1.0/24',
|
|
200
|
+
timeWindow: {
|
|
201
|
+
start: '09:00',
|
|
202
|
+
end: '17:00'
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
// Use capability token
|
|
209
|
+
client.setAuthentication({ token: capabilityToken });
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Multi-Factor Authentication
|
|
213
|
+
|
|
214
|
+
### Setting Up MFA
|
|
215
|
+
|
|
216
|
+
Enable MFA for enhanced security:
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
// Set up TOTP (Time-based One-Time Password)
|
|
220
|
+
const mfaSetup = await client.identity.setupMFA({
|
|
221
|
+
method: 'totp',
|
|
222
|
+
label: 'MyApp Production'
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
console.log('MFA Secret:', mfaSetup.data.secret);
|
|
226
|
+
console.log('QR Code:', mfaSetup.data.qrCodeUrl);
|
|
227
|
+
|
|
228
|
+
// Set up SMS MFA
|
|
229
|
+
const smsMfa = await client.identity.setupMFA({
|
|
230
|
+
method: 'sms',
|
|
231
|
+
phoneNumber: '+1234567890'
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// Set up Email MFA
|
|
235
|
+
const emailMfa = await client.identity.setupMFA({
|
|
236
|
+
method: 'email',
|
|
237
|
+
emailAddress: 'user@example.com'
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### MFA Authentication Flow
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
// Step 1: Initial authentication with DID
|
|
245
|
+
client.setAuthentication({
|
|
246
|
+
did: 'did:atp:testnet:user',
|
|
247
|
+
privateKey: userPrivateKey
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// Step 2: Check if MFA is required
|
|
251
|
+
try {
|
|
252
|
+
await client.identity.resolve('did:atp:testnet:user');
|
|
253
|
+
} catch (error) {
|
|
254
|
+
if (error instanceof ATPAuthenticationError && error.code === 'MFA_REQUIRED') {
|
|
255
|
+
// MFA verification needed
|
|
256
|
+
const mfaCode = await promptUserForMFACode();
|
|
257
|
+
|
|
258
|
+
// Verify MFA
|
|
259
|
+
const mfaResult = await client.identity.verifyMFA({
|
|
260
|
+
method: 'totp',
|
|
261
|
+
code: mfaCode
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
if (mfaResult.data.verified) {
|
|
265
|
+
console.log('MFA verification successful');
|
|
266
|
+
// Client is now fully authenticated
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### MFA Recovery
|
|
273
|
+
|
|
274
|
+
Handle MFA recovery scenarios:
|
|
275
|
+
|
|
276
|
+
```javascript
|
|
277
|
+
// Generate recovery codes during MFA setup
|
|
278
|
+
const recoverySetup = await client.identity.setupMFARecovery({
|
|
279
|
+
codeCount: 10 // Generate 10 recovery codes
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
console.log('Recovery codes:', recoverySetup.data.recoveryCodes);
|
|
283
|
+
|
|
284
|
+
// Use recovery code when primary MFA is unavailable
|
|
285
|
+
const recoveryResult = await client.identity.verifyMFARecovery({
|
|
286
|
+
recoveryCode: 'RECOVERY-CODE-123'
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
if (recoveryResult.data.verified) {
|
|
290
|
+
// Disable compromised recovery code
|
|
291
|
+
await client.identity.revokeRecoveryCode('RECOVERY-CODE-123');
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Service-to-Service Authentication
|
|
296
|
+
|
|
297
|
+
### Machine-to-Machine Authentication
|
|
298
|
+
|
|
299
|
+
For automated services:
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
// Service identity with long-lived credentials
|
|
303
|
+
const serviceConfig = {
|
|
304
|
+
baseUrl: 'https://api.atp.example.com',
|
|
305
|
+
auth: {
|
|
306
|
+
did: 'did:atp:mainnet:service-abc123',
|
|
307
|
+
privateKey: await loadServiceKey(),
|
|
308
|
+
|
|
309
|
+
// Service-specific options
|
|
310
|
+
serviceType: 'automated',
|
|
311
|
+
scope: ['audit:write', 'events:publish']
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
const serviceClient = new ATPClient(serviceConfig);
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Cross-Service Communication
|
|
319
|
+
|
|
320
|
+
Authenticate between ATP services:
|
|
321
|
+
|
|
322
|
+
```javascript
|
|
323
|
+
// Create service-to-service token
|
|
324
|
+
const serviceToken = await JWTUtils.createDIDJWT(
|
|
325
|
+
{
|
|
326
|
+
service: 'audit-service',
|
|
327
|
+
operation: 'log_event',
|
|
328
|
+
requestId: generateRequestId()
|
|
329
|
+
},
|
|
330
|
+
servicePrivateKey,
|
|
331
|
+
'did:atp:mainnet:audit-service',
|
|
332
|
+
{
|
|
333
|
+
audience: 'did:atp:mainnet:identity-service',
|
|
334
|
+
expiresIn: '5m' // Short-lived for service calls
|
|
335
|
+
}
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
// Use for inter-service communication
|
|
339
|
+
const response = await fetch('https://identity-service/api/validate', {
|
|
340
|
+
headers: {
|
|
341
|
+
'Authorization': `Bearer ${serviceToken}`,
|
|
342
|
+
'Content-Type': 'application/json'
|
|
343
|
+
},
|
|
344
|
+
body: JSON.stringify(requestData)
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Service Mesh Authentication
|
|
349
|
+
|
|
350
|
+
For microservices architectures:
|
|
351
|
+
|
|
352
|
+
```javascript
|
|
353
|
+
// Load service mesh certificates
|
|
354
|
+
const serviceConfig = {
|
|
355
|
+
baseUrl: 'https://atp-mesh.internal',
|
|
356
|
+
tls: {
|
|
357
|
+
cert: fs.readFileSync('/etc/certs/service.crt'),
|
|
358
|
+
key: fs.readFileSync('/etc/certs/service.key'),
|
|
359
|
+
ca: fs.readFileSync('/etc/certs/ca.crt')
|
|
360
|
+
},
|
|
361
|
+
auth: {
|
|
362
|
+
method: 'mutual-tls',
|
|
363
|
+
serviceId: process.env.SERVICE_ID
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
## Token Management
|
|
369
|
+
|
|
370
|
+
### Token Lifecycle
|
|
371
|
+
|
|
372
|
+
Manage token lifecycle automatically:
|
|
373
|
+
|
|
374
|
+
```javascript
|
|
375
|
+
class TokenManager {
|
|
376
|
+
constructor(client, did, privateKey) {
|
|
377
|
+
this.client = client;
|
|
378
|
+
this.did = did;
|
|
379
|
+
this.privateKey = privateKey;
|
|
380
|
+
this.currentToken = null;
|
|
381
|
+
this.refreshToken = null;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
async ensureValidToken() {
|
|
385
|
+
// Check if current token is expired
|
|
386
|
+
if (!this.currentToken || JWTUtils.isExpired(this.currentToken)) {
|
|
387
|
+
await this.refreshAuthToken();
|
|
388
|
+
}
|
|
389
|
+
return this.currentToken;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async refreshAuthToken() {
|
|
393
|
+
if (this.refreshToken && !JWTUtils.isExpired(this.refreshToken)) {
|
|
394
|
+
// Use refresh token
|
|
395
|
+
this.currentToken = await this.exchangeRefreshToken();
|
|
396
|
+
} else {
|
|
397
|
+
// Create new token with DID
|
|
398
|
+
this.currentToken = await JWTUtils.createAuthToken(
|
|
399
|
+
this.did,
|
|
400
|
+
this.privateKey,
|
|
401
|
+
{ expiresIn: '1h' }
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
this.refreshToken = await JWTUtils.createRefreshToken(
|
|
405
|
+
this.did,
|
|
406
|
+
this.privateKey,
|
|
407
|
+
generateTokenId(),
|
|
408
|
+
{ expiresIn: '30d' }
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Update client authentication
|
|
413
|
+
this.client.setAuthentication({ token: this.currentToken });
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
async exchangeRefreshToken() {
|
|
417
|
+
const response = await fetch('/auth/refresh', {
|
|
418
|
+
method: 'POST',
|
|
419
|
+
headers: {
|
|
420
|
+
'Authorization': `Bearer ${this.refreshToken}`,
|
|
421
|
+
'Content-Type': 'application/json'
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
const data = await response.json();
|
|
426
|
+
return data.accessToken;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Usage
|
|
431
|
+
const tokenManager = new TokenManager(client, did, privateKey);
|
|
432
|
+
await tokenManager.ensureValidToken();
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Token Caching
|
|
436
|
+
|
|
437
|
+
Cache tokens to improve performance:
|
|
438
|
+
|
|
439
|
+
```javascript
|
|
440
|
+
class CachedAuthClient {
|
|
441
|
+
constructor(config) {
|
|
442
|
+
this.client = new ATPClient(config);
|
|
443
|
+
this.tokenCache = new Map();
|
|
444
|
+
this.did = config.auth.did;
|
|
445
|
+
this.privateKey = config.auth.privateKey;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
async authenticatedRequest(operation, ...args) {
|
|
449
|
+
const cacheKey = `token:${this.did}`;
|
|
450
|
+
let token = this.tokenCache.get(cacheKey);
|
|
451
|
+
|
|
452
|
+
// Check if token is expired or near expiry
|
|
453
|
+
if (!token || this.isTokenNearExpiry(token)) {
|
|
454
|
+
token = await this.generateFreshToken();
|
|
455
|
+
this.tokenCache.set(cacheKey, token);
|
|
456
|
+
this.client.setAuthentication({ token });
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return await operation.apply(this.client, args);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
isTokenNearExpiry(token) {
|
|
463
|
+
const timeToExpiry = JWTUtils.getTimeToExpiration(token);
|
|
464
|
+
return timeToExpiry < 300; // Refresh if less than 5 minutes remaining
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
async generateFreshToken() {
|
|
468
|
+
return await JWTUtils.createAuthToken(
|
|
469
|
+
this.did,
|
|
470
|
+
this.privateKey,
|
|
471
|
+
{ expiresIn: '1h' }
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Token Revocation
|
|
478
|
+
|
|
479
|
+
Revoke compromised tokens:
|
|
480
|
+
|
|
481
|
+
```javascript
|
|
482
|
+
// Revoke specific token
|
|
483
|
+
await client.identity.revokeToken({
|
|
484
|
+
tokenId: 'token-abc123',
|
|
485
|
+
reason: 'Security incident'
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// Revoke all tokens for a DID
|
|
489
|
+
await client.identity.revokeAllTokens({
|
|
490
|
+
did: 'did:atp:testnet:user',
|
|
491
|
+
reason: 'Account compromise'
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// Check token revocation status
|
|
495
|
+
const tokenStatus = await client.identity.checkTokenStatus('token-abc123');
|
|
496
|
+
if (tokenStatus.data.revoked) {
|
|
497
|
+
console.log('Token has been revoked');
|
|
498
|
+
}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
## Security Best Practices
|
|
502
|
+
|
|
503
|
+
### Key Management
|
|
504
|
+
|
|
505
|
+
1. **Secure Storage**: Store private keys in secure vaults (HSMs, AWS KMS, etc.)
|
|
506
|
+
2. **Key Rotation**: Rotate keys regularly
|
|
507
|
+
3. **Separation**: Use different keys for different environments
|
|
508
|
+
4. **Backup**: Securely backup recovery keys
|
|
509
|
+
|
|
510
|
+
```javascript
|
|
511
|
+
// Example: AWS KMS integration
|
|
512
|
+
import { KMSClient, DecryptCommand } from '@aws-sdk/client-kms';
|
|
513
|
+
|
|
514
|
+
async function loadPrivateKeyFromKMS(keyId) {
|
|
515
|
+
const kmsClient = new KMSClient({ region: 'us-east-1' });
|
|
516
|
+
|
|
517
|
+
const command = new DecryptCommand({
|
|
518
|
+
CiphertextBlob: Buffer.from(process.env.ENCRYPTED_PRIVATE_KEY, 'base64')
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
const response = await kmsClient.send(command);
|
|
522
|
+
return Buffer.from(response.Plaintext).toString('hex');
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Use with client
|
|
526
|
+
const privateKey = await loadPrivateKeyFromKMS(process.env.KMS_KEY_ID);
|
|
527
|
+
client.setAuthentication({
|
|
528
|
+
did: process.env.ATP_DID,
|
|
529
|
+
privateKey: privateKey
|
|
530
|
+
});
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### Token Security
|
|
534
|
+
|
|
535
|
+
1. **Short Expiry**: Use short token lifetimes
|
|
536
|
+
2. **Refresh Tokens**: Implement token refresh
|
|
537
|
+
3. **Secure Transmission**: Always use HTTPS
|
|
538
|
+
4. **Token Validation**: Validate tokens on every request
|
|
539
|
+
|
|
540
|
+
```javascript
|
|
541
|
+
// Secure token configuration
|
|
542
|
+
const tokenConfig = {
|
|
543
|
+
accessTokenExpiry: '15m', // Short-lived access tokens
|
|
544
|
+
refreshTokenExpiry: '7d', // Longer-lived refresh tokens
|
|
545
|
+
audience: 'specific-service', // Limit token scope
|
|
546
|
+
issuer: 'trusted-issuer',
|
|
547
|
+
|
|
548
|
+
// Security headers
|
|
549
|
+
headers: {
|
|
550
|
+
'Strict-Transport-Security': 'max-age=31536000',
|
|
551
|
+
'X-Content-Type-Options': 'nosniff',
|
|
552
|
+
'X-Frame-Options': 'DENY'
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
### Environment Separation
|
|
558
|
+
|
|
559
|
+
Separate credentials by environment:
|
|
560
|
+
|
|
561
|
+
```javascript
|
|
562
|
+
// Environment-specific authentication
|
|
563
|
+
const authConfig = {
|
|
564
|
+
development: {
|
|
565
|
+
did: 'did:atp:testnet:dev-service',
|
|
566
|
+
privateKey: process.env.DEV_PRIVATE_KEY,
|
|
567
|
+
trustedIssuers: ['did:atp:testnet:dev-issuer']
|
|
568
|
+
},
|
|
569
|
+
|
|
570
|
+
staging: {
|
|
571
|
+
did: 'did:atp:testnet:staging-service',
|
|
572
|
+
privateKey: process.env.STAGING_PRIVATE_KEY,
|
|
573
|
+
trustedIssuers: ['did:atp:testnet:staging-issuer']
|
|
574
|
+
},
|
|
575
|
+
|
|
576
|
+
production: {
|
|
577
|
+
did: 'did:atp:mainnet:prod-service',
|
|
578
|
+
privateKey: await loadFromSecureVault(),
|
|
579
|
+
trustedIssuers: ['did:atp:mainnet:prod-issuer'],
|
|
580
|
+
mfaRequired: true
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
const config = authConfig[process.env.NODE_ENV || 'development'];
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
### Monitoring and Auditing
|
|
588
|
+
|
|
589
|
+
Monitor authentication events:
|
|
590
|
+
|
|
591
|
+
```javascript
|
|
592
|
+
// Authentication event logging
|
|
593
|
+
client.on('auth:success', (event) => {
|
|
594
|
+
console.log(`Authentication successful: ${event.did}`);
|
|
595
|
+
|
|
596
|
+
// Log to audit service
|
|
597
|
+
client.audit.logEvent({
|
|
598
|
+
source: 'sdk-client',
|
|
599
|
+
action: 'authentication_success',
|
|
600
|
+
resource: 'auth:login',
|
|
601
|
+
actor: event.did,
|
|
602
|
+
details: {
|
|
603
|
+
method: event.method,
|
|
604
|
+
timestamp: new Date().toISOString(),
|
|
605
|
+
userAgent: process.env.USER_AGENT
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
client.on('auth:failure', (event) => {
|
|
611
|
+
console.error(`Authentication failed: ${event.error}`);
|
|
612
|
+
|
|
613
|
+
// Log security event
|
|
614
|
+
client.audit.logEvent({
|
|
615
|
+
source: 'sdk-client',
|
|
616
|
+
action: 'authentication_failure',
|
|
617
|
+
resource: 'auth:login',
|
|
618
|
+
details: {
|
|
619
|
+
error: event.error,
|
|
620
|
+
did: event.did,
|
|
621
|
+
timestamp: new Date().toISOString(),
|
|
622
|
+
severity: 'high'
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
});
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Error Handling
|
|
629
|
+
|
|
630
|
+
Handle authentication errors gracefully:
|
|
631
|
+
|
|
632
|
+
```javascript
|
|
633
|
+
async function safeAuthentication(client, credentials) {
|
|
634
|
+
try {
|
|
635
|
+
client.setAuthentication(credentials);
|
|
636
|
+
|
|
637
|
+
// Test authentication
|
|
638
|
+
await client.identity.resolve(credentials.did);
|
|
639
|
+
|
|
640
|
+
return { success: true };
|
|
641
|
+
|
|
642
|
+
} catch (error) {
|
|
643
|
+
if (error instanceof ATPAuthenticationError) {
|
|
644
|
+
switch (error.code) {
|
|
645
|
+
case 'INVALID_DID':
|
|
646
|
+
return { success: false, error: 'Invalid DID format' };
|
|
647
|
+
|
|
648
|
+
case 'INVALID_SIGNATURE':
|
|
649
|
+
return { success: false, error: 'Invalid private key' };
|
|
650
|
+
|
|
651
|
+
case 'MFA_REQUIRED':
|
|
652
|
+
return { success: false, error: 'MFA verification required', requiresMFA: true };
|
|
653
|
+
|
|
654
|
+
case 'TOKEN_EXPIRED':
|
|
655
|
+
return { success: false, error: 'Token has expired', requiresRefresh: true };
|
|
656
|
+
|
|
657
|
+
default:
|
|
658
|
+
return { success: false, error: 'Authentication failed' };
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
throw error; // Re-throw non-auth errors
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
This authentication guide covers all aspects of securing your ATP™ SDK integration. Always follow security best practices and regularly review your authentication implementation.
|