패키지, 저장소 및 앱 카테고리 검색

GitHub 저장소authpass/biometric_storage

생체 인식 저장

생체 인증(예: 지문) 뒤에 데이터를 저장하는 Flutter 플러그인

생체 인식 저장 프로젝트 이미지
스타
198
포크
123
최근 푸시(UTC)
2026. 8. 26.
프로젝트 상태
활성

원본 README

아래는 영문 원문 스냅샷입니다. 최신 내용은 GitHub에서 확인하세요.

biometric_storage

Pub

Encrypted file store, optionally secured by biometric lock for Android, iOS, MacOS and partial support for Linux, Windows and Web.

Meant as a way to store small data in a hardware encrypted fashion. E.g. to store passwords, secret keys, etc. but not massive amounts of data.

  • Android: Uses androidx with KeyStore.
  • iOS and MacOS: LocalAuthentication with KeyChain.
  • Linux: Stores values in Keyring using libsecret. (No biometric authentication support).
  • Windows: Uses wincred.h to read/write into the credential store.
  • Web: Warning Uses unauthenticated, unencrypted storage in localStorage. If you have a better idea for secure storage on web platform, please open an Issue.

Check out AuthPass Password Manager for a app which makes heavy use of this plugin.

Getting Started

Installation
Android

Always required:

  • API Level >= 23 (android/app/build.gradle minSdkVersion 23)

Required only if you actually prompt for authentication, that is, if any storage uses the default authenticationRequired: true. Storage created with authenticationRequired: false never shows a BiometricPrompt, so neither of the following applies to it:

  • MainActivity must extend FlutterFragmentActivity. BiometricPrompt needs a FragmentActivity to host its dialog. If the plugin is attached to a plain FlutterActivity it logs an error and every authenticated read or write fails with AuthError:Failed — unauthenticated storage keeps working.

  • The activity theme must descend from Theme.AppCompat — but only for devices where androidx.biometric falls back to drawing its own fingerprint dialog, which it builds with androidx.appcompat.app.AlertDialog. That fallback is used below API 28, on API 28 devices without a fingerprint sensor, and on a short manufacturer allow-list where a crypto object forces it. From API 28 onwards the system BiometricPrompt is used and the theme does not matter.

    If you do need it:

    android/app/src/main/AndroidManifest.xml:

    <activity
        android:name=".MainActivity"
        android:launchMode="singleTop"
        android:theme="@style/LaunchTheme">
        [...]
        <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
    </activity>
    

    android/app/src/main/res/values/styles.xml:

    <resources>
      <style name="LaunchTheme" parent="Theme.AppCompat.NoActionBar">
        ...
      </style>
      <style name="NormalTheme" parent="Theme.AppCompat.NoActionBar">
        ...
      </style>
    </resources>
    
Logging

The plugin writes to android.util.Log under the tag BiometricStorage. A debug build logs everything; a release build logs nothing below INFO until you ask for it:

adb shell setprop log.tag.BiometricStorage VERBOSE

That suits reading logs off a device. If your app collects its own — a file appender, a crash reporter, slf4j, Timber — install a sink instead, from Application.onCreate or your FlutterActivity, before the first call into the plugin:

import android.util.Log
import design.codeux.biometric_storage.BiometricStorageLogging
import org.slf4j.LoggerFactory

BiometricStorageLogging.sink =
    BiometricStorageLogging.Sink { priority, tag, message, throwable ->
        val log = LoggerFactory.getLogger(tag)
        when (priority) {
            Log.VERBOSE -> log.trace(message, throwable)
            Log.DEBUG -> log.debug(message, throwable)
            Log.INFO -> log.info(message, throwable)
            Log.WARN -> log.warn(message, throwable)
            else -> log.error(message, throwable)
        }
    }

Installing a sink turns every level on, since it says something wants the records. To decide the level yourself — including keeping verbose logging in a release build without touching a device property — set it explicitly:

BiometricStorageLogging.level = Log.VERBOSE

throwable is passed separately rather than flattened into message, so you can hand the real exception to whatever you report to. The sink is called on whichever thread produced the record, so it must be safe to call from the main thread and from a background executor.

Resources
  • https://developer.android.com/topic/security/data
  • https://developer.android.com/topic/security/best-practices
iOS

https://developer.apple.com/documentation/localauthentication/logging_a_user_into_your_app_with_face_id_or_touch_id

  • include the NSFaceIDUsageDescription key in your app’s Info.plist file
  • Deployment target >= iOS 13 (below whatever Flutter itself requires, so in practice this never binds).

Known Issue: since iOS 15 the simulator seem to no longer support local authentication: https://developer.apple.com/forums/thread/685773

IosPromptInfo.saveTitle / accessTitle are invisible on Face ID devices. Face ID authenticates against a HUD that shows its glyph and the words "Face ID" and nothing else, and the "not recognized" alert after a failure offers only retry and cancel. The strings do reach the system — they are set as LAContext.localizedReason — but iOS does not draw them. Touch ID devices and macOS do show them, so they are still worth setting.

Mac OS
  • include the NSFaceIDUsageDescription key in your app’s Info.plist file
  • enable keychain sharing and signing. (not sure why this is required. but without it You will probably see an error like:

    SecurityError, Error while writing data: -34018: A required entitlement isn't present.

  • Deployment target >= macOS 10.15.
Swift Package Manager (iOS and Mac OS)

The iOS and macOS implementations ship both a Package.swift and a podspec, so they work with either dependency manager. Adding this plugin to an app that has migrated to Swift Package Manager does not bring CocoaPods back — no Podfile is generated.

Usage

You basically only need 4 methods.

  1. Check whether biometric authentication is supported by the device
  final response = await BiometricStorage().canAuthenticate()
  if (response != CanAuthenticateResponse.success) {
    // panic..
  }
  1. Create the access object
  final storageFile = await BiometricStorage().getStorage('mystorage');
  1. Read data
  final data = await storageFile.read();
  1. Write data
  final myNewData = 'Hello World';
  await storageFile.write(myNewData);

Storing without a biometric prompt — for a value a background task has to be able to refresh, for example — is authenticationRequired: false. The value is still encrypted at rest; it is simply not gated behind an authentication.

  final storageFile = await BiometricStorage().getStorage(
    'mystorage',
    options: StorageFileInitOptions(authenticationRequired: false),
  );

See also the API documentation: https://pub.dev/documentation/biometric_storage/latest/biometric_storage/BiometricStorageFile-class.html#instance-methods

AuthPass GitHub avatar
GitHub 작성자

AuthPass ↗

AuthPass – Password Manager

언어DartKotlinC++SwiftCMakeCHTMLRubyObjective-C

이 저장소가 배포한 패키지

사용 중인 의존성

의존성 목록 9 개

  • flutter{"sdk":"flutter"}
  • flutter_web_plugins{"sdk":"flutter"}
  • logging>=1.0.0 <2.0.0
  • plugin_platform_interface>=2.0.0 <3.0.0
  • ffi>=2.1.0 <3.0.0
  • win32>=6.0.1 <7.0.0
  • web>=0.5.0 <2.0.0
  • flutter_test개발 의존성{"sdk":"flutter"}
  • flutter_lints개발 의존성^6.0.0

프로젝트에 맞는 저장소를 선택하려면?

사용 목적에 따라 검색하고 개발 활동을 비교한 뒤 원본 저장소에서 요구 사항을 확인하세요.

  1. 이름, 작성자 또는 설명으로 검색하고 기술 주제로 범위를 좁힙니다.
  2. 스타, 포크, 최근 푸시를 함께 비교하세요. 스타는 관심의 지표이며 품질을 보장하지 않습니다.
  3. 사용하기 전에 GitHub에서 README, 라이선스, Issues를 확인하세요.

출처 및 관리

“A repository is the most basic element of GitHub.”

GitHub Docs — About repositories ↗