블로그 목록

expo-local-authentication으로 지문·Face ID 잠금 붙이기

가계부 앱을 만들다가 앱을 열 때마다 잠금을 걸고 싶어졌다. 민감한 데이터가 있으니 백그라운드에서 돌아왔을 때 지문이나 Face ID로 한 번 확인하는 흐름이다. 직접 지문 API를 붙이려면 iOS는 LocalAuthentication, Android는 BiometricPrompt를 각각 만져야 하는데, Expo에서는 expo-local-authentication 하나로 두 플랫폼이 다 덮인다.

설치

npx expo install expo-local-authentication

iOS는 Face ID를 쓰려면 사용 이유를 Info.plist에 넣어줘야 한다. app.json의 플러그인 설정으로 처리한다.

{
  "plugins": [
    ["expo-local-authentication", {
      "faceIDPermission": "앱 잠금 해제를 위해 Face ID를 사용합니다."
    }]
  ]
}

이걸 빠뜨리면 iOS에서 Face ID 프롬프트가 뜨는 순간 앱이 그냥 죽는다. 처음에 원인을 못 찾고 한참 헤맸다.

인증하기 전에 하드웨어부터 확인

바로 인증을 띄우면 안 된다. 기기에 센서가 있는지, 지문/얼굴이 등록돼 있는지를 먼저 봐야 한다. 이 두 가지를 안 거르면 센서 없는 기기에서 그냥 실패로 떨어진다.

import * as LocalAuthentication from 'expo-local-authentication';

async function authenticate() {
  const hasHardware = await LocalAuthentication.hasHardwareAsync();
  const isEnrolled = await LocalAuthentication.isEnrolledAsync();

  if (!hasHardware || !isEnrolled) {
    // 생체 인증을 못 쓰는 기기 → PIN 입력 화면으로 폴백
    return { success: false, fallback: true };
  }

  const result = await LocalAuthentication.authenticateAsync({
    promptMessage: '앱 잠금 해제',
    fallbackLabel: '비밀번호 입력',
    disableDeviceFallback: false,
  });

  return { success: result.success, fallback: false };
}

disableDeviceFallbackfalse로 두면 생체 인증이 몇 번 실패했을 때 기기 PIN 입력으로 자동 폴백된다. 손이 젖었거나 마스크를 썼을 때를 생각하면 이걸 막아두는 건 사용성에 안 좋다.

어떤 인증 수단이 있는지 구분하기

버튼 문구를 "지문으로 잠금 해제"로 할지 "Face ID로 잠금 해제"로 할지 정하려면 어떤 센서인지 알아야 한다.

const types = await LocalAuthentication.supportedAuthenticationTypesAsync();

const hasFaceId = types.includes(
  LocalAuthentication.AuthenticationType.FACIAL_RECOGNITION
);
const label = hasFaceId ? 'Face ID로 잠금 해제' : '지문으로 잠금 해제';

FINGERPRINT, FACIAL_RECOGNITION, IRIS 세 가지가 있고, 배열로 여러 개가 동시에 올 수도 있다.

실전 팁 하나

authenticateAsync는 앱이 백그라운드로 갔다가 돌아올 때 호출하는 게 보통인데, AppStateactive로 바뀌는 순간마다 무조건 부르면 프롬프트가 겹쳐서 뜬다. 인증 진행 중 플래그를 하나 두고, 이미 떠 있으면 재호출을 막아야 깔끔하다.


정리하면 흐름은 단순하다. 하드웨어·등록 여부 확인 → 인증 → 실패 시 PIN 폴백. 직접 네이티브 두 개를 붙였으면 하루는 걸렸을 일이 30분이면 끝났다. 다만 Face ID 권한 문구를 빠뜨리면 크래시가 나니 그것만 조심하자.