0
# Security & Authentication
1
2
Biometric authentication, secure storage, device security features, and advanced authentication methods for protecting user data and ensuring app security.
3
4
## Capabilities
5
6
### Touch ID Authentication
7
8
iOS Touch ID fingerprint authentication for secure app access and user verification.
9
10
```typescript { .api }
11
/**
12
* TouchID class for iOS fingerprint authentication
13
*/
14
class TouchID {
15
/**
16
* Check if Touch ID is available on device
17
* @returns Promise resolving to availability status string
18
*/
19
static isAvailable(): Promise<string>;
20
21
/**
22
* Verify fingerprint with default message
23
* @param message Message to display in authentication dialog
24
* @returns Promise indicating authentication success
25
*/
26
static verifyFingerprint(message: string): Promise<any>;
27
28
/**
29
* Verify fingerprint with custom password fallback
30
* @param message Message to display in authentication dialog
31
* @returns Promise indicating authentication success
32
*/
33
static verifyFingerprintWithCustomPasswordFallback(message: string): Promise<any>;
34
35
/**
36
* Verify fingerprint with custom labels and password fallback
37
* @param message Message to display in authentication dialog
38
* @param enterPasswordLabel Label for password entry button
39
* @returns Promise indicating authentication success
40
*/
41
static verifyFingerprintWithCustomPasswordFallbackAndEnterPasswordLabel(message: string, enterPasswordLabel: string): Promise<any>;
42
}
43
```
44
45
**Usage Examples:**
46
47
```typescript
48
import { TouchID } from 'ionic-native';
49
50
// Touch ID authentication service
51
class TouchIDService {
52
53
async checkAvailability(): Promise<boolean> {
54
try {
55
const result = await TouchID.isAvailable();
56
console.log('Touch ID availability:', result);
57
return true;
58
} catch (error) {
59
console.log('Touch ID not available:', error);
60
return false;
61
}
62
}
63
64
async authenticate(reason: string = 'Authenticate to access the app'): Promise<boolean> {
65
try {
66
const isAvailable = await this.checkAvailability();
67
if (!isAvailable) {
68
throw new Error('Touch ID not available');
69
}
70
71
await TouchID.verifyFingerprint(reason);
72
console.log('Touch ID authentication successful');
73
return true;
74
} catch (error) {
75
console.error('Touch ID authentication failed:', error);
76
return false;
77
}
78
}
79
80
async authenticateWithFallback(reason: string = 'Authenticate to continue'): Promise<boolean> {
81
try {
82
await TouchID.verifyFingerprintWithCustomPasswordFallback(reason);
83
console.log('Authentication successful (Touch ID or passcode)');
84
return true;
85
} catch (error) {
86
console.error('Authentication failed:', error);
87
return false;
88
}
89
}
90
91
async authenticateWithCustomLabels(
92
reason: string = 'Verify your identity',
93
passwordLabel: string = 'Enter Passcode'
94
): Promise<boolean> {
95
try {
96
await TouchID.verifyFingerprintWithCustomPasswordFallbackAndEnterPasswordLabel(reason, passwordLabel);
97
console.log('Authentication successful with custom labels');
98
return true;
99
} catch (error) {
100
console.error('Authentication with custom labels failed:', error);
101
return false;
102
}
103
}
104
}
105
106
// Usage in app
107
const touchID = new TouchIDService();
108
109
// Check and authenticate
110
async function secureLaunch() {
111
const available = await touchID.checkAvailability();
112
113
if (available) {
114
const authenticated = await touchID.authenticate('Please verify your identity to access your account');
115
116
if (authenticated) {
117
// Proceed to main app
118
navigateToMainApp();
119
} else {
120
// Handle authentication failure
121
showAuthenticationError();
122
}
123
} else {
124
// Fallback to other authentication methods
125
showPasswordLogin();
126
}
127
}
128
```
129
130
### Fingerprint AIO (All-in-One)
131
132
Cross-platform fingerprint authentication supporting both iOS and Android devices.
133
134
```typescript { .api }
135
/**
136
* Fingerprint authentication options
137
*/
138
interface FingerprintOptions {
139
/** Client ID for keychain access */
140
clientId: string;
141
/** Client secret for additional security */
142
clientSecret: string;
143
/** Disable backup authentication methods */
144
disableBackup?: boolean;
145
/** Localized fallback title */
146
localizedFallbackTitle?: string;
147
/** Localized cancel title */
148
localizedCancelTitle?: string;
149
}
150
151
/**
152
* FingerprintAIO class for cross-platform fingerprint authentication
153
*/
154
class FingerprintAIO {
155
/**
156
* Check if fingerprint authentication is available
157
* @returns Promise resolving to availability information
158
*/
159
static isAvailable(): Promise<any>;
160
161
/**
162
* Show fingerprint authentication dialog
163
* @param options Authentication configuration options
164
* @returns Promise indicating authentication result
165
*/
166
static show(options: FingerprintOptions): Promise<any>;
167
}
168
```
169
170
**Usage Examples:**
171
172
```typescript
173
import { FingerprintAIO, FingerprintOptions } from 'ionic-native';
174
175
// Cross-platform fingerprint authentication
176
class BiometricAuthService {
177
178
async checkBiometricSupport(): Promise<{
179
available: boolean;
180
type?: string;
181
hasEnrolledFingerprints?: boolean;
182
}> {
183
try {
184
const result = await FingerprintAIO.isAvailable();
185
186
return {
187
available: true,
188
type: result.type, // 'finger' or 'face'
189
hasEnrolledFingerprints: result.hasEnrolledFingerprints
190
};
191
} catch (error) {
192
console.log('Biometric authentication not available:', error);
193
return { available: false };
194
}
195
}
196
197
async authenticate(options: {
198
title?: string;
199
subtitle?: string;
200
description?: string;
201
fallbackEnabled?: boolean;
202
} = {}): Promise<boolean> {
203
try {
204
const support = await this.checkBiometricSupport();
205
if (!support.available) {
206
throw new Error('Biometric authentication not available');
207
}
208
209
if (!support.hasEnrolledFingerprints) {
210
throw new Error('No biometrics enrolled on device');
211
}
212
213
const fingerprintOptions: FingerprintOptions = {
214
clientId: 'myAppBiometric',
215
clientSecret: 'password123', // Use secure secret in production
216
disableBackup: !options.fallbackEnabled,
217
localizedFallbackTitle: 'Use Password',
218
localizedCancelTitle: 'Cancel'
219
};
220
221
await FingerprintAIO.show(fingerprintOptions);
222
console.log('Biometric authentication successful');
223
return true;
224
225
} catch (error) {
226
console.error('Biometric authentication failed:', error);
227
228
// Handle specific error cases
229
if (error.message === 'BiometricLockedOut') {
230
throw new Error('Too many failed attempts. Please try again later.');
231
} else if (error.message === 'BiometricNotEnrolled') {
232
throw new Error('No biometrics enrolled. Please set up biometric authentication in device settings.');
233
} else if (error.message === 'UserCancel') {
234
throw new Error('Authentication cancelled by user');
235
}
236
237
return false;
238
}
239
}
240
241
async authenticateForPayment(amount: number, currency: string = 'USD'): Promise<boolean> {
242
return await this.authenticate({
243
title: 'Authenticate Payment',
244
subtitle: `Confirm payment of ${amount} ${currency}`,
245
description: 'Place your finger on the sensor to authorize this transaction',
246
fallbackEnabled: true
247
});
248
}
249
250
async authenticateForSensitiveData(): Promise<boolean> {
251
return await this.authenticate({
252
title: 'Access Sensitive Data',
253
subtitle: 'Biometric verification required',
254
description: 'Verify your identity to view sensitive information',
255
fallbackEnabled: false
256
});
257
}
258
}
259
260
// Enhanced biometric service with security features
261
class SecureBiometricService extends BiometricAuthService {
262
private maxAttempts = 3;
263
private attemptCount = 0;
264
private lockoutTime = 30000; // 30 seconds
265
private isLockedOut = false;
266
267
async secureAuthenticate(purpose: string): Promise<boolean> {
268
if (this.isLockedOut) {
269
throw new Error('Authentication temporarily locked due to too many failed attempts');
270
}
271
272
try {
273
const result = await this.authenticate({
274
title: 'Secure Authentication',
275
subtitle: purpose,
276
description: 'Verify your identity to continue',
277
fallbackEnabled: true
278
});
279
280
// Reset attempt counter on success
281
this.attemptCount = 0;
282
return result;
283
284
} catch (error) {
285
this.attemptCount++;
286
287
if (this.attemptCount >= this.maxAttempts) {
288
this.lockoutUser();
289
}
290
291
throw error;
292
}
293
}
294
295
private lockoutUser() {
296
this.isLockedOut = true;
297
console.warn('User locked out due to too many failed authentication attempts');
298
299
// Auto-unlock after timeout
300
setTimeout(() => {
301
this.isLockedOut = false;
302
this.attemptCount = 0;
303
console.log('Authentication lockout expired');
304
}, this.lockoutTime);
305
}
306
307
getRemainingAttempts(): number {
308
return Math.max(0, this.maxAttempts - this.attemptCount);
309
}
310
311
isCurrentlyLockedOut(): boolean {
312
return this.isLockedOut;
313
}
314
}
315
```
316
317
### Secure Storage Implementation
318
319
Advanced secure storage implementation with encryption and key management.
320
321
```typescript { .api }
322
/**
323
* Advanced secure storage service with encryption
324
*/
325
class AdvancedSecureStorage {
326
private storage: any;
327
private encryptionKey: string;
328
329
async initialize(storeName: string = 'secure_app_store'): Promise<void> {
330
try {
331
const secureStorage = new SecureStorage();
332
this.storage = await secureStorage.create(storeName);
333
334
// Generate or retrieve encryption key
335
this.encryptionKey = await this.getOrCreateEncryptionKey();
336
337
console.log('Secure storage initialized');
338
} catch (error) {
339
console.error('Secure storage initialization failed:', error);
340
throw error;
341
}
342
}
343
344
async storeSecureData(key: string, data: any, requireBiometric: boolean = false): Promise<void> {
345
try {
346
if (requireBiometric) {
347
const biometricService = new BiometricAuthService();
348
const authenticated = await biometricService.authenticate({
349
title: 'Secure Data Storage',
350
subtitle: 'Authenticate to store sensitive data',
351
fallbackEnabled: true
352
});
353
354
if (!authenticated) {
355
throw new Error('Biometric authentication required for secure storage');
356
}
357
}
358
359
// Encrypt data before storage
360
const encryptedData = this.encrypt(JSON.stringify(data));
361
await this.storage.set(key, encryptedData);
362
363
console.log(`Secure data stored with key: ${key}`);
364
} catch (error) {
365
console.error('Secure data storage failed:', error);
366
throw error;
367
}
368
}
369
370
async retrieveSecureData(key: string, requireBiometric: boolean = false): Promise<any> {
371
try {
372
if (requireBiometric) {
373
const biometricService = new BiometricAuthService();
374
const authenticated = await biometricService.authenticate({
375
title: 'Access Secure Data',
376
subtitle: 'Authenticate to access sensitive data',
377
fallbackEnabled: true
378
});
379
380
if (!authenticated) {
381
throw new Error('Biometric authentication required for secure access');
382
}
383
}
384
385
const encryptedData = await this.storage.get(key);
386
387
if (!encryptedData) {
388
return null;
389
}
390
391
// Decrypt data after retrieval
392
const decryptedData = this.decrypt(encryptedData);
393
return JSON.parse(decryptedData);
394
395
} catch (error) {
396
console.error('Secure data retrieval failed:', error);
397
throw error;
398
}
399
}
400
401
async removeSecureData(key: string, requireBiometric: boolean = false): Promise<void> {
402
try {
403
if (requireBiometric) {
404
const biometricService = new BiometricAuthService();
405
const authenticated = await biometricService.authenticate({
406
title: 'Remove Secure Data',
407
subtitle: 'Authenticate to remove sensitive data',
408
fallbackEnabled: true
409
});
410
411
if (!authenticated) {
412
throw new Error('Biometric authentication required for secure removal');
413
}
414
}
415
416
await this.storage.remove(key);
417
console.log(`Secure data removed for key: ${key}`);
418
} catch (error) {
419
console.error('Secure data removal failed:', error);
420
throw error;
421
}
422
}
423
424
async listSecureKeys(): Promise<string[]> {
425
try {
426
return await this.storage.keys();
427
} catch (error) {
428
console.error('Failed to list secure keys:', error);
429
return [];
430
}
431
}
432
433
async clearAllSecureData(requireBiometric: boolean = true): Promise<void> {
434
try {
435
if (requireBiometric) {
436
const biometricService = new BiometricAuthService();
437
const authenticated = await biometricService.authenticate({
438
title: 'Clear All Data',
439
subtitle: 'Authenticate to clear all secure data',
440
description: 'This action cannot be undone',
441
fallbackEnabled: true
442
});
443
444
if (!authenticated) {
445
throw new Error('Biometric authentication required to clear all data');
446
}
447
}
448
449
await this.storage.clear();
450
console.log('All secure data cleared');
451
} catch (error) {
452
console.error('Failed to clear secure data:', error);
453
throw error;
454
}
455
}
456
457
private async getOrCreateEncryptionKey(): Promise<string> {
458
try {
459
let key = await this.storage.get('_encryption_key');
460
461
if (!key) {
462
key = this.generateEncryptionKey();
463
await this.storage.set('_encryption_key', key);
464
}
465
466
return key;
467
} catch (error) {
468
console.error('Encryption key management failed:', error);
469
throw error;
470
}
471
}
472
473
private generateEncryptionKey(): string {
474
// Simple key generation (use proper crypto library in production)
475
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
476
let key = '';
477
for (let i = 0; i < 32; i++) {
478
key += chars.charAt(Math.floor(Math.random() * chars.length));
479
}
480
return key;
481
}
482
483
private encrypt(data: string): string {
484
// Simple XOR encryption (use proper encryption in production)
485
let encrypted = '';
486
for (let i = 0; i < data.length; i++) {
487
const keyChar = this.encryptionKey.charCodeAt(i % this.encryptionKey.length);
488
const dataChar = data.charCodeAt(i);
489
encrypted += String.fromCharCode(dataChar ^ keyChar);
490
}
491
return btoa(encrypted); // Base64 encode
492
}
493
494
private decrypt(encryptedData: string): string {
495
const data = atob(encryptedData); // Base64 decode
496
let decrypted = '';
497
for (let i = 0; i < data.length; i++) {
498
const keyChar = this.encryptionKey.charCodeAt(i % this.encryptionKey.length);
499
const dataChar = data.charCodeAt(i);
500
decrypted += String.fromCharCode(dataChar ^ keyChar);
501
}
502
return decrypted;
503
}
504
}
505
```
506
507
### Authentication Manager
508
509
Comprehensive authentication system combining multiple security layers.
510
511
```typescript
512
// Multi-factor authentication manager
513
class AuthenticationManager {
514
private biometricService: SecureBiometricService;
515
private secureStorage: AdvancedSecureStorage;
516
private sessionTimeout = 300000; // 5 minutes
517
private sessionTimer: any;
518
519
constructor() {
520
this.biometricService = new SecureBiometricService();
521
this.secureStorage = new AdvancedSecureStorage();
522
}
523
524
async initialize(): Promise<void> {
525
await this.secureStorage.initialize('auth_manager_store');
526
this.startSessionManager();
527
}
528
529
async authenticateUser(options: {
530
requireBiometric?: boolean;
531
purpose?: string;
532
sessionDuration?: number;
533
} = {}): Promise<{
534
success: boolean;
535
sessionToken?: string;
536
expiresAt?: Date;
537
}> {
538
try {
539
let authenticated = false;
540
541
if (options.requireBiometric) {
542
const support = await this.biometricService.checkBiometricSupport();
543
544
if (support.available && support.hasEnrolledFingerprints) {
545
authenticated = await this.biometricService.secureAuthenticate(
546
options.purpose || 'Authenticate to access the application'
547
);
548
} else {
549
throw new Error('Biometric authentication required but not available');
550
}
551
} else {
552
// Try biometric first, fallback to other methods
553
try {
554
authenticated = await this.biometricService.secureAuthenticate(
555
options.purpose || 'Verify your identity'
556
);
557
} catch (error) {
558
// Fallback to PIN/Password
559
authenticated = await this.showPasswordPrompt();
560
}
561
}
562
563
if (authenticated) {
564
const sessionToken = this.generateSessionToken();
565
const expiresAt = new Date(Date.now() + (options.sessionDuration || this.sessionTimeout));
566
567
// Store session info securely
568
await this.secureStorage.storeSecureData('active_session', {
569
token: sessionToken,
570
expiresAt: expiresAt.toISOString(),
571
createdAt: new Date().toISOString()
572
});
573
574
this.resetSessionTimer();
575
576
return {
577
success: true,
578
sessionToken,
579
expiresAt
580
};
581
}
582
583
return { success: false };
584
585
} catch (error) {
586
console.error('Authentication failed:', error);
587
return { success: false };
588
}
589
}
590
591
async validateSession(): Promise<boolean> {
592
try {
593
const sessionData = await this.secureStorage.retrieveSecureData('active_session');
594
595
if (!sessionData) {
596
return false;
597
}
598
599
const expiresAt = new Date(sessionData.expiresAt);
600
const now = new Date();
601
602
if (now > expiresAt) {
603
await this.endSession();
604
return false;
605
}
606
607
return true;
608
} catch (error) {
609
console.error('Session validation failed:', error);
610
return false;
611
}
612
}
613
614
async endSession(): Promise<void> {
615
try {
616
await this.secureStorage.removeSecureData('active_session');
617
this.clearSessionTimer();
618
console.log('Session ended');
619
} catch (error) {
620
console.error('Failed to end session:', error);
621
}
622
}
623
624
async extendSession(additionalTime: number = 300000): Promise<void> {
625
try {
626
const sessionData = await this.secureStorage.retrieveSecureData('active_session');
627
628
if (sessionData) {
629
const newExpiresAt = new Date(Date.now() + additionalTime);
630
sessionData.expiresAt = newExpiresAt.toISOString();
631
632
await this.secureStorage.storeSecureData('active_session', sessionData);
633
this.resetSessionTimer();
634
635
console.log('Session extended until:', newExpiresAt);
636
}
637
} catch (error) {
638
console.error('Failed to extend session:', error);
639
}
640
}
641
642
async requireSecureAccess(action: string): Promise<boolean> {
643
// Check if user has current valid session
644
const hasValidSession = await this.validateSession();
645
646
if (!hasValidSession) {
647
// Require fresh authentication
648
const authResult = await this.authenticateUser({
649
requireBiometric: true,
650
purpose: `Authenticate to ${action}`
651
});
652
653
return authResult.success;
654
}
655
656
// For sensitive operations, require fresh biometric even with valid session
657
if (this.isSensitiveAction(action)) {
658
return await this.biometricService.secureAuthenticate(`Confirm ${action}`);
659
}
660
661
return true;
662
}
663
664
private isSensitiveAction(action: string): boolean {
665
const sensitiveActions = [
666
'delete account',
667
'change password',
668
'export data',
669
'financial transaction',
670
'modify security settings'
671
];
672
673
return sensitiveActions.some(sensitive =>
674
action.toLowerCase().includes(sensitive)
675
);
676
}
677
678
private generateSessionToken(): string {
679
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
680
let token = '';
681
for (let i = 0; i < 64; i++) {
682
token += chars.charAt(Math.floor(Math.random() * chars.length));
683
}
684
return token;
685
}
686
687
private async showPasswordPrompt(): Promise<boolean> {
688
// Implement custom password/PIN prompt
689
// This would show a secure input dialog
690
return new Promise((resolve) => {
691
// Placeholder implementation
692
const password = prompt('Enter your password:');
693
resolve(password === 'correct_password'); // Replace with real validation
694
});
695
}
696
697
private startSessionManager(): void {
698
// Check session validity periodically
699
setInterval(async () => {
700
const isValid = await this.validateSession();
701
if (!isValid) {
702
this.onSessionExpired();
703
}
704
}, 60000); // Check every minute
705
}
706
707
private resetSessionTimer(): void {
708
this.clearSessionTimer();
709
this.sessionTimer = setTimeout(() => {
710
this.endSession();
711
this.onSessionExpired();
712
}, this.sessionTimeout);
713
}
714
715
private clearSessionTimer(): void {
716
if (this.sessionTimer) {
717
clearTimeout(this.sessionTimer);
718
this.sessionTimer = null;
719
}
720
}
721
722
private onSessionExpired(): void {
723
console.log('Session expired - user needs to re-authenticate');
724
// Implement UI to handle session expiry
725
// e.g., redirect to login screen, show re-auth dialog
726
}
727
}
728
729
// Usage example
730
const authManager = new AuthenticationManager();
731
732
async function secureAppFlow() {
733
await authManager.initialize();
734
735
// Authenticate user on app start
736
const authResult = await authManager.authenticateUser({
737
requireBiometric: false,
738
purpose: 'Access your account'
739
});
740
741
if (authResult.success) {
742
console.log('User authenticated successfully');
743
744
// Later, for sensitive operations
745
const canDelete = await authManager.requireSecureAccess('delete account');
746
if (canDelete) {
747
// Proceed with sensitive operation
748
console.log('User authorized for sensitive operation');
749
}
750
}
751
}
752
```