@egintegrations/auth-services 0.1.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 +28 -0
- package/LICENSE +21 -0
- package/README.md +554 -0
- package/dist/index.d.mts +68 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +223 -0
- package/dist/index.mjs +179 -0
- package/package.json +65 -0
- package/src/BiometricAuth.ts +119 -0
- package/src/SecureKeyStore.ts +58 -0
- package/src/TokenManager.ts +61 -0
- package/src/index.ts +20 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2026-01-22
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial release of @egintegrations/auth-services
|
|
12
|
+
- TokenManager - Generic token storage with secure store
|
|
13
|
+
- SingletonTokenManager - Singleton pattern for simple token management
|
|
14
|
+
- BiometricAuth - Configurable biometric authentication (Face ID / Touch ID)
|
|
15
|
+
- SecureKeyStore - Generic secure key/value storage with prefix support
|
|
16
|
+
- Convenience functions for direct secure storage access
|
|
17
|
+
- Comprehensive test suite with 100% coverage (69 tests)
|
|
18
|
+
- Full TypeScript support with type definitions
|
|
19
|
+
- ESM and CommonJS module support
|
|
20
|
+
|
|
21
|
+
### Notes
|
|
22
|
+
- Extracted from AutismTrainerApp authentication services
|
|
23
|
+
- Refactored to be configurable and reusable
|
|
24
|
+
- TokenManager supports custom storage keys
|
|
25
|
+
- BiometricAuth supports custom prompt messages and fallback labels
|
|
26
|
+
- SecureKeyStore supports key prefixes for namespace isolation
|
|
27
|
+
- Removed app-specific user management and role-based access control
|
|
28
|
+
- Works with Expo and bare React Native applications
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 EGI Integrations
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
# @egintegrations/auth-services
|
|
2
|
+
|
|
3
|
+
React Native authentication utilities for token management, biometric authentication, and secure key storage. Works with Expo and bare React Native.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **TokenManager**: Secure token storage and retrieval
|
|
8
|
+
- **BiometricAuth**: Face ID / Touch ID authentication
|
|
9
|
+
- **SecureKeyStore**: Generic secure key/value storage
|
|
10
|
+
- **TypeScript**: Full type safety with TypeScript support
|
|
11
|
+
- **Configurable**: Customizable storage keys, prompts, and behavior
|
|
12
|
+
- **Well-tested**: 100% test coverage (69 tests)
|
|
13
|
+
- **Dual Module**: ESM and CommonJS support
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @egintegrations/auth-services expo-secure-store expo-local-authentication
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Peer Dependencies
|
|
22
|
+
|
|
23
|
+
This package requires:
|
|
24
|
+
- `expo-secure-store` >= 12.0.0
|
|
25
|
+
- `expo-local-authentication` >= 13.0.0
|
|
26
|
+
- `react-native` >= 0.70.0
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { TokenManager, BiometricAuth, SecureKeyStore } from '@egintegrations/auth-services';
|
|
32
|
+
|
|
33
|
+
// Token management
|
|
34
|
+
const tokenManager = new TokenManager();
|
|
35
|
+
await tokenManager.saveToken('your-auth-token');
|
|
36
|
+
const token = await tokenManager.getToken();
|
|
37
|
+
|
|
38
|
+
// Biometric authentication
|
|
39
|
+
const bioAuth = new BiometricAuth();
|
|
40
|
+
if (await bioAuth.canAuthenticate()) {
|
|
41
|
+
await bioAuth.enable('username');
|
|
42
|
+
const username = await bioAuth.authenticate();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Secure key storage
|
|
46
|
+
const keyStore = new SecureKeyStore({ keyPrefix: 'app_' });
|
|
47
|
+
await keyStore.set('api_key', 'secret-key');
|
|
48
|
+
const apiKey = await keyStore.get('api_key');
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## TokenManager
|
|
52
|
+
|
|
53
|
+
Manages authentication tokens in secure storage.
|
|
54
|
+
|
|
55
|
+
### Basic Usage
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { TokenManager } from '@egintegrations/auth-services';
|
|
59
|
+
|
|
60
|
+
// Create manager with default storage key
|
|
61
|
+
const tokenManager = new TokenManager();
|
|
62
|
+
|
|
63
|
+
// Save token
|
|
64
|
+
await tokenManager.saveToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
|
|
65
|
+
|
|
66
|
+
// Get token
|
|
67
|
+
const token = await tokenManager.getToken();
|
|
68
|
+
|
|
69
|
+
// Check if token exists
|
|
70
|
+
const hasToken = await tokenManager.hasToken();
|
|
71
|
+
|
|
72
|
+
// Clear token
|
|
73
|
+
await tokenManager.clearToken();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Custom Storage Key
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// Use custom storage key for multiple token types
|
|
80
|
+
const accessTokenManager = new TokenManager({ storageKey: 'access_token' });
|
|
81
|
+
const refreshTokenManager = new TokenManager({ storageKey: 'refresh_token' });
|
|
82
|
+
|
|
83
|
+
await accessTokenManager.saveToken('access-token-123');
|
|
84
|
+
await refreshTokenManager.saveToken('refresh-token-456');
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Singleton Pattern
|
|
88
|
+
|
|
89
|
+
For simple apps with single token:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { SingletonTokenManager } from '@egintegrations/auth-services';
|
|
93
|
+
|
|
94
|
+
// All methods are static
|
|
95
|
+
await SingletonTokenManager.saveToken('token');
|
|
96
|
+
const token = await SingletonTokenManager.getToken();
|
|
97
|
+
const hasToken = await SingletonTokenManager.hasToken();
|
|
98
|
+
await SingletonTokenManager.clearToken();
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## BiometricAuth
|
|
102
|
+
|
|
103
|
+
Manages biometric authentication (Face ID / Touch ID).
|
|
104
|
+
|
|
105
|
+
### Check Availability
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { BiometricAuth } from '@egintegrations/auth-services';
|
|
109
|
+
|
|
110
|
+
const bioAuth = new BiometricAuth();
|
|
111
|
+
|
|
112
|
+
// Check if device supports biometric auth
|
|
113
|
+
const canAuth = await bioAuth.canAuthenticate();
|
|
114
|
+
|
|
115
|
+
// Get biometric type
|
|
116
|
+
const type = await bioAuth.getBiometricType(); // 'faceId' | 'touchId' | 'fingerprint' | 'none'
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Enable Biometric Login
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const bioAuth = new BiometricAuth();
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
// Prompt user to authenticate and enable biometric login
|
|
126
|
+
await bioAuth.enable('username');
|
|
127
|
+
console.log('Biometric login enabled');
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error('Failed to enable biometric:', error.message);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Authenticate with Biometrics
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
const bioAuth = new BiometricAuth();
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
// Prompt biometric authentication
|
|
140
|
+
const username = await bioAuth.authenticate();
|
|
141
|
+
console.log('Authenticated as:', username);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.error('Authentication failed:', error.message);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Custom Prompts
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const bioAuth = new BiometricAuth({
|
|
151
|
+
promptMessages: {
|
|
152
|
+
enable: 'Enable Face ID for MyApp',
|
|
153
|
+
authenticate: 'Sign in to MyApp',
|
|
154
|
+
},
|
|
155
|
+
fallbackLabel: 'Use Password',
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
await bioAuth.enable('user@example.com');
|
|
159
|
+
const username = await bioAuth.authenticate();
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Manage Saved Username
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
const bioAuth = new BiometricAuth();
|
|
166
|
+
|
|
167
|
+
// Save username without prompting
|
|
168
|
+
await bioAuth.saveUsername('newuser@example.com');
|
|
169
|
+
|
|
170
|
+
// Get saved username (only if biometric is enabled)
|
|
171
|
+
const savedUsername = await bioAuth.getSavedUsername();
|
|
172
|
+
|
|
173
|
+
// Clear saved username
|
|
174
|
+
await bioAuth.clearSavedUsername();
|
|
175
|
+
|
|
176
|
+
// Disable biometric completely
|
|
177
|
+
await bioAuth.disable();
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Complete Login Flow Example
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { BiometricAuth, TokenManager } from '@egintegrations/auth-services';
|
|
184
|
+
|
|
185
|
+
const bioAuth = new BiometricAuth();
|
|
186
|
+
const tokenManager = new TokenManager();
|
|
187
|
+
|
|
188
|
+
async function loginWithBiometric() {
|
|
189
|
+
try {
|
|
190
|
+
// Check if biometric is enabled
|
|
191
|
+
const isEnabled = await bioAuth.isEnabled();
|
|
192
|
+
|
|
193
|
+
if (!isEnabled) {
|
|
194
|
+
console.log('Biometric not enabled, use password login');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Authenticate
|
|
199
|
+
const username = await bioAuth.authenticate();
|
|
200
|
+
|
|
201
|
+
// Call your API to get token
|
|
202
|
+
const response = await fetch('https://api.example.com/auth/biometric', {
|
|
203
|
+
method: 'POST',
|
|
204
|
+
body: JSON.stringify({ username }),
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const { token } = await response.json();
|
|
208
|
+
|
|
209
|
+
// Save token
|
|
210
|
+
await tokenManager.saveToken(token);
|
|
211
|
+
|
|
212
|
+
console.log('Logged in as:', username);
|
|
213
|
+
} catch (error) {
|
|
214
|
+
console.error('Biometric login failed:', error.message);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## SecureKeyStore
|
|
220
|
+
|
|
221
|
+
Generic secure key-value storage with namespace support.
|
|
222
|
+
|
|
223
|
+
### Basic Usage
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
import { SecureKeyStore } from '@egintegrations/auth-services';
|
|
227
|
+
|
|
228
|
+
const store = new SecureKeyStore();
|
|
229
|
+
|
|
230
|
+
// Store value
|
|
231
|
+
await store.set('api_key', 'sk-1234567890');
|
|
232
|
+
|
|
233
|
+
// Retrieve value
|
|
234
|
+
const apiKey = await store.get('api_key');
|
|
235
|
+
|
|
236
|
+
// Check if key exists
|
|
237
|
+
const hasKey = await store.has('api_key');
|
|
238
|
+
|
|
239
|
+
// Delete key
|
|
240
|
+
await store.delete('api_key');
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Namespace Isolation
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
// Create separate stores for different purposes
|
|
247
|
+
const apiStore = new SecureKeyStore({ keyPrefix: 'api_' });
|
|
248
|
+
const userStore = new SecureKeyStore({ keyPrefix: 'user_' });
|
|
249
|
+
|
|
250
|
+
await apiStore.set('openai_key', 'sk-...');
|
|
251
|
+
await userStore.set('preference', 'dark_mode');
|
|
252
|
+
|
|
253
|
+
// Keys are isolated
|
|
254
|
+
const apiKeys = await apiStore.get('openai_key'); // Works
|
|
255
|
+
const userKeys = await userStore.get('openai_key'); // null (different namespace)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Clear Multiple Keys
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
const store = new SecureKeyStore({ keyPrefix: 'app_' });
|
|
262
|
+
|
|
263
|
+
await store.set('key1', 'value1');
|
|
264
|
+
await store.set('key2', 'value2');
|
|
265
|
+
await store.set('key3', 'value3');
|
|
266
|
+
|
|
267
|
+
// Clear specific keys
|
|
268
|
+
await store.clear(['key1', 'key2']);
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Convenience Functions
|
|
272
|
+
|
|
273
|
+
For simple use cases without creating a store instance:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import {
|
|
277
|
+
getSecureKey,
|
|
278
|
+
setSecureKey,
|
|
279
|
+
deleteSecureKey,
|
|
280
|
+
hasSecureKey,
|
|
281
|
+
} from '@egintegrations/auth-services';
|
|
282
|
+
|
|
283
|
+
// Direct access to secure storage (no prefix)
|
|
284
|
+
await setSecureKey('my_key', 'my_value');
|
|
285
|
+
const value = await getSecureKey('my_key');
|
|
286
|
+
const exists = await hasSecureKey('my_key');
|
|
287
|
+
await deleteSecureKey('my_key');
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Advanced Examples
|
|
291
|
+
|
|
292
|
+
### Complete Authentication System
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import {
|
|
296
|
+
TokenManager,
|
|
297
|
+
BiometricAuth,
|
|
298
|
+
SecureKeyStore,
|
|
299
|
+
} from '@egintegrations/auth-services';
|
|
300
|
+
|
|
301
|
+
class AuthService {
|
|
302
|
+
private tokenManager = new TokenManager();
|
|
303
|
+
private bioAuth = new BiometricAuth({
|
|
304
|
+
promptMessages: {
|
|
305
|
+
enable: 'Enable Face ID for faster login',
|
|
306
|
+
authenticate: 'Authenticate to continue',
|
|
307
|
+
},
|
|
308
|
+
});
|
|
309
|
+
private keyStore = new SecureKeyStore({ keyPrefix: 'auth_' });
|
|
310
|
+
|
|
311
|
+
async login(username: string, password: string): Promise<void> {
|
|
312
|
+
// Call your API
|
|
313
|
+
const response = await fetch('https://api.example.com/login', {
|
|
314
|
+
method: 'POST',
|
|
315
|
+
headers: { 'Content-Type': 'application/json' },
|
|
316
|
+
body: JSON.stringify({ username, password }),
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
const { token } = await response.json();
|
|
320
|
+
|
|
321
|
+
// Save token
|
|
322
|
+
await this.tokenManager.saveToken(token);
|
|
323
|
+
|
|
324
|
+
// Offer biometric enrollment if available
|
|
325
|
+
const canAuth = await this.bioAuth.canAuthenticate();
|
|
326
|
+
if (canAuth) {
|
|
327
|
+
await this.bioAuth.enable(username);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async loginWithBiometric(): Promise<void> {
|
|
332
|
+
const username = await this.bioAuth.authenticate();
|
|
333
|
+
|
|
334
|
+
// Exchange biometric authentication for token
|
|
335
|
+
const response = await fetch('https://api.example.com/auth/biometric', {
|
|
336
|
+
method: 'POST',
|
|
337
|
+
headers: { 'Content-Type': 'application/json' },
|
|
338
|
+
body: JSON.stringify({ username }),
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const { token } = await response.json();
|
|
342
|
+
await this.tokenManager.saveToken(token);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async logout(): Promise<void> {
|
|
346
|
+
await this.tokenManager.clearToken();
|
|
347
|
+
// Keep biometric enabled for next login
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
async getAuthToken(): Promise<string | null> {
|
|
351
|
+
return this.tokenManager.getToken();
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async isAuthenticated(): Promise<boolean> {
|
|
355
|
+
return this.tokenManager.hasToken();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
async saveApiKey(service: string, key: string): Promise<void> {
|
|
359
|
+
await this.keyStore.set(`${service}_key`, key);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async getApiKey(service: string): Promise<string | null> {
|
|
363
|
+
return this.keyStore.get(`${service}_key`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Usage
|
|
368
|
+
const auth = new AuthService();
|
|
369
|
+
|
|
370
|
+
// Normal login
|
|
371
|
+
await auth.login('user@example.com', 'password123');
|
|
372
|
+
|
|
373
|
+
// Biometric login
|
|
374
|
+
if (await auth.bioAuth.canAuthenticate()) {
|
|
375
|
+
await auth.loginWithBiometric();
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Get auth token for API calls
|
|
379
|
+
const token = await auth.getAuthToken();
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### API Integration with TokenManager
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
import { TokenManager } from '@egintegrations/auth-services';
|
|
386
|
+
import { ApiClient } from '@egintegrations/api-client';
|
|
387
|
+
|
|
388
|
+
const tokenManager = new TokenManager();
|
|
389
|
+
|
|
390
|
+
// Create API client
|
|
391
|
+
const apiClient = new ApiClient({
|
|
392
|
+
baseUrl: 'https://api.example.com',
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// Add token to all requests
|
|
396
|
+
apiClient.addRequestInterceptor(async (config) => {
|
|
397
|
+
const token = await tokenManager.getToken();
|
|
398
|
+
if (token) {
|
|
399
|
+
config.headers = config.headers || {};
|
|
400
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
401
|
+
}
|
|
402
|
+
return config;
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Handle 401 errors
|
|
406
|
+
apiClient.addErrorInterceptor(async (error) => {
|
|
407
|
+
if (error.response?.status === 401) {
|
|
408
|
+
await tokenManager.clearToken();
|
|
409
|
+
// Redirect to login
|
|
410
|
+
}
|
|
411
|
+
throw error;
|
|
412
|
+
});
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## API Reference
|
|
416
|
+
|
|
417
|
+
### TokenManager
|
|
418
|
+
|
|
419
|
+
#### Constructor
|
|
420
|
+
```typescript
|
|
421
|
+
new TokenManager(config?: TokenManagerConfig)
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**Config:**
|
|
425
|
+
- `storageKey?: string` - Storage key (default: 'auth_token')
|
|
426
|
+
|
|
427
|
+
#### Methods
|
|
428
|
+
- `getToken(): Promise<string | null>` - Get stored token
|
|
429
|
+
- `saveToken(token: string): Promise<void>` - Save token
|
|
430
|
+
- `clearToken(): Promise<void>` - Delete token
|
|
431
|
+
- `hasToken(): Promise<boolean>` - Check if token exists
|
|
432
|
+
|
|
433
|
+
### SingletonTokenManager
|
|
434
|
+
|
|
435
|
+
Static methods matching TokenManager interface.
|
|
436
|
+
|
|
437
|
+
### BiometricAuth
|
|
438
|
+
|
|
439
|
+
#### Constructor
|
|
440
|
+
```typescript
|
|
441
|
+
new BiometricAuth(config?: BiometricAuthConfig)
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
**Config:**
|
|
445
|
+
- `savedUsernameKey?: string` - Username storage key (default: 'biometric_username')
|
|
446
|
+
- `enabledKey?: string` - Enabled flag key (default: 'biometric_enabled')
|
|
447
|
+
- `promptMessages?: { enable?: string, authenticate?: string }` - Custom prompts
|
|
448
|
+
- `fallbackLabel?: string` - Fallback button label (default: 'Use password')
|
|
449
|
+
|
|
450
|
+
#### Methods
|
|
451
|
+
- `canAuthenticate(): Promise<boolean>` - Check device support
|
|
452
|
+
- `isEnabled(): Promise<boolean>` - Check if biometric enabled
|
|
453
|
+
- `enable(username: string): Promise<void>` - Enable biometric login
|
|
454
|
+
- `disable(): Promise<void>` - Disable biometric login
|
|
455
|
+
- `getBiometricType(): Promise<BiometricType>` - Get biometric type
|
|
456
|
+
- `authenticate(): Promise<string>` - Authenticate and get username
|
|
457
|
+
- `saveUsername(username: string): Promise<void>` - Save username
|
|
458
|
+
- `clearSavedUsername(): Promise<void>` - Clear username
|
|
459
|
+
- `getSavedUsername(): Promise<string | null>` - Get saved username
|
|
460
|
+
|
|
461
|
+
### SecureKeyStore
|
|
462
|
+
|
|
463
|
+
#### Constructor
|
|
464
|
+
```typescript
|
|
465
|
+
new SecureKeyStore(config?: SecureKeyStoreConfig)
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Config:**
|
|
469
|
+
- `keyPrefix?: string` - Key prefix for namespace isolation (default: 'secure_key_')
|
|
470
|
+
|
|
471
|
+
#### Methods
|
|
472
|
+
- `get(key: string): Promise<string | null>` - Get value
|
|
473
|
+
- `set(key: string, value: string): Promise<void>` - Set value
|
|
474
|
+
- `delete(key: string): Promise<void>` - Delete key
|
|
475
|
+
- `has(key: string): Promise<boolean>` - Check if key exists
|
|
476
|
+
- `clear(keys?: string[]): Promise<void>` - Clear multiple keys
|
|
477
|
+
|
|
478
|
+
## Error Handling
|
|
479
|
+
|
|
480
|
+
All methods can throw errors. Always use try-catch:
|
|
481
|
+
|
|
482
|
+
```typescript
|
|
483
|
+
try {
|
|
484
|
+
await tokenManager.saveToken(token);
|
|
485
|
+
} catch (error) {
|
|
486
|
+
console.error('Failed to save token:', error);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
try {
|
|
490
|
+
const username = await bioAuth.authenticate();
|
|
491
|
+
} catch (error) {
|
|
492
|
+
console.error('Biometric auth failed:', error.message);
|
|
493
|
+
// Handle failure (show password login)
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## Development
|
|
498
|
+
|
|
499
|
+
```bash
|
|
500
|
+
# Install dependencies
|
|
501
|
+
npm install
|
|
502
|
+
|
|
503
|
+
# Build
|
|
504
|
+
npm run build
|
|
505
|
+
|
|
506
|
+
# Run tests
|
|
507
|
+
npm test
|
|
508
|
+
|
|
509
|
+
# Run tests with coverage
|
|
510
|
+
npm test -- --coverage
|
|
511
|
+
|
|
512
|
+
# Type check
|
|
513
|
+
npm run typecheck
|
|
514
|
+
|
|
515
|
+
# Lint
|
|
516
|
+
npm run lint
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
## Contributing
|
|
520
|
+
|
|
521
|
+
Contributions are welcome! Please ensure:
|
|
522
|
+
|
|
523
|
+
1. All tests pass (`npm test`)
|
|
524
|
+
2. Code coverage remains 100%
|
|
525
|
+
3. TypeScript types are properly defined
|
|
526
|
+
4. Code follows the existing style (run `npm run lint`)
|
|
527
|
+
|
|
528
|
+
## License
|
|
529
|
+
|
|
530
|
+
MIT © EGI Integrations
|
|
531
|
+
|
|
532
|
+
## Extracted From
|
|
533
|
+
|
|
534
|
+
This package was extracted from AutismTrainerApp's authentication services and refactored to be reusable across React Native applications.
|
|
535
|
+
|
|
536
|
+
**What was removed:**
|
|
537
|
+
- App-specific user management (roles, permissions, progress tracking)
|
|
538
|
+
- Local user database and AsyncStorage user management
|
|
539
|
+
- Supervised user relationships
|
|
540
|
+
- Application-specific authentication flows
|
|
541
|
+
|
|
542
|
+
**What was kept and improved:**
|
|
543
|
+
- Token management (now configurable)
|
|
544
|
+
- Biometric authentication (now with custom prompts)
|
|
545
|
+
- Secure key storage (now with namespace support)
|
|
546
|
+
|
|
547
|
+
## Related Packages
|
|
548
|
+
|
|
549
|
+
- [@egintegrations/api-client](https://www.npmjs.com/package/@egintegrations/api-client) - HTTP client for API integrations
|
|
550
|
+
- [@egintegrations/core-utils](https://www.npmjs.com/package/@egintegrations/core-utils) - Utility functions
|
|
551
|
+
|
|
552
|
+
## Support
|
|
553
|
+
|
|
554
|
+
For issues and questions, please open an issue on [GitHub](https://github.com/EGIntegrations/egi-comp-library/issues).
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
interface TokenManagerConfig {
|
|
2
|
+
storageKey?: string;
|
|
3
|
+
}
|
|
4
|
+
declare class TokenManager {
|
|
5
|
+
private storageKey;
|
|
6
|
+
constructor(config?: TokenManagerConfig);
|
|
7
|
+
getToken(): Promise<string | null>;
|
|
8
|
+
saveToken(token: string): Promise<void>;
|
|
9
|
+
clearToken(): Promise<void>;
|
|
10
|
+
hasToken(): Promise<boolean>;
|
|
11
|
+
}
|
|
12
|
+
declare class SingletonTokenManager {
|
|
13
|
+
private static instance;
|
|
14
|
+
private static defaultKey;
|
|
15
|
+
private constructor();
|
|
16
|
+
static getInstance(storageKey?: string): TokenManager;
|
|
17
|
+
static getToken(): Promise<string | null>;
|
|
18
|
+
static saveToken(token: string): Promise<void>;
|
|
19
|
+
static clearToken(): Promise<void>;
|
|
20
|
+
static hasToken(): Promise<boolean>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface BiometricAuthConfig {
|
|
24
|
+
savedUsernameKey?: string;
|
|
25
|
+
enabledKey?: string;
|
|
26
|
+
promptMessages?: {
|
|
27
|
+
enable?: string;
|
|
28
|
+
authenticate?: string;
|
|
29
|
+
};
|
|
30
|
+
fallbackLabel?: string;
|
|
31
|
+
}
|
|
32
|
+
type BiometricType = 'faceId' | 'touchId' | 'fingerprint' | 'none';
|
|
33
|
+
declare class BiometricAuth {
|
|
34
|
+
private savedUsernameKey;
|
|
35
|
+
private enabledKey;
|
|
36
|
+
private promptMessages;
|
|
37
|
+
private fallbackLabel;
|
|
38
|
+
constructor(config?: BiometricAuthConfig);
|
|
39
|
+
canAuthenticate(): Promise<boolean>;
|
|
40
|
+
isEnabled(): Promise<boolean>;
|
|
41
|
+
enable(username: string): Promise<void>;
|
|
42
|
+
disable(): Promise<void>;
|
|
43
|
+
getBiometricType(): Promise<BiometricType>;
|
|
44
|
+
authenticate(): Promise<string>;
|
|
45
|
+
saveUsername(username: string): Promise<void>;
|
|
46
|
+
clearSavedUsername(): Promise<void>;
|
|
47
|
+
getSavedUsername(): Promise<string | null>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface SecureKeyStoreConfig {
|
|
51
|
+
keyPrefix?: string;
|
|
52
|
+
}
|
|
53
|
+
declare class SecureKeyStore {
|
|
54
|
+
private keyPrefix;
|
|
55
|
+
constructor(config?: SecureKeyStoreConfig);
|
|
56
|
+
private getFullKey;
|
|
57
|
+
get(key: string): Promise<string | null>;
|
|
58
|
+
set(key: string, value: string): Promise<void>;
|
|
59
|
+
delete(key: string): Promise<void>;
|
|
60
|
+
has(key: string): Promise<boolean>;
|
|
61
|
+
clear(keys?: string[]): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
declare function getSecureKey(key: string): Promise<string | null>;
|
|
64
|
+
declare function setSecureKey(key: string, value: string): Promise<void>;
|
|
65
|
+
declare function deleteSecureKey(key: string): Promise<void>;
|
|
66
|
+
declare function hasSecureKey(key: string): Promise<boolean>;
|
|
67
|
+
|
|
68
|
+
export { BiometricAuth, type BiometricAuthConfig, type BiometricType, SecureKeyStore, type SecureKeyStoreConfig, SingletonTokenManager, TokenManager, type TokenManagerConfig, deleteSecureKey, getSecureKey, hasSecureKey, setSecureKey };
|