> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/expo/expo/llms.txt
> Use this file to discover all available pages before exploring further.

# expo-app-integrity

> Assert app integrity on mobile platforms with attestation APIs

# expo-app-integrity

**Version:** 55.0.6

A native module that helps assert app integrity on mobile platforms using Apple's App Attest and Google's Play Integrity APIs. Verify that your app hasn't been tampered with and is running on a genuine device.

## Installation

```bash theme={null}
npx expo install expo-app-integrity
```

## Usage

```typescript theme={null}
import * as AppIntegrity from 'expo-app-integrity';

// Check if integrity checking is available
const isAvailable = await AppIntegrity.isAvailableAsync();

if (isAvailable) {
  // Request attestation
  const token = await AppIntegrity.getAttestationAsync('challenge-from-server');
  
  // Send token to your server for verification
  await verifyWithServer(token);
}
```

## API Reference

### Methods

<ParamField path="isAvailableAsync()" type="() => Promise<boolean>">
  Checks if app integrity verification is available

  Returns `true` on iOS 14+ and Android with Play Services

  ```typescript theme={null}
  const available = await AppIntegrity.isAvailableAsync();
  if (!available) {
    console.log('Integrity checking not available');
  }
  ```
</ParamField>

<ParamField path="getAttestationAsync(challenge)" type="(challenge: string) => Promise<string>">
  Requests attestation token

  **Parameters:**

  * `challenge` (string): Challenge string from your server

  **Returns:** Attestation token to verify on server

  ```typescript theme={null}
  const challenge = await fetchChallengeFromServer();
  const token = await AppIntegrity.getAttestationAsync(challenge);

  // Send token to server for verification
  const isValid = await verifyTokenOnServer(token);
  ```
</ParamField>

## Examples

### Basic Integrity Check

```typescript theme={null}
import * as AppIntegrity from 'expo-app-integrity';

async function verifyAppIntegrity() {
  const isAvailable = await AppIntegrity.isAvailableAsync();
  
  if (!isAvailable) {
    console.log('App integrity checking not supported');
    return false;
  }

  try {
    // Get challenge from your server
    const challenge = await fetch('https://api.example.com/challenge')
      .then(res => res.text());

    // Get attestation token
    const token = await AppIntegrity.getAttestationAsync(challenge);

    // Verify token with your server
    const response = await fetch('https://api.example.com/verify', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ token }),
    });

    const { valid } = await response.json();
    return valid;
  } catch (error) {
    console.error('Integrity check failed:', error);
    return false;
  }
}
```

### Protect API Calls

```typescript theme={null}
import * * AppIntegrity from 'expo-app-integrity';

async function makeSecureAPICall(endpoint: string, data: any) {
  // Get attestation before making sensitive API call
  const challenge = Date.now().toString();
  const attestation = await AppIntegrity.getAttestationAsync(challenge);

  const response = await fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Attestation': attestation,
      'X-Challenge': challenge,
    },
    body: JSON.stringify(data),
  });

  return response.json();
}
```

### Complete Example with Server Verification

```tsx theme={null}
import * as AppIntegrity from 'expo-app-integrity';
import { useState, useEffect } from 'react';
import { View, Button, Text, StyleSheet, ActivityIndicator } from 'react-native';

export default function IntegrityExample() {
  const [isAvailable, setIsAvailable] = useState(false);
  const [isVerified, setIsVerified] = useState<boolean | null>(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    checkAvailability();
  }, []);

  async function checkAvailability() {
    const available = await AppIntegrity.isAvailableAsync();
    setIsAvailable(available);
  }

  async function verifyIntegrity() {
    setLoading(true);
    setIsVerified(null);

    try {
      // Step 1: Get challenge from server
      const challengeResponse = await fetch(
        'https://your-api.com/integrity/challenge'
      );
      const { challenge } = await challengeResponse.json();

      // Step 2: Get attestation token
      const token = await AppIntegrity.getAttestationAsync(challenge);

      // Step 3: Verify with server
      const verifyResponse = await fetch(
        'https://your-api.com/integrity/verify',
        {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ token, challenge }),
        }
      );

      const { valid } = await verifyResponse.json();
      setIsVerified(valid);
    } catch (error) {
      console.error('Verification error:', error);
      setIsVerified(false);
    } finally {
      setLoading(false);
    }
  }

  if (!isAvailable) {
    return (
      <View style={styles.container}>
        <Text style={styles.message}>
          App integrity checking is not available on this device
        </Text>
      </View>
    );
  }

  return (
    <View style={styles.container}>
      <Text style={styles.title}>App Integrity Check</Text>

      {loading ? (
        <ActivityIndicator size="large" />
      ) : (
        <>
          <Button title="Verify App Integrity" onPress={verifyIntegrity} />

          {isVerified !== null && (
            <View style={styles.result}>
              {isVerified ? (
                <>
                  <Text style={styles.success}>✓ Verified</Text>
                  <Text>App integrity check passed</Text>
                </>
              ) : (
                <>
                  <Text style={styles.error}>✗ Failed</Text>
                  <Text>App integrity check failed</Text>
                </>
              )}
            </View>
          )}
        </>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
    gap: 20,
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
  },
  message: {
    fontSize: 16,
    textAlign: 'center',
    color: '#666',
  },
  result: {
    alignItems: 'center',
    gap: 10,
  },
  success: {
    fontSize: 48,
    color: '#4CAF50',
  },
  error: {
    fontSize: 48,
    color: '#F44336',
  },
});
```

## Platform Support

| Platform | API Used        | Minimum Version                 |
| -------- | --------------- | ------------------------------- |
| iOS      | App Attest      | iOS 14+                         |
| Android  | Play Integrity  | Android 4.4+ with Play Services |
| Web      | ❌ Not available | -                               |

## Server-Side Verification

### iOS (App Attest)

```javascript theme={null}
// Node.js example with Apple's App Attest API
const jwt = require('jsonwebtoken');
const { appleAppAttest } = require('apple-app-attest');

async function verifyiOSAttestation(token, challenge) {
  try {
    const decoded = jwt.decode(token, { complete: true });
    
    // Verify with Apple's servers
    const result = await appleAppAttest.verifyAttestation({
      attestation: token,
      challenge,
      bundleId: 'com.yourapp.bundle',
    });

    return result.valid;
  } catch (error) {
    console.error('iOS attestation verification failed:', error);
    return false;
  }
}
```

### Android (Play Integrity)

```javascript theme={null}
// Node.js example with Google Play Integrity API
const { google } = require('googleapis');

async function verifyAndroidAttestation(token, challenge) {
  try {
    const playIntegrity = google.playintegrity('v1');
    
    const response = await playIntegrity.decodeIntegrityToken({
      packageName: 'com.yourapp.package',
      requestBody: { integrityToken: token },
    });

    // Check integrity verdict
    const { appIntegrity, deviceIntegrity } = response.data.tokenPayloadExternal;
    
    return (
      appIntegrity.appRecognitionVerdict === 'PLAY_RECOGNIZED' &&
      deviceIntegrity.deviceRecognitionVerdict.includes('MEETS_DEVICE_INTEGRITY')
    );
  } catch (error) {
    console.error('Android attestation verification failed:', error);
    return false;
  }
}
```

## Configuration

### iOS

No additional configuration required. App Attest is automatically available on iOS 14+.

### Android

Add to `app.json`:

```json theme={null}
{
  "expo": {
    "android": {
      "package": "com.yourapp.package"
    },
    "plugins": [
      [
        "expo-app-integrity",
        {
          "androidCloudProjectNumber": "YOUR_PROJECT_NUMBER"
        }
      ]
    ]
  }
}
```

Enable Play Integrity API in Google Cloud Console.

## Use Cases

* **Anti-Tampering**: Detect if app has been modified or repackaged
* **Emulator Detection**: Identify if app is running on emulator
* **Root/Jailbreak Detection**: Detect rooted or jailbroken devices
* **API Protection**: Verify app integrity before sensitive operations
* **License Verification**: Ensure app is from official store
* **Fraud Prevention**: Prevent abuse from modified apps

## Best Practices

1. **Server Verification**: Always verify attestation tokens on your server
2. **Fresh Challenges**: Use unique, time-limited challenges
3. **Graceful Degradation**: Handle unavailable integrity checks gracefully
4. **Rate Limiting**: Limit attestation requests to prevent abuse
5. **Secure Storage**: Store attestation keys securely
6. **Error Handling**: Handle errors without revealing security details

<Warning>
  Never rely solely on client-side integrity checks. Always verify attestation tokens on your secure server.
</Warning>

## Limitations

* **iOS**: Requires iOS 14 or later
* **Android**: Requires Google Play Services
* **Rate Limits**: Both platforms have rate limits on attestation requests
* **No Web Support**: Not available for web platforms
* **Not Foolproof**: Can be bypassed by sophisticated attackers

<Note>
  App integrity checks provide an additional layer of security but are not foolproof. Use them as part of a comprehensive security strategy.
</Note>

## Resources

* [Official Documentation](https://docs.expo.dev/versions/latest/sdk/app-integrity/)
* [GitHub Repository](https://github.com/expo/expo/tree/main/packages/expo-app-integrity)
* [Apple App Attest](https://developer.apple.com/documentation/devicecheck/validating_apps_that_connect_to_your_server)
* [Google Play Integrity](https://developer.android.com/google/play/integrity)
