{"id":51122462,"url":"https://github.com/arpitaswal/biometric-authentication-secure-flow","last_synced_at":"2026-06-25T04:00:34.180Z","repository":{"id":359808401,"uuid":"1243823511","full_name":"ArpitAswal/Biometric-Authentication-Secure-Flow","owner":"ArpitAswal","description":"A Flutter application demonstrating standard biometric authentication (Fingerprint / Face ID) patterns, featuring \"Remember Me\" (Soft Logout) and account removal (Hard Logout) capabilities.","archived":false,"fork":false,"pushed_at":"2026-05-23T14:19:02.000Z","size":98,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-23T16:16:15.705Z","etag":null,"topics":["biometric-authentication","email-authentication","flutter-app","google-authentication","secure-storage"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ArpitAswal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-19T17:43:46.000Z","updated_at":"2026-05-23T14:26:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ArpitAswal/Biometric-Authentication-Secure-Flow","commit_stats":null,"previous_names":["arpitaswal/biometric-authentication-secure-flow"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/ArpitAswal/Biometric-Authentication-Secure-Flow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArpitAswal%2FBiometric-Authentication-Secure-Flow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArpitAswal%2FBiometric-Authentication-Secure-Flow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArpitAswal%2FBiometric-Authentication-Secure-Flow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArpitAswal%2FBiometric-Authentication-Secure-Flow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ArpitAswal","download_url":"https://codeload.github.com/ArpitAswal/Biometric-Authentication-Secure-Flow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ArpitAswal%2FBiometric-Authentication-Secure-Flow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34758776,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-25T02:00:05.521Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["biometric-authentication","email-authentication","flutter-app","google-authentication","secure-storage"],"created_at":"2026-06-25T04:00:33.240Z","updated_at":"2026-06-25T04:00:34.139Z","avatar_url":"https://github.com/ArpitAswal.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Premium Biometric Authentication App\n\nA Flutter application demonstrating standard biometric authentication (Fingerprint / Face ID) patterns, featuring \"Remember Me\" (Soft Logout) and account removal (Hard Logout) capabilities.\n\n---\n\n## 📱 Try the App\nYou can download and install the latest working version of the app directly on your Android device:\n\n[![Download APK](https://img.shields.io/badge/Download-APK-green?style=for-the-badge\u0026logo=android)](https://github.com/ArpitAswal/Biometric-Authentication-Secure-Flow/releases/download/v1.0.0/app-release.apk)\n\n---\n\n## ⚙️ Google Sign-In Setup (Required before running)\n\nGoogle Sign-In requires a `google-services.json` file that links your Android app to a Firebase project. This file contains your API keys and client IDs, etc.\n### Step 1 — Create a Firebase project\n\n1. Go to [https://console.firebase.google.com](https://console.firebase.google.com) and create (or open) a project.\n2. Click **Add app → Android**.\n3. Enter the **Android package name**: `com.example.biomteric_signin`\n   *(This must match `applicationId` in `android/app/build.gradle.kts`)*\n4. Enter a **debug SHA-1 fingerprint** (see Step 2 below).\n5. Download the generated `google-services.json`.\n\n### Step 2 — Get your debug SHA-1 fingerprint\n\nRun this command in your terminal:\n\n```bash\nkeytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android\n```\n\nCopy the `SHA1` value and paste it into the Firebase console during app registration.\n\n### Step 3 — Place google-services.json\n\nCopy the downloaded file into:\n\n```\nandroid/app/google-services.json   ← place it here\nandroid/app/google-services.json.example  ← this is the safe template (already committed)\n```\n\n\n### Step 4 — Enable Google Sign-In in Firebase\n\n1. In the Firebase console, go to **Authentication → Sign-in method**.\n2. Enable **Google** as a sign-in provider and save.\n\n### Step 5 — For teammates / CI (keeping secrets out of GitHub)\n\nBecause `google-services.json` is gitignored, your teammates need to generate their own. There are two common approaches:\n\n| Approach | How |\n|:---|:---|\n| **Manual** | Each developer follows Steps 1-3 above and downloads their own copy. |\n| **CI/CD Secret** | Store the file content as a base64-encoded secret in GitHub Actions / Bitrise, then decode it during the build step. |\n\nFor GitHub Actions, add this to your workflow:\n\n```yaml\n- name: Decode google-services.json\n  run: echo \"${{ secrets.GOOGLE_SERVICES_JSON }}\" | base64 --decode \u003e android/app/google-services.json\n```\n\n### Step 6 — Secure Web Client ID Configuration (Keeping Web Client ID Private)\n\nOn Android, the `google_sign_in` package requires an explicit `serverClientId` (which corresponds to your Google Web Client ID) during initialization. To prevent committing this credential to a public GitHub repository, the app reads it at compile time from the environment variable `GOOGLE_WEB_CLIENT_ID` via `String.fromEnvironment`.\n\nHere are three ways to supply this ID:\n\n#### Option A: Using `secrets.json` (Recommended for Local Dev)\n1. Copy [secrets.json.example](file:///Users/arpit/StudioProjects/biomteric_signin/secrets.json.example) to `secrets.json` in the project root:\n   ```json\n   {\n     \"GOOGLE_WEB_CLIENT_ID\": \"YOUR_WEB_CLIENT_ID_HERE\"\n   }\n   ```\n   *(Note: `secrets.json` is already gitignored, so it won't be pushed to Git.)*\n\n2. Run or build the app by passing the `--dart-define-from-file` flag:\n   ```bash\n   flutter run --dart-define-from-file=secrets.json\n   ```\n\n#### Option B: Inline CLI Argument\nDirectly pass it as a `--dart-define` key-value pair in your command-line terminal:\n```bash\nflutter run --dart-define=GOOGLE_WEB_CLIENT_ID=YOUR_WEB_CLIENT_ID_HERE\n```\n\n#### Option C: IDE Run Configurations\n- **VS Code**: Create a `.vscode/launch.json` file in the project root and add the argument to `toolArgs`:\n  ```json\n  {\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n      {\n        \"name\": \"biomteric_signin\",\n        \"request\": \"launch\",\n        \"type\": \"dart\",\n        \"toolArgs\": [\n          \"--dart-define-from-file\",\n          \"secrets.json\"\n        ]\n      }\n    ]\n  }\n  ```\n  *(Or use `--dart-define` inline arguments if you prefer: `\"toolArgs\": [\"--dart-define\", \"GOOGLE_WEB_CLIENT_ID=...\"]`)*\n- **Android Studio / IntelliJ**:\n  1. Open the Run Configurations dropdown and select **Edit Configurations...**\n  2. In the **Additional run args** field, add: `--dart-define-from-file=secrets.json` or `--dart-define=GOOGLE_WEB_CLIENT_ID=...`\n\n#### CI/CD Setup (e.g., GitHub Actions)\nTo build your app in CI/CD pipelines, configure `GOOGLE_WEB_CLIENT_ID` as a repository secret and inject it:\n```yaml\n- name: Build Android App Bundle\n  run: flutter build appbundle --release --dart-define=GOOGLE_WEB_CLIENT_ID=${{ secrets.GOOGLE_WEB_CLIENT_ID }}\n```\n\n---\n\n\n## Architecture \u0026 Authentication Flows\n\n### Biometric Flow (Multi-User Single-Device Handling)\n\nSince mobile operating systems (iOS Secure Enclave \u0026 Android Keystore) verify whether the *device owner* has authenticated but do not identify *which* specific user is logging in, this application implements a standard single-active-biometric pattern. \n\nOnly the **last user who logged in and enabled biometrics** can log in via biometric authentication. Logging in with a different account automatically wipes the previously stored biometric configuration to ensure security.\n\n```mermaid\ngraph TD\n    A[Start: App Opened] --\u003e B{Saved Biometric Credentials Exist?}\n    B -- Yes --\u003e C[Show Quick Biometric Login]\n    B -- No --\u003e D[Show Manual Login Screen]\n    \n    C --\u003e E[User taps Biometric Login]\n    E --\u003e F[Fingerprint/Face Scan]\n    F -- Success --\u003e G[Decrypt Token -\u003e Log into Saved Account]\n    F -- Fail --\u003e D\n    \n    D --\u003e H[User logs in manually]\n    H --\u003e I{Is this a different user from saved account?}\n    I -- Yes --\u003e J[Delete old biometric token \u0026 settings]\n    I -- No --\u003e K[Proceed]\n    J --\u003e K\n    K --\u003e L[Save new User's credentials to Secure Storage]\n    L --\u003e M[App Dashboard]\n```\n\n---\n\n### Scenario 1: User A enables biometrics, User B logs in manually (does not enable biometrics)\n\n| Step | Action | Secure Storage State | Login Screen Behavior |\n| :--- | :--- | :--- | :--- |\n| **1** | **User A** logs in and enables biometrics. | `savedUsername` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"token_A\"` | — |\n| **2** | **User A** logs out (Soft Logout). | `savedUsername` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"token_A\"` | **Quick Biometric Sign-In** button is visible. |\n| **3** | **User B** logs in manually. | `savedUsername` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `false`\u003cbr\u003e`token` = `null` | Previous biometric setup for User A is deleted on detection of a different user. |\n| **4** | **User B** logs out (Soft Logout). | `savedUsername` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `false`\u003cbr\u003e`token` = `null` | **Quick Biometric Sign-In** button is hidden. |\n\n---\n\n### Scenario 2: Both User A and User B enable biometrics\n\n| Step | Action | Secure Storage State | Login Screen Behavior |\n| :--- | :--- | :--- | :--- |\n| **1** | **User A** logs in and enables biometrics. | `savedUsername` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"token_A\"` | — |\n| **2** | **User A** logs out (Soft Logout). | `savedUsername` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"token_A\"` | **Quick Biometric Sign-In** button is visible. |\n| **3** | **User B** logs in manually. | `savedUsername` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `false`\u003cbr\u003e`token` = `null` | User A's configurations are cleared. |\n| **4** | **User B** enables biometrics in settings. | `savedUsername` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"token_B\"` | — |\n| **5** | **User B** logs out (Soft Logout). | `savedUsername` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"token_B\"` | **Quick Biometric Sign-In** button is visible for **User B**. |\n\n---\n\n### 🌐 Google Sign-In Biometric Flow\n\nFor Google Sign-In, the biometric setup and verification work identically to the email/password flow but leverage Secure Storage to persist the provider type (`\"google\"`), the user's Google email (`savedUsername`), and the user's name (`savedDisplayName`).\n\n#### Flow Diagram\n\n```mermaid\ngraph TD\n    A[Start: Google Sign-in Successful] --\u003e B[Save user.email, user.displayName, authProvider='google']\n    B --\u003e C[Save google_secure_token_ID to Secure Storage]\n    C --\u003e D[User opts-in to Biometric Login in Settings]\n    D --\u003e E[biometricEnabled = true in Secure Storage]\n    E --\u003e F[User performs Soft Logout]\n    F --\u003e G[Clear in-memory session \u0026 call googleSignIn.signOut]\n    G --\u003e H[Saved state remains in Secure Storage]\n    H --\u003e I[Login Screen: Quick Biometric Sign-In displays with Google User info]\n    I --\u003e J[User taps Quick Biometric Sign-In]\n    J --\u003e K[Biometric Authentication prompt]\n    K -- Success --\u003e L[Retrieve stored token \u0026 authProvider='google']\n    L --\u003e M[Reconstruct AccountModel without network call]\n    M --\u003e N[Dashboard Access Restored]\n    K -- Failure --\u003e O[Stay on Login Screen]\n```\n\n#### Google Scenario 1: Google User A enables biometrics, Google User B logs in manually (does not enable biometrics)\n\n| Step | Action | Secure Storage State | Login Screen Behavior |\n| :--- | :--- | :--- | :--- |\n| **1** | **Google User A** logs in and enables biometrics. | `savedUsername` = `\"user_a@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"google_secure_token_ID_A\"` | — |\n| **2** | **Google User A** logs out (Soft Logout). | `savedUsername` = `\"user_a@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"google_secure_token_ID_A\"` | **Quick Biometric Sign-In** button is visible (labeled with User A's Google credentials). |\n| **3** | **Google User B** logs in manually via Google. | `savedUsername` = `\"user_b@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `false`\u003cbr\u003e`token` = `null` | App detects a different user account. Previous biometric setup for User A is deleted. |\n| **4** | **Google User B** logs out (Soft Logout). | `savedUsername` = `\"user_b@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `false`\u003cbr\u003e`token` = `null` | **Quick Biometric Sign-In** button is hidden. |\n\n---\n\n#### Google Scenario 2: Both Google User A and Google User B enable biometrics\n\n| Step | Action | Secure Storage State | Login Screen Behavior |\n| :--- | :--- | :--- | :--- |\n| **1** | **Google User A** logs in and enables biometrics. | `savedUsername` = `\"user_a@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"google_secure_token_ID_A\"` | — |\n| **2** | **Google User A** logs out (Soft Logout). | `savedUsername` = `\"user_a@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"google_secure_token_ID_A\"` | **Quick Biometric Sign-In** button is visible for **User A**. |\n| **3** | **Google User B** logs in manually via Google. | `savedUsername` = `\"user_b@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `false`\u003cbr\u003e`token` = `null` | User A's configurations are cleared on different user detection. |\n| **4** | **Google User B** enables biometrics in settings. | `savedUsername` = `\"user_b@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"google_secure_token_ID_B\"` | — |\n| **5** | **Google User B** logs out (Soft Logout). | `savedUsername` = `\"user_b@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"google_secure_token_ID_B\"` | **Quick Biometric Sign-In** button is visible for **User B**. |\n\n---\n\n#### Cross-Provider Scenario 3: Google User A enables biometrics, Email/Password User B logs in\n\n| Step | Action | Secure Storage State | Login Screen Behavior |\n| :--- | :--- | :--- | :--- |\n| **1** | **Google User A** logs in and enables biometrics. | `savedUsername` = `\"user_a@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"google_secure_token_ID_A\"` | — |\n| **2** | **Google User A** logs out (Soft Logout). | `savedUsername` = `\"user_a@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"google_secure_token_ID_A\"` | **Quick Biometric Sign-In** button is visible for **User A**. |\n| **3** | **User B** logs in using **Email/Password** (`user_b@email.com`). | `savedUsername` = `\"user_b@email.com\"`\u003cbr\u003e`savedAuthProvider` = `\"email\"`\u003cbr\u003e`savedDisplayName` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `false`\u003cbr\u003e`token` = `null` | App detects username change. Google User A's configurations are deleted. |\n| **4** | **User B** logs out (Soft Logout). | `savedUsername` = `\"user_b@email.com\"`\u003cbr\u003e`savedAuthProvider` = `\"email\"`\u003cbr\u003e`savedDisplayName` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `false`\u003cbr\u003e`token` = `null` | **Quick Biometric Sign-In** button is hidden. |\n\n---\n\n#### Cross-Provider Scenario 4: Email/Password User A enables biometrics, Google User B logs in\n\n| Step | Action | Secure Storage State | Login Screen Behavior |\n| :--- | :--- | :--- | :--- |\n| **1** | **User A** logs in using **Email/Password** (`user_a@email.com`) and enables biometrics. | `savedUsername` = `\"user_a@email.com\"`\u003cbr\u003e`savedAuthProvider` = `\"email\"`\u003cbr\u003e`savedDisplayName` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"email_secure_token_ID_A\"` | — |\n| **2** | **User A** logs out (Soft Logout). | `savedUsername` = `\"user_a@email.com\"`\u003cbr\u003e`savedAuthProvider` = `\"email\"`\u003cbr\u003e`savedDisplayName` = `\"User A\"`\u003cbr\u003e`biometricEnabled` = `true`\u003cbr\u003e`token` = `\"email_secure_token_ID_A\"` | **Quick Biometric Sign-In** button is visible for **User A**. |\n| **3** | **Google User B** logs in via **Google Sign-In** (`user_b@gmail.com`). | `savedUsername` = `\"user_b@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `false`\u003cbr\u003e`token` = `null` | App detects username change. User A's Email configurations are deleted. |\n| **4** | **Google User B** logs out (Soft Logout). | `savedUsername` = `\"user_b@gmail.com\"`\u003cbr\u003e`savedAuthProvider` = `\"google\"`\u003cbr\u003e`savedDisplayName` = `\"User B\"`\u003cbr\u003e`biometricEnabled` = `false`\u003cbr\u003e`token` = `null` | **Quick Biometric Sign-In** button is hidden. |\n\n---\n\n## Soft Logout vs. Hard Logout\n\n1. **Soft Logout (Logout)**\n   - Triggered via the **Logout** button.\n   - Clears the active in-memory session.\n   - Retains the token, username, and biometric configuration in Secure Storage.\n   - Allows the user to quickly log back in with biometrics on the login page.\n\n2. **Hard Logout (Remove Account)**\n   - Triggered via the **Remove Account from Device** (or **Forget Saved Account**) button.\n   - Completely deletes all credentials from Secure Storage.\n   - Disables biometric sign-in so that the next user must input their email/password manually.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farpitaswal%2Fbiometric-authentication-secure-flow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farpitaswal%2Fbiometric-authentication-secure-flow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farpitaswal%2Fbiometric-authentication-secure-flow/lists"}