@passgage/sdk-react-native
v1.0.20
Published
Passgage Access SDK - React Native wrapper with components and hooks
Maintainers
Readme
@passgage/sdk-react-native
Complete Passgage Access SDK for React Native with authentication, QR/NFC scanning, check-in, and remote work features.
Installation
npm install @passgage/sdk-react-native
# or
yarn add @passgage/sdk-react-nativeDependencies
The package has the following dependencies:
- axios: ^1.6.0 - HTTP client for API requests
- react-native-geolocation-service: ^5.3.1 - Geolocation service
- react-native-permissions: ^5.4.4 - Permissions management
- zustand: ^5.0.9 - State management
Peer Dependencies
You also need to install these peer dependencies:
npm install react-native-vision-camera react-native-nfc-manager @react-native-community/geolocation react-native-keychainFollow the installation instructions for each native library:
- react-native-vision-camera
- react-native-nfc-manager
- react-native-geolocation-service
- react-native-keychain
Usage
Provider Setup
Wrap your app with PassgageAccessProvider:
import {PassgageAccessProvider} from '@passgage/sdk-react-native';
function App() {
return (
<PassgageAccessProvider
baseURL="https://your-api.passgage.com"
msalToken={'Your MSAL Token'}
apiVersion="v2" // Optional: API version (default: "v2")
timeout={30000} // Optional: Request timeout in ms (default: 30000)
rememberUser={true} // Optional: Persist authentication (default: true)
onUnauthorized={error => {
// Handle session expiration
console.log('Unauthorized error:', error);
}}
getLocationErrorCallback={error => {
// Handle location retrieval errors
console.log('Location error:', error);
}}
locationPermissionErrorCallback={error => {
// Handle location permission errors
console.log('Permission error:', error);
}}>
<YourApp />
</PassgageAccessProvider>
);
}Provider Props
| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| baseURL | string | ✓ | - | Base URL of your Passgage API |
| msalToken | string | ✓ | - | Microsoft Azure AD token |
| apiVersion | string | ✗ | "v2" | API version to use |
| timeout | number | ✗ | 30000 | Request timeout in milliseconds |
| rememberUser | boolean | ✗ | true | Persist authentication state |
| onUnauthorized | (error: Error) => void | ✗ | - | Called when session expires |
| getLocationErrorCallback | (error: any) => void | ✗ | - | Called on location retrieval errors |
| locationPermissionErrorCallback | (error: any) => void | ✗ | - | Called on location permission errors |
Authentication
const LoginScreen = () => {
const {loading, error, loginWithAzure} = useAuthStore();
const handleLogin = async idToken => {
if (result?.idToken) {
loginWithAzure({id_token: result.idToken});
} else {
Alert.alert('Login Failed', 'No ID token received');
}
};
return (
<View style={styles.formContainer}>
{error && (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>{error}</Text>
</View>
)}
<TouchableOpacity
style={[styles.button, loading && styles.buttonDisabled]}
onPress={() => handleLogin('Provide your msal token')}
disabled={loading}>
{loading ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={styles.buttonText}>Sign In</Text>
)}
</TouchableOpacity>
</View>
);
};QR Scanner
const QRScannerScreen = () => {
const [qrCode, setQrCode] = useState('c70fc3a2-fbfb-4ca6-adcb-71ac0b796836');
const {scan, isLoading} = usePassgageQRScanner({
options: {skipLocationCheck: false, skipRepetitiveCheck: false},
onSuccess: entrance => {
const message = `Access granted!\nEntrance ID: ${entrance?.id || 'N/A'}`;
Alert.alert('Success', message);
},
onError: error => {
const errorMessage = error.message || 'QR validation failed';
Alert.alert('Failed', errorMessage);
},
});
const handleScan = async () => {
if (!qrCode.trim()) {
Alert.alert('Error', 'Please enter a QR code');
return;
}
try {
await scan(qrCode.trim());
} catch (error: any) {
// Error already handled by onError callback
console.error('QR scan error:', error);
}
};
const handleClear = () => {
setQrCode('');
};
return (
<View style={styles.container}>
<View style={styles.content}>
<Text style={styles.icon}>📱</Text>
<Text style={styles.title}>QR Code Scanner</Text>
<Text style={styles.description}>
Enter a QR code to validate access
</Text>
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
placeholder="Enter QR code"
value={qrCode}
onChangeText={setQrCode}
autoCapitalize="none"
editable={!isLoading}
returnKeyType="done"
onSubmitEditing={handleScan}
/>
</View>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={[
styles.button,
styles.scanButton,
isLoading && styles.buttonDisabled,
]}
onPress={handleScan}
disabled={isLoading || !qrCode.trim()}>
{isLoading ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={styles.buttonText}>Validate QR Code</Text>
)}
</TouchableOpacity>
{qrCode.trim() && !isLoading && (
<TouchableOpacity
style={[styles.button, styles.clearButton]}
onPress={handleClear}>
<Text style={styles.clearButtonText}>Clear</Text>
</TouchableOpacity>
)}
</View>
<View style={styles.info}>
<Text style={styles.infoText}>
💡 In a real app, you would use react-native-vision-camera to scan
QR codes with the camera
</Text>
<Text style={styles.infoText}>
{'\n'}For testing, you can enter any QR code value manually
</Text>
</View>
</View>
</View>
);
};NFC Scanner
export default function NFCScannerScreen() {
NfcManager.start();
const {nfcData, supportNFC, startScanning, stopScanning, isScanning, error} =
usePassgageNFCScanner({
options: {skipLocationCheck: false, skipRepetitiveCheck: false},
onSuccess: entrance => {
const message = `Access granted!\nEntrance ID: ${
entrance?.id || 'N/A'
}`;
Alert.alert('Success', message);
},
onError: error => {
const errorMessage = error.message || 'NFC validation failed';
Alert.alert('Failed', errorMessage);
},
});
const handleStartScan = async () => {
startScanning();
};
const handleStopScan = async () => {
try {
await stopScanning();
} catch (error: any) {
console.error('Stop NFC scan error:', error);
}
};
return (
<View style={styles.container}>
<View style={styles.content}>
<Text style={styles.icon}>💳</Text>
<Text style={styles.title}>NFC Card Scanner</Text>
<Text style={styles.description}>
{isScanning
? 'Hold your device near an NFC card'
: 'Tap the button below to start scanning'}
</Text>
<View style={styles.scanStatus}>
{isScanning ? (
<>
<ActivityIndicator size="large" color="#FF9500" />
<Text style={styles.statusText}>Scanning for NFC cards...</Text>
</>
) : (
<View style={styles.readyIndicator}>
<Text style={styles.readyText}>
{supportNFC
? 'Ready to scan'
: supportNFC === false
? 'Device not support NFC'
: 'LOADING...'}
</Text>
</View>
)}
</View>
<View style={styles.buttonContainer}>
{!isScanning ? (
<TouchableOpacity
style={[styles.button, styles.scanButton]}
onPress={async () => {
handleStartScan();
}}>
<Text style={styles.buttonText}>Start NFC Scan</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
style={[styles.button, styles.stopButton]}
onPress={handleStopScan}>
<Text style={styles.buttonText}>Stop Scanning</Text>
</TouchableOpacity>
)}
</View>
{error && (
<View style={styles.errorContainer}>
<Text style={styles.errorText}>{error.message}</Text>
</View>
)}
<View style={styles.info}>
<Text style={styles.infoTitle}>How it works:</Text>
<Text style={styles.infoText}>
1. Tap "Start NFC Scan" button{'\n'}
2. Hold your device near an NFC card{'\n'}
3. Wait for validation response{'\n'}
4. Access will be granted if authorized
</Text>
<Text style={styles.infoNote}>
{'\n'}💡 Make sure NFC is enabled in your device settings
</Text>
</View>
</View>
</View>
);
}API
Hooks
All hooks use the usePassgage* prefix to avoid naming conflicts:
usePassgageQRScanner(options)
QR code scanning with validation and location checking.
const {scan, isLoading} = usePassgageQRScanner({
options: {
skipLocationCheck: false, // Skip location verification
skipRepetitiveCheck: false, // Skip duplicate scan detection
},
onSuccess: (entrance) => {
console.log('Access granted:', entrance);
},
onError: (error) => {
console.error('Access denied:', error);
},
});
// Scan a QR code
await scan(qrCode);usePassgageNFCScanner(options)
NFC card scanning with validation and location checking.
const {nfcData, supportNFC, startScanning, stopScanning, isScanning, error} =
usePassgageNFCScanner({
options: {
skipLocationCheck: false,
skipRepetitiveCheck: false,
},
onSuccess: (entrance) => {
console.log('Access granted:', entrance);
},
onError: (error) => {
console.error('Access denied:', error);
},
});
// Start NFC scanning
await startScanning();
// Stop NFC scanning
await stopScanning();Returns:
nfcData?: string- Last scanned NFC card datasupportNFC?: boolean- Whether device supports NFCstartScanning: () => Promise<void>- Start NFC scanningstopScanning: () => Promise<void>- Stop NFC scanningisScanning: boolean- Whether currently scanningerror: Error | null- Last error if any
useLocation()
Access current user location and location utilities.
const {location, error, refreshLocation} = useLocation();
// Get current location
console.log(location?.latitude, location?.longitude);
// Manually refresh location
await refreshLocation();Returns:
location?: Location- Current location coordinateserror?: string- Location error if anyrefreshLocation: () => Promise<void>- Manually refresh location
State Management
useAuthStore()
Zustand store for authentication state management.
import {useAuthStore} from '@passgage/sdk-react-native';
const {
user,
loading,
error,
authStatus,
login,
loginWithAzure,
logout,
restoreAuth,
refreshToken,
clearError,
} = useAuthStore();
// Login with Azure AD
await loginWithAzure({id_token: 'your-azure-token'});
// Check auth status
if (authStatus === 'authenticated') {
console.log('User:', user);
}
// Logout
await logout();
// Restore previous session
await restoreAuth();
// Manually refresh token
await refreshToken();
// Clear error state
clearError();State:
user?: User- Current authenticated userloading: boolean- Loading stateerror: string | null- Error message if anyauthStatus: 'idle' | 'loading' | 'authenticated' | 'unauthenticated'- Authentication status
Methods:
login(credentials)- Login with email/passwordloginWithAzure(params)- Login with Azure AD tokenlogout()- Logout and clear sessionrestoreAuth()- Restore session from secure storagerefreshToken()- Manually refresh access tokenclearError()- Clear error state
Services
Low-level services for advanced use cases. Most developers should use hooks instead.
AuthService
import {AuthService} from '@passgage/sdk-react-native';
const authService = new AuthService(apiClient);
await authService.loginWithAzure({id_token: 'token'});
await authService.logout();QRAccessService
import {QRAccessService} from '@passgage/sdk-react-native';
const qrService = new QRAccessService(apiClient);
const entrance = await qrService.validateQRCode(qrCode, options);NFCAccessService
import {NFCAccessService} from '@passgage/sdk-react-native';
const nfcService = new NFCAccessService(apiClient);
const entrance = await nfcService.validateNFCCard(cardId, options);DeviceAccessService
import {DeviceAccessService} from '@passgage/sdk-react-native';
const deviceService = new DeviceAccessService(apiClient);
const device = await deviceService.getDeviceInfo(deviceId);LocationService
import {LocationService} from '@passgage/sdk-react-native';
const locationService = new LocationService();
const location = await locationService.getCurrentLocation();
const isInRange = locationService.isWithinRange(location, targetLocation, range);Components
<PassgageAccessProvider>- SDK configuration provider
Security Features
- JWT Authentication: Secure token-based authentication
- Automatic Token Refresh: Tokens are automatically refreshed when expired
- Secure Storage: Tokens stored securely using platform-specific secure storage (Keychain/Keystore)
- TLS 1.2+: All network communications encrypted
- Location Verification: Automatic location validation with range checking
- Backend Logging: Access logs sent to backend for audit trail
Token Flow
The SDK automatically handles authentication tokens:
- User logs in → JWT tokens stored securely
- API client automatically adds
Authorization: Bearer {token}to all requests - Tokens are automatically refreshed when they expire
- On logout, all tokens are cleared
You don't need to manually manage tokens! Just provide msal tokens to provider and the SDK handles everything.
Example Application
A complete example React Native app demonstrating all SDK features:
TypeScript Support
The SDK is written in TypeScript and includes full type definitions for all APIs, hooks, and models.
License
Proprietary - Passgage © 2025
Support
For support, contact [email protected]
