Expo: Reports of 'unknown' error code in Fingerprint API in standalone app

Created on 21 Sep 2017  ·  54Comments  ·  Source: expo/expo

Most helpful comment

Do we have an update on this issue? Can confirm it's still a problem. (expo version 30.0.0)

All 54 comments

I thought I managed to get around this issue but it happened again. Here's what I did:

After upgrading Expo to 21.0.0 I built another binary and deployed it to TestFlight.
Fingerprint was working once the update was downloaded onto any phones affected.
However when I hit Publish on XDE it broke the Fingerprint again.

I do remember updating XDE just before the first time Fingerprint broke when I published.

Not sure if XDE could be breaking it?

Hi @rshellborn ! I started to investigate this issue and cannot reproduce in any way thus far. Here is what I did:

1- Made a toy app with all 3 Fingerprint methods (hasHardwareAsync, isEnrolledAsync and authenticateAsync )
2- Tested in Expo client - Works
3-Built a standalone version via exp build:ios
4-Uploaded it to ItunesConnect and deployed it to my phone via TestFlight
5-Tested it, it worked
6- Republished the code via XDE
7-Tested again, no issues.

Are those pretty much the steps you are doing to get the error?

@charlesvinette Hi, unfortunately it just seems to happen randomly. I've seen it break on an iPhone when I haven't even published and right when I publish. So I can't give you the exact steps to replicate. Thanks for trying though.

Not a problem. What device are you testing it on? Do you have active users who are also reporting the error? Once it fails and return "unknown", is it stuck that way or would it sometimes work sometimes not? What about if you kill and re-open the application?

What device are you testing it on?
iPhone 6 but I have seen it break on iPhone 7+ and iPhone 7

Do you have active users who are also reporting the error?
I have a few active users who are reporting the error. But I think a lot may not report it even though it is broken.

Once it fails and return "unknown", is it stuck that way or would it sometimes work sometimes not?
The only way to fix it is to delete the app and download it again from the store or TestFlight (it breaks on the live app and the TestFlight app)

What about if you kill and re-open the application?
This does not fix it. Neither does turning off the passcode and turning it back on.

Got it, thanks for the additional info Rachel. I will keep playing with the toy app and see if I can get that case. I will get back to you if I find anything. Thank you!!

I have a deterministic reproduction:

Step 1: download a standalone Expo app from TestFlight
Step 2: download another standalone Expo app from TestFlight (for us, this is the beta bundle)
Step 3: the "oldest" app will no be able to trigger TouchID

You can also reverse this by deleting both and reversing the download order.

Judging by:

https://github.com/expo/expo/blob/56bf64f0ed510c0d907ff9729c603d719798132d/ios/Exponent/Versioned/Core/Api/EXFingerprint.m

and

https://developer.apple.com/documentation/localauthentication/laerror.code

It seems that

LAErrorNotInteractive

could be thrown by iOS and not be caught properly by Expo/Standalone apps. I don't actually know what notInteractive could mean, given Apple provides no further explanation and that I am literally looking at my app covering the entire screen - pretty interactively...

I suppose a default response would be to actually implement the pin code view (it would be nice if Expo could expose a default component to handle this!) because this could technically be categorised with all the other totally valid reasons for needing a PIN code screen (i.e. no biometrics enrolled).

Hey David, thanks for getting back to us. I will take some time soon to give this another look. Thanks for the detailed information!

No worries, I can confirm this still exists on SDK 25. Is it related to persistent iCloud containers? We have this weird thing where if you authenticate and put your token in one app (the beta app) it will magically switch users in the prod app (i.e. the same Secure Store token is used in all our teams' apps, even if they have different bundle ids)

I feel like this is related to - or could be solved by - ad hoc distribution profiles, are these on the horizon?

I'm having the same issue.

I have since found out the source of my error @charlesvinette - we were deploying a master and beta copy of our app with different bundle IDs, but inexplicably with the same Expo app slug.

This was overwriting the certificates on Expo servers each time we did a build for each release track, and confusing iOS about which Secure Store/Touch ID container to use.

We have since switched to using two app slugs and everything just works. 😂😭

Haha @davidthornton I am glad to hear you managed to fix your issue. @ericvan76 did you manage to fix it on your side?

I had the same workflow before release channels as @davidthornton. I think this issue can be closed now. Thanks for all the help 😄 .

Closing - let us know if you run into more trouble. :)

Can someone from Expo clarify whether certs are keyed by app slug and not the respective store app bundle IDs? 😀

@terribleben I just had this issue appear again... It may be related to deployments. I.e. we deployed a new JS bundle and touch ID "stops"...

@davidthornton
I just checked and i guess there is a bug on our side. exp command which you use to schedule app build tries to find certs keyed by both app slug and bundle id, but unfortunately our service which builds IPA files doesn't use app bundle id as a filter when it tries to find credentials to sign the app. Therefore I think it's possible that you generated two different sets of certs for master/beta versions of your app and they end up signed by the same cert. Let me know if what i wrote makes sense.
I'll take care of this issue and let you know when i fix it :)

😍😍😍 awesome! I literally said “I bet there is an interesting story behind the certs” in the office yesterday!

Our build server is down today, so we couldn’t deploy to “confirm” deployment breaks it. But if your diagnosis is correct - would it make sense that reinstalling the app would fix it?

@davidthornton
I'm not sure what you mean by reinstalling the app, but i'm pretty sure that publishing/building it under different slug would fix the problem.

Hmm it may not be related then - where Touch ID stops working (because a device has two apps) you can “fix” Touch ID by deleting the app and re-installing it from TestFlight... :/

@dsokal did you update Expo build server code? :)

@davidthornton
Yes, this issue should be fixed now. However you have to upgrade exp to the latest version (53.0.0).

@dsokal I believe this is still an issue. We have a beta app and production app and touch ID stops working when you install one and then the other like mentioned above. (We are using exp 56)

@jkbailey could you please provide more details and maybe create another issue? Do you have two different bundle identifiers for beta/production apps? Or do you rather use release channels?

@dsokal Thanks for your response!
Yes, we have 2 different bundle identifiers for beta/production. Both apps are published with unique release channels and unique slugs in the app.json. However, something must still be shared because once one of them is installed or updated, Touch/Face ID stops working in the other, and the fingerprint api returns the unknown error

Ok, I’m all out of good ideas so I’m going to start taking pot shots:

  1. iCloud containers somehow sharing iCloud Keychain state
  2. App Groups somehow being created for the same expo user
  3. The NSA is intercepting and jail breaking the app sandboxes, but only for expo users

@jkbailey @davidthornton
Ok guys, thanks for reporting. I'm looking into this issue now.

edit:
I've managed to reproduce the issue - i've built two apps using Touch ID and it only works on the lastly installed one.

Ok, so thanks to @sjchmiela, we found a bug which is causing the issue. It'll be fixed with the next deploy of our apps builders. The deploy will most probably happen later today. I'll write here when it's done.

@jkbailey @davidthornton
We just deployed a fix to our iOS builders. Could you please rebuild your apps, upload to TestFlight and confirm that it resolved the problem for you? Thanks!

@dsokal We just pushed both our beta and production builds up through expo and into Testflight and the issue is still present. Do we need to clear all our credentials and start fresh?

I just tried it with a separate application using version 2.7.6 and the problem continues.

@jkbailey no, you shouldn't have to clear your credentials. It means it's still broken :( This issue is the worst, sorry guys. We'll continue investigating it.

@dsokal I am experiencing this issue. I pushed 2 different bundle identifiers. Is the issue still under investigation? Thanks

@jeremyhicks
Yes, it's still under investigation, we know what is the root cause of this (https://stackoverflow.com/questions/38854052/touchid-error-code-1004-nslocalizeddescription-user-interaction-is-required/45770285#45770285 for the reference). All Expo standalone apps have currently the same "Product Name" which is causing the problem. Unfortunately we haven't had time to fix it yet, sorry again.

@dsokal thanks for the followup, it helps us to better understand the issue. One thing we're not to clear on, does this occur only within one Apple Team's products or every Expo standalone app, for example if you and I both published a standalone with TouchID would only one of them work on the user's device?

@jeremyhicks Sadly, I believe it's a problem with all Expo apps, no matter what the Apple id is.

Do we have an update on this issue? Can confirm it's still a problem. (expo version 30.0.0)

+1

I tried implementing fingerprint local authentication with SDK 32 and ran into the 'unknown' error issue as well and had to back all the functionality back out. Is there any advice on how to work around the issue?

I'm also having this issue on my device as well. I am able to use this snack to reproduce the error too.

https://snack.expo.io/HJV9lES_E

For me the result is

{message:"Fingerprint hardware not available.",error:"not_available",success:false}

I'm able to use other apps on my phone and unlock my phone with my fingerprint so there isn't anything wrong with the hardware. I've rebooted the device. I've also tried the same code on an Android emulator. The emulator does work fine.

I should also note that this is happening on a Managed workflow app both the local one and the one in the app store.

Been struggling with this problem all week until I discovered that I was missing the USE_FINGERPRINT permission in config.android.permission of app.json. I'm not sure why this permission isn't documented along with the examples for LocalAuthentication, but this fixed the issue for me.

Been struggling with this problem all week until I discovered that I was missing the USE_FINGERPRINT permission in config.android.permission of app.json. I'm not sure why this permission isn't documented along with the examples for LocalAuthentication, but this fixed the issue for me.

I have that in my app.json, but I still get an error on the Android side with, "Fingerprint hardware not available". The issue isn't my phones fingerprint hardware because I have many apps I use with my fingerprint.

can someone give more information on how to reproduce this specifically? the above snack doesn't reproduce it for me. could you explain your local setup a bit? do you have an adhoc build and an app store build of the client on your phone? do you have multiple versions of your standalone app on your phone? (eg: via testflight and via app store). thanks!

The fix for this issue should be deployed soon. I'll let you guys know what you should do next once it's done.

This issues should be fixed now. Anyone who is experiencing the problem should rebuild his apps with expo build:ios and upload the new .ipa files to Testflight. Starting from now, each Expo iOS standalone app has its own CFBundleExecutable which is set to a PascalCased bundle identifier (e.g. com.swmansion.expo.app.fingerprint -> ComSwmansionExpoAppFingerprint). However, you can always specify your own CFBundleExecutable in app.json as the value of expo.ios.infoPlist.CFBundleExecutable.

LocalAuthentication.authenticateAsync() is working on IOS but on Android still getting the same issue, please advise. Thanks.

@pagarfloyd could you please provide some more details? How can one reproduce that issue?

Environment

System:
OS: macOS 10.14.5
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 11.0.0 - /usr/local/bin/node
npm: 6.10.1 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
IDEs:
Android Studio: 3.3 AI-182.5107.16.33.5314842
Xcode: 10.2.1/10E1001 - /usr/bin/xcodebuild
npmPackages:
@types/react: ^16.8.19 => 16.8.23
@types/react-native: ^0.57.60 => 0.57.65
expo: ^33.0.0 => 33.0.7
react: 16.8.3 => 16.8.3
react-native: https://github.com/expo/react-native/archive/sdk-33.0.0.tar.gz => 0.59.8
npmGlobalPackages:
expo-cli: 2.21.2

Steps to Reproduce

expo init test-app
expo install expo-local-authentication
copy below to App.tsx
expo start

import React, { Component } from "react";
import { View } from "react-native";
import * as LocalAuthentication from "expo-local-authentication";

export default class App extends Component {
  async componentDidMount(): Promise<void> {
    const hasHardwareAsync: boolean = await LocalAuthentication.hasHardwareAsync();
    const supportedAuthenticationTypesAsync: number[] = await LocalAuthentication.supportedAuthenticationTypesAsync();
    const isEnrolledAsync: boolean = hasHardwareAsync ? await LocalAuthentication.isEnrolledAsync() : false;
    if (hasHardwareAsync && isEnrolledAsync && supportedAuthenticationTypesAsync.indexOf(1) !== -1) {
      const authenticateAsync = await LocalAuthentication.authenticateAsync();
      console.log(authenticateAsync);
    }
  }

  render(): JSX.Element {
    return <View />;
  }
}


It's working on IOS, but when I try on Android the result of authenticateAsync is below, it also did not wait for user to authenticate the fingerprint it just return the object below. Thanks

{error: "unknown"
message: ""
success: false}

@pagarfloyd

The problem you're experiencing is not related to this issue.
I changed your code a little bit and it works fine. I think you shouldn't call LocalAuthentication.authenticateAsync in the componentDidMount function.

The following code works fine:

import React, { Component } from "react";
import { View, Text, Button } from "react-native";
import * as LocalAuthentication from "expo-local-authentication";

export default class App extends Component {
  async authenticate(): Promise<void> {
    const hasHardwareAsync: boolean = await LocalAuthentication.hasHardwareAsync();
    const supportedAuthenticationTypesAsync: number[] = await LocalAuthentication.supportedAuthenticationTypesAsync();
    const isEnrolledAsync: boolean = hasHardwareAsync ? await LocalAuthentication.isEnrolledAsync() : false;
    console.log(hasHardwareAsync);
    console.log(supportedAuthenticationTypesAsync);
    console.log(isEnrolledAsync);
    if (hasHardwareAsync && isEnrolledAsync && supportedAuthenticationTypesAsync.indexOf(1) !== -1) {
      const authenticateAsync = await LocalAuthentication.authenticateAsync({
      promptMessage: 'This message only shows up on iOS',
      fallbackLabel: '',
    });
    }
  }

  render(): JSX.Element {
    return (
      <View style={{marginTop: 100}}>
       <Button title="Authenticate Me" onPress={this.authenticate} />
      </View>
    );
  }
}

I still have the same issue, I copy paste your edited code and try to log const authenticateAsync, after I press the button it log { "error": "unknown", "message": "", "success": false, }. Im using a MI MAX 3 with Android version 9.

@pagarfloyd could you please create a new github issue?

@dsokal please check #4976. Thanks for your help.

Was this page helpful?
0 / 5 - 0 ratings