Skip to content

Conversation

@7576457
Copy link
Contributor

@7576457 7576457 commented Jan 13, 2026

Description

This PR adds a new extension implemented as a service that allows storing data securely on the device.

On iOS, it uses Keychain.
On Android, it uses encrypted shared preferences powered by Tink.

This extension is mainly intended for mobile platforms, where it provides fine-grained control over data storage, encryption, and other behavior.
At the same time, it can also be used on web, Windows, macOS, and Linux.

Overall, this extension can be seen as an alternative to SharedPreferences, but with more features and greater control over data handling.

Test Code

import flet as ft
import flet_secure_storage as fss


def main(page: ft.Page):
    page.vertical_alignment = ft.MainAxisAlignment.CENTER
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
    storage = fss.SecureStorage()

    key = ft.TextField(label="Key", value="example_key")
    value = ft.TextField(label="Value", value="secret_value")
    result = ft.Text(theme_style=ft.TextThemeStyle.TITLE_LARGE)

    async def set_value(e):
        await storage.set(key.value, value.value)
        result.value = "Value saved"
        page.update()

    async def get_value(e):
        result.value = await storage.get(key.value)
        page.update()

    async def remove_value(e):
        await storage.remove(key.value)
        result.value = "Value removed"
        page.update()

    async def clear_storage(e):
        await storage.clear()
        result.value = "Storage cleared"
        page.update()

    async def contains_key(e):
        exists = await storage.contains_key(key.value)
        result.value = f"Key exists: {exists}"
        page.update()

    async def get_availability(e):
        is_availability = await storage.get_availability()
        page.show_dialog(
            ft.SnackBar(
                content=ft.Text(
                    value=f"Protected data available: {is_availability}"
                    if is_availability
                    else "Protected data available: None"
                )
            )
        )
        page.update()

    page.add(
        ft.Column(
            alignment=ft.MainAxisAlignment.CENTER,
            horizontal_alignment=ft.CrossAxisAlignment.CENTER,
            spacing=10,
            controls=[
                result,
                key,
                value,
                ft.Row(
                    width=300,
                    wrap=True,
                    controls=[
                        ft.Button("Set", on_click=set_value),
                        ft.Button("Get", on_click=get_value),
                        ft.Button("Contains key", on_click=contains_key),
                        ft.Button("Remove", on_click=remove_value),
                        ft.Button("Clear", on_click=clear_storage),
                        ft.Button("Check Data Availability", on_click=get_availability),
                    ],
                ),
            ],
        ),
    )


ft.run(main)

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Checklist

  • I signed the CLA.
  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • New and existing tests pass locally with my changes
  • I have made corresponding changes to the documentation (if applicable)

Screenshots

web:
image

android

android_example.mp4

Additional details

Summary by Sourcery

Introduce a cross-platform secure storage extension and wire it into the Flet client and Python SDK, while extending patch operations to support both list- and map-based structures.

New Features:

  • Add a new flet-secure-storage Python package and Flutter plugin exposing a SecureStorage service control with platform-specific configuration and CRUD APIs.
  • Register the secure storage extension in the Flet Flutter client and list it among built-in extensions and SDK-managed extensions.

Enhancements:

  • Update control patch handling to support add, remove, and move operations on both lists and maps instead of lists only.

Build:

  • Include the flet-secure-storage package in the Python SDK workspace configuration and Flutter client dependencies.

Documentation:

  • Document the new flet-secure-storage extension in the built-in extensions guide.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've reviewed this pull request using the Sourcery rules engine

@7576457
Copy link
Contributor Author

7576457 commented Jan 13, 2026

@FeodorFitsner I used T | None instead of Optional[T] for type annotations (Python 3.10+).
Let me know if you’d prefer Optional for consistency.

@7576457
Copy link
Contributor Author

7576457 commented Jan 13, 2026

I tested this on Windows and Web, and I will test it on Linux and Android soon.
I don’t have access to iOS or macOS devices to test it there.
I would really appreciate it if someone could help test this on those platforms.

  • windows
  • web
  • android
  • linux

@FeodorFitsner
Copy link
Contributor

@FeodorFitsner I used T | None instead of Optional[T] for type annotations (Python 3.10+). Let me know if you’d prefer Optional for consistency.

We use Optional across the code-base, so yes it's more preferable. We will switch everything at once to T | None when morally ready :).

} else {
throw Exception("Add operation can be applied to lists or maps: $op");
}
if (shouldNotify) node.control.notify();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What did the changes in control.dart fix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7576457/flet-secure-storage#1

I was getting an exception from line 378 when calling the .readAll method, which returns a map. When I deleted something from storage, I got the same error. This means that at runtime I'm working with a map, while control.dart expects to work only with a list.

These changes make it possible to work with a map at runtime, which is what FlutterSecureStorage actually uses.

@FeodorFitsner
Copy link
Contributor

Every new service/control package requires these additional "parts":

@FeodorFitsner
Copy link
Contributor

I've dropped a few comments - hope it's OK :). Otherwise, solid work - great contribution!

@FeodorFitsner
Copy link
Contributor

FeodorFitsner commented Jan 13, 2026

Got this message in the console when running the example:

/Users/feodor/projects/flet-dev/flet/sdk/python/packages/flet-secure-storage/src/flet_secure_storage/options.py:291: SyntaxWarning: invalid escape sequence '\`'
  - May cause errors for keys containing `"`, `<`, `>`, `|`, `:`, `*`, `?`, `/`, `\`
image image

@FeodorFitsner
Copy link
Contributor

Got this while running on macOS and trying to set a key/value:

The application encountered an error: PlatformException(Unexpected security result code, Code: -34018, Message: A required entitlement isn't present., -34018, null)

Trying to add to entitlements gives me another error building macOS client app:

/Users/feodor/projects/flet-dev/flet/client/macos/Runner.xcodeproj: error: "Runner" has entitlements that require signing with a development certificate. Enable development signing in the Signing & Capabilities editor. (in target 'Runner' from project 'Runner')

😬

@FeodorFitsner
Copy link
Contributor

OK, I'm going to test on iOS. For macOS we will implement #2347.

- manage the secure storage subscription lifecycle via `_updateListeners()`
- refactored code and organized configuration files
- removed unused code (`createSecureStorage()`, `parseDateTime()`)
- replaced `T | None` type annotations with `Optional[]`
@7576457
Copy link
Contributor Author

7576457 commented Jan 14, 2026

Got this while running on macOS and trying to set a key/value:

The application encountered an error: PlatformException(Unexpected security result code, Code: -34018, Message: A required entitlement isn't present., -34018, null)

Trying to add to entitlements gives me another error building macOS client app:

/Users/feodor/projects/flet-dev/flet/client/macos/Runner.xcodeproj: error: "Runner" has entitlements that require signing with a development certificate. Enable development signing in the Signing & Capabilities editor. (in target 'Runner' from project 'Runner')

😬

I suspect this is related to the macOS environment setup:
juliansteenbakker/flutter_secure_storage#804

There’s also some related information here that might be helpful:
flutter/flutter#132997

- added Android biometric demo
- configured WebOptions for secure storage
- updated enums with more descriptive names
- added USE_BIOMETRIC and USE_FINGERPRINT permissions to AndroidManifest
@FeodorFitsner
Copy link
Contributor

Thank you for the update!

Now, as we have doc page for secure storage I'd add more about supported platforms (example) and, most importantly, configuration requirements. Like you added two permissions here - I think it's worth mentioning for Android that "in order to use this ... you have to add that" (here) into your pyproject.toml:

[tool.flet.android.permission]
"android.permission.USE_BIOMETRIC" = true
"android.permission.USE_FINGERPRINT" = true

We have a mechanism for that.

application element in manifest must be updated too. It's possible to configure in pyproject.toml but it's not documented 🥴.

[tool.flet.android.manifest_application]
"allowBackup" = "false"
"fullBackupContent" = "false"

There are also configuration requirements for Linux (libsecret-1-dev, libsecret-1-0), Windows, macOS and iOS that should be mentioned in Flet docs.

All in all - great job, thanks for bearing with me!

@7576457
Copy link
Contributor Author

7576457 commented Jan 15, 2026

I was just about to write to you to say thank you :)
I understand your points and will apply your suggestions.

I should mention that I haven’t been able to properly test this on Linux yet. I’m using WSL for that and ran into several issues. However, I did test it on Android and attached a video to the main post -- it works perfectly there!

- added secure_storage docs folder with usage and API reference
- removed old options file; moved classes to types.py
- fixed availability event: now fires on available instead of is_available_storage
- added documentation for SecureStorageEvent
Copy link
Contributor

@ndonkoHenri ndonkoHenri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution!

I haven't tested it yet, but looks great.

I added some comments. I hope they dont feel too much. Feel free to let know if one or more are not comprehensive enough, or if you won't have time to work on (in which case I could pickup sometime later).

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new flet-secure-storage extension that provides secure storage functionality across multiple platforms (iOS, Android, web, Windows, macOS, and Linux). On iOS it uses Keychain, and on Android it uses encrypted shared preferences powered by Tink.

Changes:

  • Added new flet-secure-storage Python package with cross-platform secure storage APIs
  • Integrated the extension into the Flet client and SDK dependencies
  • Enhanced control patch operations to support both lists and maps (previously only lists)

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
sdk/python/pyproject.toml Added flet-secure-storage to workspace dependencies and isort configuration
sdk/python/packages/flet/pyproject.toml Added flet-secure-storage to extensions list
sdk/python/packages/flet/mkdocs.yml Added SecureStorage to services documentation navigation
sdk/python/packages/flet/docs/services/securestorage.md Created documentation page for SecureStorage service
sdk/python/packages/flet/docs/extend/built-in-extensions.md Listed flet-secure-storage as a built-in extension
sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/pubspec.yaml Defined Flutter package dependencies and metadata
sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/utils/secure_storage.dart Implemented parsing utilities for platform-specific options
sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/secure_storage.dart Implemented core SecureStorageService with CRUD operations
sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/src/extension.dart Registered SecureStorage as a Flet service
sdk/python/packages/flet-secure-storage/src/flutter/flet_secure_storage/lib/flet_secure_storage.dart Exported extension for Flutter integration
sdk/python/packages/flet-secure-storage/src/flet_secure_storage/types.py Defined enums and event types for secure storage
sdk/python/packages/flet-secure-storage/src/flet_secure_storage/secure_storage.py Implemented Python SecureStorage service class with async methods
sdk/python/packages/flet-secure-storage/src/flet_secure_storage/options.py Defined platform-specific configuration classes
sdk/python/packages/flet-secure-storage/src/flet_secure_storage/init.py Exposed public API exports
sdk/python/packages/flet-secure-storage/pyproject.toml Configured Python package metadata
sdk/python/packages/flet-secure-storage/LICENSE Added Apache 2.0 license
sdk/python/examples/services/secure_storage/basic.py Provided example demonstrating SecureStorage usage
packages/flet/lib/src/models/control.dart Extended patch operations to support maps in addition to lists
client/pubspec.yaml Added flet_secure_storage dependency to Flet client
client/lib/main.dart Registered flet_secure_storage extension in client
client/android/app/src/main/AndroidManifest.xml Added biometric authentication permissions
.github/workflows/ci.yml Added libsecret dependencies for Linux builds

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- added parseAccessControlFlag and updated parsing to return List[AccessControlFlag]
- code and documentation refactoring
@7576457 7576457 requested a review from ndonkoHenri January 17, 2026 12:53
@7576457
Copy link
Contributor Author

7576457 commented Jan 17, 2026

The flutter_secure_storage documentation describes Secure Enclave support for macOS and iOS (see README: https://github.com/juliansteenbakker/flutter_secure_storage/blob/develop/README.md#macos--ios) using the useSecureEnclave parameter.

However, in the current version of flutter_secure_storage published on pub.dev, this parameter is not present. As a result, it is also unavailable in the flet-secure-storage extension.

For this reason, documentation related to Secure Enclave configuration for macOS/iOS was not added to the Flet documentation, as it does not reflect the current implementation.

Possible next steps:

  • wait for a new release of flutter_secure_storage on pub.dev that includes useSecureEnclave support and update the dependency;
  • or point the dependency directly to the GitHub repository (instead of pub.dev) and add useSecureEnclave support now.

@ndonkoHenri
Copy link
Contributor

wait for a new release of flutter_secure_storage on pub.dev that includes useSecureEnclave support and update the dependency;

That feature seems to be on their dev branch, so it will make sense we wait it lands on master in the future, then we could implement new feature in flet_secure_storage.

@7576457

This comment was marked as resolved.

@7576457 7576457 requested a review from ndonkoHenri January 17, 2026 21:11
Co-authored-by: TheEthicalBoy <98978078+ndonkoHenri@users.noreply.github.com>
@7576457
Copy link
Contributor Author

7576457 commented Jan 19, 2026

// --FAT_CLIENT_START--
// --RIVE_IMPORT_START--

How are these markers used, and how do I know if flet_secure_storage needs to be inside one of them?

@FeodorFitsner
Copy link
Contributor

// --FAT_CLIENT_START--
// --RIVE_IMPORT_START--

How are these markers used, and how do I know if flet_secure_storage needs to be inside one of them?

Flet CI builds "normal" and "light" clients for Linux (only), for all other platforms it builds "normal" only.
"Light" client does not include flet_video and flet_audio as they require additional dependencies installed on linux and thus cause confusion and "bad" initial experience.

I believe flet_secure_storage should be outside of "FAT" or "RIVE" markers, i.e. be included in both "normal" and "light" clients.

There is a merge conflict right now, so you better fix it.

@7576457
Copy link
Contributor Author

7576457 commented Jan 20, 2026

Sourcery reports a potential command injection, but I believe this is a false positive

@FeodorFitsner FeodorFitsner merged commit 0a9ba9b into flet-dev:main Jan 20, 2026
31 of 33 checks passed
@FeodorFitsner
Copy link
Contributor

td3447/flet-secure-storage#1

It's sad PyPI doesn't have namespaces like npm 🥹

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants