npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@passgage/sdk-react-native

v1.0.20

Published

Passgage Access SDK - React Native wrapper with components and hooks

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-native

Dependencies

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-keychain

Follow the installation instructions for each native library:

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 data
  • supportNFC?: boolean - Whether device supports NFC
  • startScanning: () => Promise<void> - Start NFC scanning
  • stopScanning: () => Promise<void> - Stop NFC scanning
  • isScanning: boolean - Whether currently scanning
  • error: 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 coordinates
  • error?: string - Location error if any
  • refreshLocation: () => 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 user
  • loading: boolean - Loading state
  • error: string | null - Error message if any
  • authStatus: 'idle' | 'loading' | 'authenticated' | 'unauthenticated' - Authentication status

Methods:

  • login(credentials) - Login with email/password
  • loginWithAzure(params) - Login with Azure AD token
  • logout() - Logout and clear session
  • restoreAuth() - Restore session from secure storage
  • refreshToken() - Manually refresh access token
  • clearError() - 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:

  1. User logs in → JWT tokens stored securely
  2. API client automatically adds Authorization: Bearer {token} to all requests
  3. Tokens are automatically refreshed when they expire
  4. 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:

👉 Passgage SDK Example App

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]