Access Keychain values stored by ExpoSecureStore from a Flutter app [iOS]

∥☆過路亽.° 提交于 2020-06-16 08:55:31

问题


I have a ReactNative app (only published for iOS) which uses ExpoSecureStore to put and read values from iOS Keychain.

I am transitioning to Flutter and I need to keep the users logged in, i.e. to get their auth tokens from the previously installed RN version of the app.

So, here is what I do:

  1. I install the RN app from the App store,
  2. Log in (the token is saved with ExpoSecureStore),
  3. Install my Flutter app
  4. Try to access the Keychain - nothing found!
  5. Reinstall the RN app from the App store,
  6. User is logged in when I open the app!

So, my Flutter installation doesn't delete the tokens, but it can't access them.

Update 18.3.2020.

Here is what ReactNative's latest build looks like on AppstoreConnect:

Here is the same info for our Flutter build:

I tried setting the keychain group in Flutter's XCode project to all kinds of values: TEAM_ID.*, TEAM_ID., TEAM_ID, *, TEAM_ID.com.my_real_app_id etc.. but nothing helped

Is there something I am missing?

============== original question continues ================

I am using the FlutterSecureStoragePlugin (link to the .m file) to access the Keychain values.

Here is the link to the EXSecureStore.m file - EXSecureStore.m on GitHub.

  • The Flutter app has the same bundle ID, so that should not be the problem.

  • I've changed its source code so that I use the same keychain service (kSecAttrService), which defaults to "app".

  • Also, I've copied and adapted the code for reading the Keychain values from ExpoSecureStore.m to FlutterSecureStoragePlugin.m but still no luck..

Could there be any difference in the way RN and Flutter libraries pass strings down to native iOS? I guess there must be something going on with the Keychain access that I don't know, so any help is very welcome!

Thank You for reading!


回答1:


I have finally solved the expo secure store access issue!

TL;DR

The most important things are that you set up the same keychain access group, same kSecAttrService (keychain service) and, of course, the key of the item you want to access.

Here is what are the preconditions:

  • you must set the keychain access group to the same value as in the react native's build, which is TEAM_ID.*. This can be achieved by one of the two options:

    • setting the Keychain Sharing capability to *, as shown on the screenshot below, or
    • open the entitlements file (project_dir/ios/Runner/Runner.entitlements) and add the item $(AppIdentifierPrefix)* or item TEAM_ID.* to the keychain access groups array. Notice that if You are adding the first item, there is no . before the *, since AppIdentifierPrefix is converted into TEAM_ID. before the build. Link to the apple docs on the keychain-access-groups entitlement.
  • If the app you are developing has the same bundle ID (i.e. it's an update to the existing ReactNatvie/Expo app), you should not have any problems with accessing the keychain items (when you do all the other preconditions, of course). Also, if the app has the same keychain sharing group, in this case TEAM_ID.*, it should also be able to access the keychain items. Notice that having the keychain access group set to TEAM_ID.* means that only apps developed by same developer (team) can access the RN app's keychain items.

  • you must change the Flutter's library (or the native iOS) source code so that it uses the same keychain service (kSecAttrService) as Expo. For Expo, if You don't pass the keychainService param in the SecureStore options, the kSecAttrService attribute of the item you want to write (or get) will be app. You can see that yourself here, on the expo native library's source code on GitHub (link). I made a fork of the flutter library and I will make a pull request sometime in the future, but you can just change plugin's default keychain service to app as well. It currently defaults to flutter_secure_storage_service, as seen in the plugin's source code on GitHub (link).

  • the trickiest part - because of which I doubted in all of the above steps - is setting the correct key (kSecAttrAccount) for the keychain item I wanted to get. What helped me was to use the Flutter plugin's readAll method (link to the native source code of readAll on GitHub). It showed me that the keychain items were actually there, but that the keys were different than the ones ReactNative app was using. As I've found out by debugging (it's nowhere in the docs!!!), the expo username and expo project's name are added **before the string used for the key**! So, if in the ReactNative app you save a token with key accessToken, it will be saved to the Keychain as @expousername/project-name-accessToken! It's nowhere in the docs, and I don't know how it happens, because I've looked through the source code

In my question, I said that I've copied the Objective-C code from expo's library to Flutter's plugin, but that wasn't necessary.



来源:https://stackoverflow.com/questions/60703577/access-keychain-values-stored-by-exposecurestore-from-a-flutter-app-ios

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!