@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.
@@ -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 };
package/dist/index.js ADDED
@@ -0,0 +1,223 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ BiometricAuth: () => BiometricAuth,
34
+ SecureKeyStore: () => SecureKeyStore,
35
+ SingletonTokenManager: () => SingletonTokenManager,
36
+ TokenManager: () => TokenManager,
37
+ deleteSecureKey: () => deleteSecureKey,
38
+ getSecureKey: () => getSecureKey,
39
+ hasSecureKey: () => hasSecureKey,
40
+ setSecureKey: () => setSecureKey
41
+ });
42
+ module.exports = __toCommonJS(index_exports);
43
+
44
+ // src/TokenManager.ts
45
+ var SecureStore = __toESM(require("expo-secure-store"));
46
+ var TokenManager = class {
47
+ constructor(config = {}) {
48
+ this.storageKey = config.storageKey || "auth_token";
49
+ }
50
+ async getToken() {
51
+ return await SecureStore.getItemAsync(this.storageKey);
52
+ }
53
+ async saveToken(token) {
54
+ await SecureStore.setItemAsync(this.storageKey, token);
55
+ }
56
+ async clearToken() {
57
+ await SecureStore.deleteItemAsync(this.storageKey);
58
+ }
59
+ async hasToken() {
60
+ const token = await this.getToken();
61
+ return !!token;
62
+ }
63
+ };
64
+ var SingletonTokenManager = class {
65
+ constructor() {
66
+ }
67
+ static getInstance(storageKey) {
68
+ if (!this.instance) {
69
+ this.instance = new TokenManager({ storageKey: storageKey || this.defaultKey });
70
+ }
71
+ return this.instance;
72
+ }
73
+ static async getToken() {
74
+ return this.getInstance().getToken();
75
+ }
76
+ static async saveToken(token) {
77
+ return this.getInstance().saveToken(token);
78
+ }
79
+ static async clearToken() {
80
+ return this.getInstance().clearToken();
81
+ }
82
+ static async hasToken() {
83
+ return this.getInstance().hasToken();
84
+ }
85
+ };
86
+ SingletonTokenManager.instance = null;
87
+ SingletonTokenManager.defaultKey = "auth_token";
88
+
89
+ // src/BiometricAuth.ts
90
+ var LocalAuthentication = __toESM(require("expo-local-authentication"));
91
+ var SecureStore2 = __toESM(require("expo-secure-store"));
92
+ var BiometricAuth = class {
93
+ constructor(config = {}) {
94
+ this.savedUsernameKey = config.savedUsernameKey || "biometric_username";
95
+ this.enabledKey = config.enabledKey || "biometric_enabled";
96
+ this.promptMessages = {
97
+ enable: config.promptMessages?.enable || "Enable biometric login",
98
+ authenticate: config.promptMessages?.authenticate || "Authenticate to continue"
99
+ };
100
+ this.fallbackLabel = config.fallbackLabel || "Use password";
101
+ }
102
+ async canAuthenticate() {
103
+ const hasHardware = await LocalAuthentication.hasHardwareAsync();
104
+ const isEnrolled = await LocalAuthentication.isEnrolledAsync();
105
+ return hasHardware && isEnrolled;
106
+ }
107
+ async isEnabled() {
108
+ const value = await SecureStore2.getItemAsync(this.enabledKey);
109
+ return value === "true";
110
+ }
111
+ async enable(username) {
112
+ const canAuth = await this.canAuthenticate();
113
+ if (!canAuth) {
114
+ throw new Error("Biometric authentication is not available on this device");
115
+ }
116
+ const result = await LocalAuthentication.authenticateAsync({
117
+ promptMessage: this.promptMessages.enable,
118
+ fallbackLabel: this.fallbackLabel,
119
+ disableDeviceFallback: false
120
+ });
121
+ if (!result.success) {
122
+ throw new Error("Biometric authentication failed");
123
+ }
124
+ await SecureStore2.setItemAsync(this.enabledKey, "true");
125
+ await SecureStore2.setItemAsync(this.savedUsernameKey, username);
126
+ }
127
+ async disable() {
128
+ await SecureStore2.deleteItemAsync(this.enabledKey);
129
+ await SecureStore2.deleteItemAsync(this.savedUsernameKey);
130
+ }
131
+ async getBiometricType() {
132
+ const types = await LocalAuthentication.supportedAuthenticationTypesAsync();
133
+ if (types.includes(LocalAuthentication.AuthenticationType.FACIAL_RECOGNITION)) {
134
+ return "faceId";
135
+ } else if (types.includes(LocalAuthentication.AuthenticationType.FINGERPRINT)) {
136
+ return "touchId";
137
+ }
138
+ return "none";
139
+ }
140
+ async authenticate() {
141
+ const result = await LocalAuthentication.authenticateAsync({
142
+ promptMessage: this.promptMessages.authenticate,
143
+ fallbackLabel: this.fallbackLabel,
144
+ disableDeviceFallback: false
145
+ });
146
+ if (!result.success) {
147
+ throw new Error("Biometric authentication failed");
148
+ }
149
+ const enabled = await this.isEnabled();
150
+ if (!enabled) {
151
+ throw new Error("Biometric login is disabled");
152
+ }
153
+ const username = await SecureStore2.getItemAsync(this.savedUsernameKey);
154
+ if (!username) {
155
+ throw new Error("No saved username for biometric authentication");
156
+ }
157
+ return username;
158
+ }
159
+ async saveUsername(username) {
160
+ await SecureStore2.setItemAsync(this.savedUsernameKey, username);
161
+ }
162
+ async clearSavedUsername() {
163
+ await SecureStore2.deleteItemAsync(this.savedUsernameKey);
164
+ }
165
+ async getSavedUsername() {
166
+ const enabled = await this.isEnabled();
167
+ if (!enabled) return null;
168
+ return await SecureStore2.getItemAsync(this.savedUsernameKey);
169
+ }
170
+ };
171
+
172
+ // src/SecureKeyStore.ts
173
+ var SecureStore3 = __toESM(require("expo-secure-store"));
174
+ var SecureKeyStore = class {
175
+ constructor(config = {}) {
176
+ this.keyPrefix = config.keyPrefix || "secure_key_";
177
+ }
178
+ getFullKey(key) {
179
+ return `${this.keyPrefix}${key}`;
180
+ }
181
+ async get(key) {
182
+ return await SecureStore3.getItemAsync(this.getFullKey(key));
183
+ }
184
+ async set(key, value) {
185
+ await SecureStore3.setItemAsync(this.getFullKey(key), value);
186
+ }
187
+ async delete(key) {
188
+ await SecureStore3.deleteItemAsync(this.getFullKey(key));
189
+ }
190
+ async has(key) {
191
+ const value = await this.get(key);
192
+ return !!value;
193
+ }
194
+ async clear(keys) {
195
+ if (keys) {
196
+ await Promise.all(keys.map((key) => this.delete(key)));
197
+ }
198
+ }
199
+ };
200
+ async function getSecureKey(key) {
201
+ return await SecureStore3.getItemAsync(key);
202
+ }
203
+ async function setSecureKey(key, value) {
204
+ await SecureStore3.setItemAsync(key, value);
205
+ }
206
+ async function deleteSecureKey(key) {
207
+ await SecureStore3.deleteItemAsync(key);
208
+ }
209
+ async function hasSecureKey(key) {
210
+ const value = await getSecureKey(key);
211
+ return !!value;
212
+ }
213
+ // Annotate the CommonJS export names for ESM import in node:
214
+ 0 && (module.exports = {
215
+ BiometricAuth,
216
+ SecureKeyStore,
217
+ SingletonTokenManager,
218
+ TokenManager,
219
+ deleteSecureKey,
220
+ getSecureKey,
221
+ hasSecureKey,
222
+ setSecureKey
223
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,179 @@
1
+ // src/TokenManager.ts
2
+ import * as SecureStore from "expo-secure-store";
3
+ var TokenManager = class {
4
+ constructor(config = {}) {
5
+ this.storageKey = config.storageKey || "auth_token";
6
+ }
7
+ async getToken() {
8
+ return await SecureStore.getItemAsync(this.storageKey);
9
+ }
10
+ async saveToken(token) {
11
+ await SecureStore.setItemAsync(this.storageKey, token);
12
+ }
13
+ async clearToken() {
14
+ await SecureStore.deleteItemAsync(this.storageKey);
15
+ }
16
+ async hasToken() {
17
+ const token = await this.getToken();
18
+ return !!token;
19
+ }
20
+ };
21
+ var SingletonTokenManager = class {
22
+ constructor() {
23
+ }
24
+ static getInstance(storageKey) {
25
+ if (!this.instance) {
26
+ this.instance = new TokenManager({ storageKey: storageKey || this.defaultKey });
27
+ }
28
+ return this.instance;
29
+ }
30
+ static async getToken() {
31
+ return this.getInstance().getToken();
32
+ }
33
+ static async saveToken(token) {
34
+ return this.getInstance().saveToken(token);
35
+ }
36
+ static async clearToken() {
37
+ return this.getInstance().clearToken();
38
+ }
39
+ static async hasToken() {
40
+ return this.getInstance().hasToken();
41
+ }
42
+ };
43
+ SingletonTokenManager.instance = null;
44
+ SingletonTokenManager.defaultKey = "auth_token";
45
+
46
+ // src/BiometricAuth.ts
47
+ import * as LocalAuthentication from "expo-local-authentication";
48
+ import * as SecureStore2 from "expo-secure-store";
49
+ var BiometricAuth = class {
50
+ constructor(config = {}) {
51
+ this.savedUsernameKey = config.savedUsernameKey || "biometric_username";
52
+ this.enabledKey = config.enabledKey || "biometric_enabled";
53
+ this.promptMessages = {
54
+ enable: config.promptMessages?.enable || "Enable biometric login",
55
+ authenticate: config.promptMessages?.authenticate || "Authenticate to continue"
56
+ };
57
+ this.fallbackLabel = config.fallbackLabel || "Use password";
58
+ }
59
+ async canAuthenticate() {
60
+ const hasHardware = await LocalAuthentication.hasHardwareAsync();
61
+ const isEnrolled = await LocalAuthentication.isEnrolledAsync();
62
+ return hasHardware && isEnrolled;
63
+ }
64
+ async isEnabled() {
65
+ const value = await SecureStore2.getItemAsync(this.enabledKey);
66
+ return value === "true";
67
+ }
68
+ async enable(username) {
69
+ const canAuth = await this.canAuthenticate();
70
+ if (!canAuth) {
71
+ throw new Error("Biometric authentication is not available on this device");
72
+ }
73
+ const result = await LocalAuthentication.authenticateAsync({
74
+ promptMessage: this.promptMessages.enable,
75
+ fallbackLabel: this.fallbackLabel,
76
+ disableDeviceFallback: false
77
+ });
78
+ if (!result.success) {
79
+ throw new Error("Biometric authentication failed");
80
+ }
81
+ await SecureStore2.setItemAsync(this.enabledKey, "true");
82
+ await SecureStore2.setItemAsync(this.savedUsernameKey, username);
83
+ }
84
+ async disable() {
85
+ await SecureStore2.deleteItemAsync(this.enabledKey);
86
+ await SecureStore2.deleteItemAsync(this.savedUsernameKey);
87
+ }
88
+ async getBiometricType() {
89
+ const types = await LocalAuthentication.supportedAuthenticationTypesAsync();
90
+ if (types.includes(LocalAuthentication.AuthenticationType.FACIAL_RECOGNITION)) {
91
+ return "faceId";
92
+ } else if (types.includes(LocalAuthentication.AuthenticationType.FINGERPRINT)) {
93
+ return "touchId";
94
+ }
95
+ return "none";
96
+ }
97
+ async authenticate() {
98
+ const result = await LocalAuthentication.authenticateAsync({
99
+ promptMessage: this.promptMessages.authenticate,
100
+ fallbackLabel: this.fallbackLabel,
101
+ disableDeviceFallback: false
102
+ });
103
+ if (!result.success) {
104
+ throw new Error("Biometric authentication failed");
105
+ }
106
+ const enabled = await this.isEnabled();
107
+ if (!enabled) {
108
+ throw new Error("Biometric login is disabled");
109
+ }
110
+ const username = await SecureStore2.getItemAsync(this.savedUsernameKey);
111
+ if (!username) {
112
+ throw new Error("No saved username for biometric authentication");
113
+ }
114
+ return username;
115
+ }
116
+ async saveUsername(username) {
117
+ await SecureStore2.setItemAsync(this.savedUsernameKey, username);
118
+ }
119
+ async clearSavedUsername() {
120
+ await SecureStore2.deleteItemAsync(this.savedUsernameKey);
121
+ }
122
+ async getSavedUsername() {
123
+ const enabled = await this.isEnabled();
124
+ if (!enabled) return null;
125
+ return await SecureStore2.getItemAsync(this.savedUsernameKey);
126
+ }
127
+ };
128
+
129
+ // src/SecureKeyStore.ts
130
+ import * as SecureStore3 from "expo-secure-store";
131
+ var SecureKeyStore = class {
132
+ constructor(config = {}) {
133
+ this.keyPrefix = config.keyPrefix || "secure_key_";
134
+ }
135
+ getFullKey(key) {
136
+ return `${this.keyPrefix}${key}`;
137
+ }
138
+ async get(key) {
139
+ return await SecureStore3.getItemAsync(this.getFullKey(key));
140
+ }
141
+ async set(key, value) {
142
+ await SecureStore3.setItemAsync(this.getFullKey(key), value);
143
+ }
144
+ async delete(key) {
145
+ await SecureStore3.deleteItemAsync(this.getFullKey(key));
146
+ }
147
+ async has(key) {
148
+ const value = await this.get(key);
149
+ return !!value;
150
+ }
151
+ async clear(keys) {
152
+ if (keys) {
153
+ await Promise.all(keys.map((key) => this.delete(key)));
154
+ }
155
+ }
156
+ };
157
+ async function getSecureKey(key) {
158
+ return await SecureStore3.getItemAsync(key);
159
+ }
160
+ async function setSecureKey(key, value) {
161
+ await SecureStore3.setItemAsync(key, value);
162
+ }
163
+ async function deleteSecureKey(key) {
164
+ await SecureStore3.deleteItemAsync(key);
165
+ }
166
+ async function hasSecureKey(key) {
167
+ const value = await getSecureKey(key);
168
+ return !!value;
169
+ }
170
+ export {
171
+ BiometricAuth,
172
+ SecureKeyStore,
173
+ SingletonTokenManager,
174
+ TokenManager,
175
+ deleteSecureKey,
176
+ getSecureKey,
177
+ hasSecureKey,
178
+ setSecureKey
179
+ };
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@egintegrations/auth-services",
3
+ "version": "0.1.0",
4
+ "description": "React Native authentication utilities for token management, biometric authentication, and secure key storage. Works with Expo and bare React Native.",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "src",
18
+ "README.md",
19
+ "CHANGELOG.md",
20
+ "LICENSE"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
24
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
25
+ "test": "jest",
26
+ "typecheck": "tsc --noEmit",
27
+ "lint": "eslint src --ext .ts,.tsx",
28
+ "prepublishOnly": "npm run lint && npm run typecheck && npm run build && npm run test"
29
+ },
30
+ "keywords": [
31
+ "typescript",
32
+ "react-native",
33
+ "authentication",
34
+ "biometric",
35
+ "token-management",
36
+ "secure-storage",
37
+ "expo",
38
+ "mobile",
39
+ "egintegrations"
40
+ ],
41
+ "author": "EGI Integrations",
42
+ "license": "MIT",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/EGIntegrations/egi-comp-library.git",
46
+ "directory": "packages/typescript/auth-services"
47
+ },
48
+ "peerDependencies": {
49
+ "expo-local-authentication": ">=13.0.0",
50
+ "expo-secure-store": ">=12.0.0",
51
+ "react-native": ">=0.70.0"
52
+ },
53
+ "devDependencies": {
54
+ "@types/jest": "^29.5.11",
55
+ "@types/node": "^20.10.6",
56
+ "@types/react-native": "^0.72.0",
57
+ "@typescript-eslint/eslint-plugin": "^6.17.0",
58
+ "@typescript-eslint/parser": "^6.17.0",
59
+ "eslint": "^8.56.0",
60
+ "jest": "^29.7.0",
61
+ "ts-jest": "^29.1.1",
62
+ "tsup": "^8.0.1",
63
+ "typescript": "^5.3.3"
64
+ }
65
+ }
@@ -0,0 +1,119 @@
1
+ import * as LocalAuthentication from 'expo-local-authentication';
2
+ import * as SecureStore from 'expo-secure-store';
3
+
4
+ export interface BiometricAuthConfig {
5
+ savedUsernameKey?: string;
6
+ enabledKey?: string;
7
+ promptMessages?: {
8
+ enable?: string;
9
+ authenticate?: string;
10
+ };
11
+ fallbackLabel?: string;
12
+ }
13
+
14
+ export type BiometricType = 'faceId' | 'touchId' | 'fingerprint' | 'none';
15
+
16
+ export class BiometricAuth {
17
+ private savedUsernameKey: string;
18
+ private enabledKey: string;
19
+ private promptMessages: {
20
+ enable: string;
21
+ authenticate: string;
22
+ };
23
+ private fallbackLabel: string;
24
+
25
+ constructor(config: BiometricAuthConfig = {}) {
26
+ this.savedUsernameKey = config.savedUsernameKey || 'biometric_username';
27
+ this.enabledKey = config.enabledKey || 'biometric_enabled';
28
+ this.promptMessages = {
29
+ enable: config.promptMessages?.enable || 'Enable biometric login',
30
+ authenticate: config.promptMessages?.authenticate || 'Authenticate to continue',
31
+ };
32
+ this.fallbackLabel = config.fallbackLabel || 'Use password';
33
+ }
34
+
35
+ async canAuthenticate(): Promise<boolean> {
36
+ const hasHardware = await LocalAuthentication.hasHardwareAsync();
37
+ const isEnrolled = await LocalAuthentication.isEnrolledAsync();
38
+ return hasHardware && isEnrolled;
39
+ }
40
+
41
+ async isEnabled(): Promise<boolean> {
42
+ const value = await SecureStore.getItemAsync(this.enabledKey);
43
+ return value === 'true';
44
+ }
45
+
46
+ async enable(username: string): Promise<void> {
47
+ const canAuth = await this.canAuthenticate();
48
+ if (!canAuth) {
49
+ throw new Error('Biometric authentication is not available on this device');
50
+ }
51
+
52
+ const result = await LocalAuthentication.authenticateAsync({
53
+ promptMessage: this.promptMessages.enable,
54
+ fallbackLabel: this.fallbackLabel,
55
+ disableDeviceFallback: false,
56
+ });
57
+
58
+ if (!result.success) {
59
+ throw new Error('Biometric authentication failed');
60
+ }
61
+
62
+ await SecureStore.setItemAsync(this.enabledKey, 'true');
63
+ await SecureStore.setItemAsync(this.savedUsernameKey, username);
64
+ }
65
+
66
+ async disable(): Promise<void> {
67
+ await SecureStore.deleteItemAsync(this.enabledKey);
68
+ await SecureStore.deleteItemAsync(this.savedUsernameKey);
69
+ }
70
+
71
+ async getBiometricType(): Promise<BiometricType> {
72
+ const types = await LocalAuthentication.supportedAuthenticationTypesAsync();
73
+
74
+ if (types.includes(LocalAuthentication.AuthenticationType.FACIAL_RECOGNITION)) {
75
+ return 'faceId';
76
+ } else if (types.includes(LocalAuthentication.AuthenticationType.FINGERPRINT)) {
77
+ return 'touchId';
78
+ }
79
+ return 'none';
80
+ }
81
+
82
+ async authenticate(): Promise<string> {
83
+ const result = await LocalAuthentication.authenticateAsync({
84
+ promptMessage: this.promptMessages.authenticate,
85
+ fallbackLabel: this.fallbackLabel,
86
+ disableDeviceFallback: false,
87
+ });
88
+
89
+ if (!result.success) {
90
+ throw new Error('Biometric authentication failed');
91
+ }
92
+
93
+ const enabled = await this.isEnabled();
94
+ if (!enabled) {
95
+ throw new Error('Biometric login is disabled');
96
+ }
97
+
98
+ const username = await SecureStore.getItemAsync(this.savedUsernameKey);
99
+ if (!username) {
100
+ throw new Error('No saved username for biometric authentication');
101
+ }
102
+
103
+ return username;
104
+ }
105
+
106
+ async saveUsername(username: string): Promise<void> {
107
+ await SecureStore.setItemAsync(this.savedUsernameKey, username);
108
+ }
109
+
110
+ async clearSavedUsername(): Promise<void> {
111
+ await SecureStore.deleteItemAsync(this.savedUsernameKey);
112
+ }
113
+
114
+ async getSavedUsername(): Promise<string | null> {
115
+ const enabled = await this.isEnabled();
116
+ if (!enabled) return null;
117
+ return await SecureStore.getItemAsync(this.savedUsernameKey);
118
+ }
119
+ }