Capacitor Secure Storage

repository·main·Indexed 41 days ago

https://github.com/aparajita/capacitor-secure-storage

A Capacitor 8+ plugin providing secure key/value storage using the iOS Keychain and Android KeyStore. It supports JSON data types, iCloud Keychain synchronization on iOS, and provides a VueUse-compatible interface for string-based storage. Note: Web implementation uses unencrypted localStorage and is intended for debugging only.

Tokens
9.4K
Snippets
16
Records
19
Agent score
51%

What's inside capacitor-secure-storage

  1. How secure storage works on iOS, Android, and Web

    main

    The storage mechanism varies by platform:

    • iOS: Data is stored in the encrypted system keychain and is specific to your app. Note that iOS does not delete keychain data when the app is deleted.
    • Android: Data is encrypted using AES in GCM mode with a secret key generated by the Android KeyStore, then stored in SharedPreferences. Data is deleted if the app is deleted.
    • Web: Data is stored unencrypted in localStorage. This is intended for debugging purposes only; do not use this plugin on the web in production.
  2. Configure iCloud Keychain sync on iOS

    main

    On iOS, you can synchronize secure data across multiple devices using iCloud Keychain.

    Synchronization can be controlled in two ways:

    1. Globally: Use setSynchronize() to turn sync on or off for the entire app.
    2. Per Operation: Pass a sync boolean in the options object of a specific operation to override the global setting.

    Important behaviors:

    • The user must have iCloud Keychain enabled on their device for sync to work.
    • iOS treats the local keychain and iCloud keychain as separate entities. A value can exist in both keychains under the same key.
    • When the resolved sync setting is true, calls to keys() return keys from both the iCloud and local keychains, which may result in duplicates.
  3. Run the project demos

    main

    The repository includes Ionic/Vue demo apps (available in demo-pods and demo-spm variants for iOS). To run them, you must first build the plugin locally.

    1. Clone and install dependencies:
    git clone https://github.com/aparajita/capacitor-secure-storage.git
    cd capacitor-secure-storage
    pnpm install -r
    1. Build the plugin:
    pnpm build
    1. Run the demos from the root:
    • iOS:
      • pnpm demo.pods.ios
      • pnpm demo.spm.ios
    • Android:
      • pnpm demo.pods.android
      • pnpm demo.spm.android
    • Web:
      • pnpm demo.pods.browser
      • pnpm demo.spm.browser
    pnpm build
    # Then run specific demo commands
    pnpm demo.pods.ios
  4. Configure oxlint with oxlint.config.jsonc

    main

    The project uses oxlint for linting. Configuration is managed via an oxlint.config.jsonc file. This file allows you to define ignore patterns, plugins, environment settings, and specific rule configurations for various linting engines (ESLint, Import, Node, OXC, Promise, TypeScript, and Unicorn).

    Key configuration sections include:

    • ignorePatterns: Files or directories to skip (e.g., **/*.d.ts, .claude/**).
    • plugins: The linting plugins enabled for the project.
    • env: Defines the execution environment (e.g., node, es2022).
    • rules: Specific rule overrides and settings.
    • overrides: File-specific rule or environment adjustments (e.g., disabling certain TypeScript rules for .js or .cjs files).
    {
      "$schema": "./node_modules/oxlint/configuration_schema.json",
      "ignorePatterns": ["**/*.d.ts", ".claude/**"],
      "plugins": [
        "eslint",
        "import",
        "node",
        "oxc",
        "promise",
        "typescript",
        "unicorn"
      ],
      "env": {
        "builtin": true,
        "node": true,
        "es2022": true
      },
      "rules": { ... },
      "overrides": [ ... ]
    }
  5. Configure the Capacitor project via capacitor.config.ts

    main

    The capacitor.config.ts file defines the core configuration for a Capacitor application. In this project's demo, it configures the application ID, name, logging behavior, server scheme, and plugin-specific settings for Keyboard and SplashScreen.

    import type { CapacitorConfig } from '@capacitor/cli'
    import { KeyboardResize } from '@capacitor/keyboard'
    
    const config: CapacitorConfig = {
      appId: '',
      appName: '',
      loggingBehavior: 'debug',
      server: {
        androidScheme: 'http',
      },
      webDir: 'dist',
      plugins: {
        Keyboard: {
          resize: KeyboardResize.None,
        },
        SplashScreen: {
          launchAutoHide: false,
        },
      },
    }
    
    export default config
  6. Configure the Ionic project for the demo

    main

    The ionic.config.json file in the demo-shared directory defines the project identity and integration settings for the demonstration application. It specifies that the project uses a custom type and integrates with Capacitor, using pnpm as the npm client.

    {
      "name": "capacitor-secure-storage-demo",
      "integrations": {
        "capacitor": {}
      },
      "type": "custom",
      "npmClient": "pnpm"
    }
  7. Configure the Capacitor app identity and web directory

    main

    In the capacitor.config.ts file, you can define the application's unique identifier, name, and the directory containing the web assets. This configuration is used by Capacitor to identify the app on native platforms and locate the web build.

    Key properties:

    • appId: The unique bundle identifier for the application (e.g., com.aparajita.capacitor.securestoragedemo).
    • appName: The display name of the application.
    • webDir: The path to the directory containing the compiled web application assets.
    import baseConfig from 'demo-shared/capacitor.config'
    
    const config = {
      ...baseConfig,
      appId: 'com.aparajita.capacitor.securestoragedemo',
      appName: 'Storage',
      webDir: '../demo-shared/dist',
    }
    
    export default config
  8. Configure the Capacitor app for the demo project

    main

    The capacitor.config.ts file for the demo-spm package extends a base configuration from demo-shared/capacitor.config. It defines the specific application identity and web directory for the demo app.

    Key configuration properties:

    • appId: The unique identifier for the application (com.aparajita.capacitor.securestoragedemo).
    • appName: The display name of the application (Storage).
    • webDir: The path to the compiled web assets (../demo-shared/dist).
    import baseConfig from 'demo-shared/capacitor.config'
    
    const config = {
      ...baseConfig,
      appId: 'com.aparajita.capacitor.securestoragedemo',
      appName: 'Storage',
      webDir: '../demo-shared/dist',
    }
    
    export default config
  9. List all keys with keys()

    main

    The keys() method returns an array of all keys currently in storage that match the active prefix. The returned strings have the prefix stripped away.

    iOS Sync Override: If you pass sync: true to keys(), it temporarily overrides the global setSynchronize() setting. If synchronization is enabled, the method returns keys from both the iCloud and local keychains.

    const allKeys = await SecureStoragePlugin.keys();
    // To include iCloud keys on iOS:
    const allKeysWithSync = await SecureStoragePlugin.keys(true);
  10. Remove items with remove() and clear()

    main

    Use remove(key, sync?) to delete a specific item. It returns true if the item existed and false otherwise. Use clear(sync?) to remove all items that match the current key prefix.

    On iOS, you can pass a sync boolean to either method to temporarily override the iCloud synchronization setting.

    // Remove a specific key
    const existed = await SecureStoragePlugin.remove('session_token');
    
    // Clear all prefixed keys
    await SecureStoragePlugin.clear();