@egintegrations/auth-services
v0.1.0
Published
React Native authentication utilities for token management, biometric authentication, and secure key storage. Works with Expo and bare React Native.
Downloads
86
Maintainers
Readme
@egintegrations/auth-services
React Native authentication utilities for token management, biometric authentication, and secure key storage. Works with Expo and bare React Native.
Features
- TokenManager: Secure token storage and retrieval
- BiometricAuth: Face ID / Touch ID authentication
- SecureKeyStore: Generic secure key/value storage
- TypeScript: Full type safety with TypeScript support
- Configurable: Customizable storage keys, prompts, and behavior
- Well-tested: 100% test coverage (69 tests)
- Dual Module: ESM and CommonJS support
Installation
npm install @egintegrations/auth-services expo-secure-store expo-local-authenticationPeer Dependencies
This package requires:
expo-secure-store>= 12.0.0expo-local-authentication>= 13.0.0react-native>= 0.70.0
Quick Start
import { TokenManager, BiometricAuth, SecureKeyStore } from '@egintegrations/auth-services';
// Token management
const tokenManager = new TokenManager();
await tokenManager.saveToken('your-auth-token');
const token = await tokenManager.getToken();
// Biometric authentication
const bioAuth = new BiometricAuth();
if (await bioAuth.canAuthenticate()) {
await bioAuth.enable('username');
const username = await bioAuth.authenticate();
}
// Secure key storage
const keyStore = new SecureKeyStore({ keyPrefix: 'app_' });
await keyStore.set('api_key', 'secret-key');
const apiKey = await keyStore.get('api_key');TokenManager
Manages authentication tokens in secure storage.
Basic Usage
import { TokenManager } from '@egintegrations/auth-services';
// Create manager with default storage key
const tokenManager = new TokenManager();
// Save token
await tokenManager.saveToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
// Get token
const token = await tokenManager.getToken();
// Check if token exists
const hasToken = await tokenManager.hasToken();
// Clear token
await tokenManager.clearToken();Custom Storage Key
// Use custom storage key for multiple token types
const accessTokenManager = new TokenManager({ storageKey: 'access_token' });
const refreshTokenManager = new TokenManager({ storageKey: 'refresh_token' });
await accessTokenManager.saveToken('access-token-123');
await refreshTokenManager.saveToken('refresh-token-456');Singleton Pattern
For simple apps with single token:
import { SingletonTokenManager } from '@egintegrations/auth-services';
// All methods are static
await SingletonTokenManager.saveToken('token');
const token = await SingletonTokenManager.getToken();
const hasToken = await SingletonTokenManager.hasToken();
await SingletonTokenManager.clearToken();BiometricAuth
Manages biometric authentication (Face ID / Touch ID).
Check Availability
import { BiometricAuth } from '@egintegrations/auth-services';
const bioAuth = new BiometricAuth();
// Check if device supports biometric auth
const canAuth = await bioAuth.canAuthenticate();
// Get biometric type
const type = await bioAuth.getBiometricType(); // 'faceId' | 'touchId' | 'fingerprint' | 'none'Enable Biometric Login
const bioAuth = new BiometricAuth();
try {
// Prompt user to authenticate and enable biometric login
await bioAuth.enable('username');
console.log('Biometric login enabled');
} catch (error) {
console.error('Failed to enable biometric:', error.message);
}Authenticate with Biometrics
const bioAuth = new BiometricAuth();
try {
// Prompt biometric authentication
const username = await bioAuth.authenticate();
console.log('Authenticated as:', username);
} catch (error) {
console.error('Authentication failed:', error.message);
}Custom Prompts
const bioAuth = new BiometricAuth({
promptMessages: {
enable: 'Enable Face ID for MyApp',
authenticate: 'Sign in to MyApp',
},
fallbackLabel: 'Use Password',
});
await bioAuth.enable('[email protected]');
const username = await bioAuth.authenticate();Manage Saved Username
const bioAuth = new BiometricAuth();
// Save username without prompting
await bioAuth.saveUsername('[email protected]');
// Get saved username (only if biometric is enabled)
const savedUsername = await bioAuth.getSavedUsername();
// Clear saved username
await bioAuth.clearSavedUsername();
// Disable biometric completely
await bioAuth.disable();Complete Login Flow Example
import { BiometricAuth, TokenManager } from '@egintegrations/auth-services';
const bioAuth = new BiometricAuth();
const tokenManager = new TokenManager();
async function loginWithBiometric() {
try {
// Check if biometric is enabled
const isEnabled = await bioAuth.isEnabled();
if (!isEnabled) {
console.log('Biometric not enabled, use password login');
return;
}
// Authenticate
const username = await bioAuth.authenticate();
// Call your API to get token
const response = await fetch('https://api.example.com/auth/biometric', {
method: 'POST',
body: JSON.stringify({ username }),
});
const { token } = await response.json();
// Save token
await tokenManager.saveToken(token);
console.log('Logged in as:', username);
} catch (error) {
console.error('Biometric login failed:', error.message);
}
}SecureKeyStore
Generic secure key-value storage with namespace support.
Basic Usage
import { SecureKeyStore } from '@egintegrations/auth-services';
const store = new SecureKeyStore();
// Store value
await store.set('api_key', 'sk-1234567890');
// Retrieve value
const apiKey = await store.get('api_key');
// Check if key exists
const hasKey = await store.has('api_key');
// Delete key
await store.delete('api_key');Namespace Isolation
// Create separate stores for different purposes
const apiStore = new SecureKeyStore({ keyPrefix: 'api_' });
const userStore = new SecureKeyStore({ keyPrefix: 'user_' });
await apiStore.set('openai_key', 'sk-...');
await userStore.set('preference', 'dark_mode');
// Keys are isolated
const apiKeys = await apiStore.get('openai_key'); // Works
const userKeys = await userStore.get('openai_key'); // null (different namespace)Clear Multiple Keys
const store = new SecureKeyStore({ keyPrefix: 'app_' });
await store.set('key1', 'value1');
await store.set('key2', 'value2');
await store.set('key3', 'value3');
// Clear specific keys
await store.clear(['key1', 'key2']);Convenience Functions
For simple use cases without creating a store instance:
import {
getSecureKey,
setSecureKey,
deleteSecureKey,
hasSecureKey,
} from '@egintegrations/auth-services';
// Direct access to secure storage (no prefix)
await setSecureKey('my_key', 'my_value');
const value = await getSecureKey('my_key');
const exists = await hasSecureKey('my_key');
await deleteSecureKey('my_key');Advanced Examples
Complete Authentication System
import {
TokenManager,
BiometricAuth,
SecureKeyStore,
} from '@egintegrations/auth-services';
class AuthService {
private tokenManager = new TokenManager();
private bioAuth = new BiometricAuth({
promptMessages: {
enable: 'Enable Face ID for faster login',
authenticate: 'Authenticate to continue',
},
});
private keyStore = new SecureKeyStore({ keyPrefix: 'auth_' });
async login(username: string, password: string): Promise<void> {
// Call your API
const response = await fetch('https://api.example.com/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
const { token } = await response.json();
// Save token
await this.tokenManager.saveToken(token);
// Offer biometric enrollment if available
const canAuth = await this.bioAuth.canAuthenticate();
if (canAuth) {
await this.bioAuth.enable(username);
}
}
async loginWithBiometric(): Promise<void> {
const username = await this.bioAuth.authenticate();
// Exchange biometric authentication for token
const response = await fetch('https://api.example.com/auth/biometric', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username }),
});
const { token } = await response.json();
await this.tokenManager.saveToken(token);
}
async logout(): Promise<void> {
await this.tokenManager.clearToken();
// Keep biometric enabled for next login
}
async getAuthToken(): Promise<string | null> {
return this.tokenManager.getToken();
}
async isAuthenticated(): Promise<boolean> {
return this.tokenManager.hasToken();
}
async saveApiKey(service: string, key: string): Promise<void> {
await this.keyStore.set(`${service}_key`, key);
}
async getApiKey(service: string): Promise<string | null> {
return this.keyStore.get(`${service}_key`);
}
}
// Usage
const auth = new AuthService();
// Normal login
await auth.login('[email protected]', 'password123');
// Biometric login
if (await auth.bioAuth.canAuthenticate()) {
await auth.loginWithBiometric();
}
// Get auth token for API calls
const token = await auth.getAuthToken();API Integration with TokenManager
import { TokenManager } from '@egintegrations/auth-services';
import { ApiClient } from '@egintegrations/api-client';
const tokenManager = new TokenManager();
// Create API client
const apiClient = new ApiClient({
baseUrl: 'https://api.example.com',
});
// Add token to all requests
apiClient.addRequestInterceptor(async (config) => {
const token = await tokenManager.getToken();
if (token) {
config.headers = config.headers || {};
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Handle 401 errors
apiClient.addErrorInterceptor(async (error) => {
if (error.response?.status === 401) {
await tokenManager.clearToken();
// Redirect to login
}
throw error;
});API Reference
TokenManager
Constructor
new TokenManager(config?: TokenManagerConfig)Config:
storageKey?: string- Storage key (default: 'auth_token')
Methods
getToken(): Promise<string | null>- Get stored tokensaveToken(token: string): Promise<void>- Save tokenclearToken(): Promise<void>- Delete tokenhasToken(): Promise<boolean>- Check if token exists
SingletonTokenManager
Static methods matching TokenManager interface.
BiometricAuth
Constructor
new BiometricAuth(config?: BiometricAuthConfig)Config:
savedUsernameKey?: string- Username storage key (default: 'biometric_username')enabledKey?: string- Enabled flag key (default: 'biometric_enabled')promptMessages?: { enable?: string, authenticate?: string }- Custom promptsfallbackLabel?: string- Fallback button label (default: 'Use password')
Methods
canAuthenticate(): Promise<boolean>- Check device supportisEnabled(): Promise<boolean>- Check if biometric enabledenable(username: string): Promise<void>- Enable biometric logindisable(): Promise<void>- Disable biometric logingetBiometricType(): Promise<BiometricType>- Get biometric typeauthenticate(): Promise<string>- Authenticate and get usernamesaveUsername(username: string): Promise<void>- Save usernameclearSavedUsername(): Promise<void>- Clear usernamegetSavedUsername(): Promise<string | null>- Get saved username
SecureKeyStore
Constructor
new SecureKeyStore(config?: SecureKeyStoreConfig)Config:
keyPrefix?: string- Key prefix for namespace isolation (default: 'secure_key_')
Methods
get(key: string): Promise<string | null>- Get valueset(key: string, value: string): Promise<void>- Set valuedelete(key: string): Promise<void>- Delete keyhas(key: string): Promise<boolean>- Check if key existsclear(keys?: string[]): Promise<void>- Clear multiple keys
Error Handling
All methods can throw errors. Always use try-catch:
try {
await tokenManager.saveToken(token);
} catch (error) {
console.error('Failed to save token:', error);
}
try {
const username = await bioAuth.authenticate();
} catch (error) {
console.error('Biometric auth failed:', error.message);
// Handle failure (show password login)
}Development
# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Run tests with coverage
npm test -- --coverage
# Type check
npm run typecheck
# Lint
npm run lintContributing
Contributions are welcome! Please ensure:
- All tests pass (
npm test) - Code coverage remains 100%
- TypeScript types are properly defined
- Code follows the existing style (run
npm run lint)
License
MIT © EGI Integrations
Extracted From
This package was extracted from AutismTrainerApp's authentication services and refactored to be reusable across React Native applications.
What was removed:
- App-specific user management (roles, permissions, progress tracking)
- Local user database and AsyncStorage user management
- Supervised user relationships
- Application-specific authentication flows
What was kept and improved:
- Token management (now configurable)
- Biometric authentication (now with custom prompts)
- Secure key storage (now with namespace support)
Related Packages
- @egintegrations/api-client - HTTP client for API integrations
- @egintegrations/core-utils - Utility functions
Support
For issues and questions, please open an issue on GitHub.
