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

# Contacts Authorization

> Requesting and managing access to device contacts

# Contacts Authorization

The ContactsManager SDK requires permission to access the user's device contacts. This guide explains how to request and manage contacts access in your app.

## Authorization Status

Check the current authorization status using the `contactsAccessStatus` property:

<CodeGroup>
  ```swift Swift theme={null}
  let status = ContactsService.shared.contactsAccessStatus

  switch status {
  case .notDetermined:
      print("User has not yet been asked for permission")
  case .authorized:
      print("Access granted")
  case .denied:
      print("Access denied")
  case .restricted:
      print("Access restricted")
  }
  ```

  ```jsx React Native theme={null}
  import { checkAccessStatus } from '@contactsmanager/rn';

  // Check access status
  const statusCode = await checkAccessStatus();

  // Status codes follow the native platform values
  // iOS: 0 = notDetermined, 1 = restricted, 2 = denied, 3 = authorized, 4 = limited
  // Android: 0 = denied, 1 = authorized
  switch (statusCode) {
    case 0: // iOS: notDetermined, Android: denied
      console.log("Permission not determined yet (iOS) or denied (Android)");
      break;
    case 3: // iOS: authorized
    case 1: // Android: authorized
      console.log("Access granted");
      break;
    case 2: // iOS: denied
      console.log("Access denied");
      break;
    case 1: // iOS: restricted
      console.log("Access restricted");
      break;
    case 4: // iOS: limited 
      console.log("Limited access granted");
      break;
  }
  ```

  ```kotlin Kotlin theme={null}
  // Get authorization service instance
  val authService = ContactAuthorizationService.getInstance(context)

  // Check current status
  when (authService.checkAccessStatus()) {
      ContactsAccessStatus.NOT_DETERMINED -> {
          println("User has not yet been asked for permission")
      }
      ContactsAccessStatus.AUTHORIZED -> {
          println("Access granted")
      }
      ContactsAccessStatus.DENIED -> {
          println("Access denied")
      }
      ContactsAccessStatus.RESTRICTED -> {
          println("Access restricted")
      }
  }
  ```

  ```objectivec Objective-C theme={null}
  CMContactsAuthorizationService *authService = [CMContactsAuthorizationService sharedInstance];
  ContactsAccessStatus status = [authService checkAccessStatus];

  switch (status) {
      case ContactsAccessStatusNotDetermined:
          NSLog(@"User has not yet been asked for permission");
          break;
      case ContactsAccessStatusAuthorized:
          NSLog(@"Access granted");
          break;
      case ContactsAccessStatusDenied:
          NSLog(@"Access denied");
          break;
      case ContactsAccessStatusRestricted:
          NSLog(@"Access restricted");
          break;
      case ContactsAccessStatusLimitedAuthorized:
          NSLog(@"Limited access granted");
          break;
  }
  ```
</CodeGroup>

## Requesting Access

Request access to contacts with the `requestContactsAccess()` method:

<CodeGroup>
  ```swift Swift theme={null}
  let granted = await ContactsService.shared.requestContactsAccess()

  if granted {
      print("Contacts access granted")
      // Now you can use contacts features
  } else {
      print("Contacts access denied")
      // Handle the denial case
  }
  ```

  ```jsx React Native theme={null}
  import { requestContactsAccess } from '@contactsmanager/rn';

  try {
    // Request access
    const { granted, status } = await requestContactsAccess();
    
    if (granted) {
      console.log("Contacts access granted");
      // Now you can use contacts features
    } else {
      console.log("Contacts access denied");
      // Handle the denial case
    }
  } catch (error) {
    console.error("Error requesting contacts access:", error);
  }
  ```

  ```kotlin Kotlin theme={null}
  // Get authorization service instance
  val authService = ContactAuthorizationService.getInstance(context)

  // Request access
  authService.requestAccess(activity) { status, error ->
      if (error == null && status == ContactsAccessStatus.AUTHORIZED) {
          println("Contacts access granted")
          // Now you can use contacts features
      } else {
          println("Contacts access denied")
          // Handle the denial case
      }
  }
  ```

  ```objectivec Objective-C theme={null}
  CMContactsAuthorizationService *authService = [CMContactsAuthorizationService sharedInstance];
  [authService requestAccessWithCompletion:^(ContactsAccessStatus status, NSError * _Nullable error) {
      if (error == nil && status == ContactsAccessStatusAuthorized) {
          NSLog(@"Contacts access granted");
          // Now you can use contacts features
      } else {
          NSLog(@"Contacts access denied");
          // Handle the denial case
      }
  }];
  ```
</CodeGroup>

### Best Practices for Requesting Access

1. **Explain Why**: Before requesting access, explain to users why your app needs contacts access
2. **Request at the Right Time**: Only request access when you actually need it
3. **Handle Denial Gracefully**: Provide a way for users to enable access later if they initially deny it

## Handling Access Denial

When access is denied, the SDK provides a SwiftUI alert that guides users to the Settings app:

<CodeGroup>
  ```swift Swift theme={null}
  struct ContentView: View {
      var body: some View {
          VStack {
              Text("Your content here")
          }
          // This will only show when access has been denied
          .overlay(ContactsService.shared.settingsAlert)
      }
  }
  ```

  ```jsx React Native theme={null}
  import React, { useEffect, useState } from 'react';
  import { View, Text, Alert, Linking, Platform } from 'react-native';
  import { shouldShowSettingsAlert } from '@contactsmanager/rn';

  function ContactsScreen() {
    useEffect(() => {
      checkSettingsAlert();
    }, []);

    const checkSettingsAlert = async () => {
      try {
        const shouldShow = await shouldShowSettingsAlert();
        
        if (shouldShow) {
          Alert.alert(
            "Contacts Access Required",
            "This app needs access to your contacts. Please enable it in your device settings.",
            [
              { text: "Cancel", style: "cancel" },
              { 
                text: "Open Settings", 
                onPress: () => {
                  if (Platform.OS === 'ios') {
                    Linking.openURL('app-settings:');
                  } else {
                    Linking.openSettings();
                  }
                }
              }
            ]
          );
        }
      } catch (error) {
        console.error("Error checking settings alert:", error);
      }
    };

    return (
      <View>
        <Text>Your content here</Text>
      </View>
    );
  }
  ```

  ```kotlin Kotlin theme={null}
  // Get authorization service instance
  val authService = ContactAuthorizationService.getInstance(context)

  // Check if settings alert should be shown
  if (authService.shouldShowSettingsAlert(activity)) {
      // Show settings alert
      authService.showSettingsAlertView(activity)
  }
  ```

  ```objectivec Objective-C theme={null}
  CMContactsAuthorizationService *authService = [CMContactsAuthorizationService sharedInstance];

  // Check if settings alert should be shown
  if ([authService shouldShowSettingsAlert]) {
      // Show settings alert
      [authService showSettingsAlertViewFromViewController:viewController];
  }
  ```
</CodeGroup>

You can also check if the settings alert should be shown:

<CodeGroup>
  ```swift Swift theme={null}
  if ContactsService.shared.contactsAccessStatus == .denied {
      // Show your custom UI to guide users to settings
  }
  ```

  ```jsx React Native theme={null}
  import { checkAccessStatus, shouldShowSettingsAlert } from '@contactsmanager/rn';

  // Check access status
  const statusCode = await checkAccessStatus();

  // For iOS: 2 = denied, For Android: 0 = denied
  if ((Platform.OS === 'ios' && statusCode === 2) || 
      (Platform.OS === 'android' && statusCode === 0)) {
    // Show your custom UI to guide users to settings
  }

  // Alternative approach
  const shouldShow = await shouldShowSettingsAlert();
  if (shouldShow) {
    // Show your custom UI to guide users to settings
  }
  ```

  ```kotlin Kotlin theme={null}
  // Get authorization service instance
  val authService = ContactAuthorizationService.getInstance(context)

  // Check if access is denied
  if (authService.checkAccessStatus() == ContactsAccessStatus.DENIED) {
      // Show your custom UI to guide users to settings
  }
  ```

  ```objectivec Objective-C theme={null}
  CMContactsAuthorizationService *authService = [CMContactsAuthorizationService sharedInstance];

  if ([authService checkAccessStatus] == ContactsAccessStatusDenied) {
      // Show your custom UI to guide users to settings
  }
  ```
</CodeGroup>

## Privacy Configuration

In addition to requesting permission at runtime, you must configure your app's `Info.plist` file with a privacy description:

<CodeGroup>
  ```xml Swift theme={null}
  <key>NSContactsUsageDescription</key>
  <string>This app needs access to your contacts to provide contact management and social features.</string>
  ```

  ```jsx React Native theme={null}
  // In iOS/Info.plist
  <key>NSContactsUsageDescription</key>
  <string>This app needs access to your contacts to provide contact management and social features.</string>

  // For Android in android/app/src/main/AndroidManifest.xml
  <uses-permission android:name="android.permission.READ_CONTACTS" />
  ```

  ```kotlin Kotlin theme={null}
  // In AndroidManifest.xml
  <uses-permission android:name="android.permission.READ_CONTACTS" />
  ```

  ```objectivec Objective-C theme={null}
  // In Info.plist
  <key>NSContactsUsageDescription</key>
  <string>This app needs access to your contacts to provide contact management and social features.</string>
  ```
</CodeGroup>

This message will be shown to users when they are prompted for permission.

## Complete Authorization Flow Example

Here's a complete example showing the authorization flow:

<CodeGroup>
  ```swift Swift theme={null}
  import SwiftUI
  import ContactsManager

  struct ContactsView: View {
      @State private var isLoading = false
      @State private var contacts: [Contact] = []
      @State private var errorMessage: String?
      
      var body: some View {
          VStack {
              if isLoading {
                  ProgressView("Loading contacts...")
              } else if let error = errorMessage {
                  Text("Error: \(error)")
                      .foregroundColor(.red)
                  Button("Try Again") {
                      checkContactsAccess()
                  }
                  .padding()
              } else if contacts.isEmpty {
                  Text("No contacts found")
                      .foregroundColor(.gray)
              } else {
                  List(contacts, id: \.id) { contact in
                      Text(contact.displayName ?? "Unknown")
                  }
              }
          }
          .navigationTitle("Contacts")
          .onAppear {
              checkContactsAccess()
          }
          // Show settings alert if needed
          .overlay(ContactsService.shared.settingsAlert)
      }
      
      private func checkContactsAccess() {
          Task {
              let status = ContactsService.shared.contactsAccessStatus
              
              switch status {
              case .notDetermined:
                  // Request access
                  let granted = await ContactsService.shared.requestContactsAccess()
                  if granted {
                      loadContacts()
                  } else {
                      errorMessage = "Contacts access denied"
                  }
                  
              case .authorized:
                  // Already have access, load contacts
                  loadContacts()
                  
              case .denied, .restricted:
                  // Access denied or restricted
                  errorMessage = "Please grant contacts access in Settings"
              }
          }
      }
      
      private func loadContacts() {
          isLoading = true
          errorMessage = nil
          
          Task {
              do {
                  // First ensure contacts are synced
                  _ = try await ContactsService.shared.syncContacts()
                  
                  // Then fetch contacts
                  let fetchedContacts = try await ContactsService.shared.fetchContacts(
                      fieldType: .any
                  )
                  
                  DispatchQueue.main.async {
                      self.contacts = fetchedContacts
                      self.isLoading = false
                  }
              } catch {
                  DispatchQueue.main.async {
                      self.errorMessage = error.localizedDescription
                      self.isLoading = false
                  }
              }
          }
      }
  }
  ```

  ```jsx React Native theme={null}
  import React, { useState, useEffect } from 'react';
  import { View, Text, FlatList, ActivityIndicator, Button, StyleSheet, Platform } from 'react-native';
  import { 
    requestContactsAccess, 
    checkAccessStatus, 
    shouldShowSettingsAlert, 
    hasContactsReadAccess,
    getContacts 
  } from '@contactsmanager/rn';

  function ContactsScreen() {
    const [isLoading, setIsLoading] = useState(false);
    const [contacts, setContacts] = useState([]);
    const [errorMessage, setErrorMessage] = useState(null);

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

    const checkContactsAccess = async () => {
      try {
        const statusCode = await checkAccessStatus();
        
        // iOS: 0 = notDetermined, Android: already handled in requestAccess
        if (Platform.OS === 'ios' && statusCode === 0) {
          // Request access
          const { granted } = await requestContactsAccess();
          if (granted) {
            loadContacts();
          } else {
            setErrorMessage("Contacts access denied");
          }
        } else if ((Platform.OS === 'ios' && statusCode === 3) || 
                   (Platform.OS === 'android' && statusCode === 1)) {
          // Access already granted
          loadContacts();
        } else {
          // Access denied or restricted
          const shouldShow = await shouldShowSettingsAlert();
          if (shouldShow) {
            setErrorMessage("Please grant contacts access in Settings");
          }
        }
      } catch (error) {
        setErrorMessage(`Error checking contacts access: ${error.message}`);
      }
    };

    const loadContacts = async () => {
      setIsLoading(true);
      setErrorMessage(null);
      
      try {
        // Check if we have read access
        const hasReadAccess = await hasContactsReadAccess();
        
        if (hasReadAccess) {
          // Fetch contacts
          const fetchedContacts = await getContacts();
          
          setContacts(fetchedContacts);
          setIsLoading(false);
        } else {
          setErrorMessage("No read access to contacts");
          setIsLoading(false);
        }
      } catch (error) {
        setErrorMessage(`Error loading contacts: ${error.message}`);
        setIsLoading(false);
      }
    };

    return (
      <View style={styles.container}>
        {isLoading ? (
          <ActivityIndicator size="large" />
        ) : errorMessage ? (
          <View style={styles.errorContainer}>
            <Text style={styles.errorText}>Error: {errorMessage}</Text>
            <Button title="Try Again" onPress={checkContactsAccess} />
          </View>
        ) : contacts.length === 0 ? (
          <Text style={styles.emptyText}>No contacts found</Text>
        ) : (
          <FlatList
            data={contacts}
            keyExtractor={(item) => item.contactId || item.id}
            renderItem={({ item }) => (
              <Text style={styles.contactName}>{item.displayName || "Unknown"}</Text>
            )}
          />
        )}
      </View>
    );
  }

  const styles = StyleSheet.create({
    container: {
      flex: 1,
      padding: 16,
    },
    errorContainer: {
      flex: 1,
      justifyContent: 'center',
      alignItems: 'center',
    },
    errorText: {
      color: 'red',
      marginBottom: 16,
    },
    emptyText: {
      textAlign: 'center',
      color: 'gray',
    },
    contactName: {
      fontSize: 16,
      paddingVertical: 8,
    },
  });

  export default ContactsScreen;
  ```

  ```kotlin Kotlin theme={null}
  // Get authorization service instance
  val authService = ContactAuthorizationService.getInstance(context)

  // Check current status
  when (authService.checkAccessStatus()) {
      ContactsAccessStatus.NOT_DETERMINED -> {
          println("User has not yet been asked for permission")
      }
      ContactsAccessStatus.AUTHORIZED -> {
          println("Access granted")
      }
      ContactsAccessStatus.DENIED -> {
          println("Access denied")
      }
      ContactsAccessStatus.RESTRICTED -> {
          println("Access restricted")
      }
  }
  ```

  ```objectivec Objective-C theme={null}
  CMContactsAuthorizationService *authService = [CMContactsAuthorizationService sharedInstance];
  ContactsAccessStatus status = [authService checkAccessStatus];

  switch (status) {
      case ContactsAccessStatusNotDetermined:
          NSLog(@"User has not yet been asked for permission");
          break;
      case ContactsAccessStatusAuthorized:
          NSLog(@"Access granted");
          break;
      case ContactsAccessStatusDenied:
          NSLog(@"Access denied");
          break;
      case ContactsAccessStatusRestricted:
          NSLog(@"Access restricted");
          break;
      case ContactsAccessStatusLimitedAuthorized:
          NSLog(@"Limited access granted");
          break;
  }
  ```
</CodeGroup>

## Troubleshooting

### Common Issues

1. **Permission Dialog Not Showing**
   * Verify that you've added the `NSContactsUsageDescription` key to your Info.plist
   * Make sure you're calling `requestContactsAccess()` on the main thread

2. **Permission Denied**
   * Use the settings alert to guide users to enable access in Settings
   * Explain the benefits of contacts access clearly

3. **Sync Failing After Permission Granted**
   * Make sure the SDK is properly initialized
   * Check for network connectivity issues
   * Verify that you've registered the contact source
