Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: non-zero custom status code considered fatal #1087

Closed
Navil opened this issue Jan 3, 2023 · 12 comments · Fixed by #1378
Closed

[Bug]: non-zero custom status code considered fatal #1087

Navil opened this issue Jan 3, 2023 · 12 comments · Fixed by #1378
Assignees

Comments

@Navil
Copy link

Navil commented Jan 3, 2023

What happened?

Our sentry reports a few fatal errors, when signing in:

AppException: non-zero custom status code considered fatal, link to server logs: null

We do not get this on our devices, it is visible to us in sentry. We could reproduce it on a GT-I9505 with Android Version 5.0.1. So maybe it is related to old versions of Android?

The error message does not help much to find the issue.

Repro steps

Sign in with Firebase (Phone Auth)
Sign in Realm (JWT)
Error

Version

Channel stable, 3.3.10, on Microsoft Windows [Version 10.0.19045.2364], locale de-AT

What Realm SDK flavor are you using?

MongoDB Atlas (i.e. Sync, auth, functions)

What type of application is this?

Flutter Application

Client OS and version

Android 5.0.1

Code snippets

debugPrint('Verifying phone code'); 
try {
      // Sign the user in (or link) with the credential
      firebase.UserCredential firebaseCredential =
          await firebase.FirebaseAuth.instance.signInWithCredential(credential);
       debugPrint('Signed in with Firebase');

      String jwt = await firebaseCredential.user!.getIdToken();
      user = await app.logIn(Credentials.jwt(jwt));
      _verificationId = null;
      notifyListeners();
      debugPrint('Signed in with Realm');
    } catch (error, stackTrace) {
      Sentry.captureException(error, stackTrace: stackTrace);
    }

Stacktrace of the exception/crash you're getting

AppException: AppException: non-zero custom status code considered fatal, link to server logs: null

Relevant log output

Verifying phone code
Signed in with Firebase
AppException: AppException: non-zero custom status code considered fatal, link to server logs: null
@nielsenko
Copy link
Contributor

How does the jwt look?

@Navil
Copy link
Author

Navil commented Jan 3, 2023

I do not have those tokens in my logs so I have no token from the crashing device. I could however try to reproduce it on the development environment or provide a working jwt if this helps.

@nielsenko
Copy link
Contributor

It might help. Remember to strip the signature part before posting the JWTs here.

I'm also interested in how you have setup Audience (aud claim) and Verification Method on the backend (https://www.mongodb.com/docs/atlas/app-services/authentication/custom-jwt/)

@Navil
Copy link
Author

Navil commented Jan 3, 2023

So, I can reproduce the issue with an emulator running on 5.0.1.

Here is the content of the jwt:

{
  "alg": "RS256",
  "kid": "ce9b880f8182dda557f7c70e20e4e370e3d12747",
  "typ": "JWT"
}
{
  "iss": "https://securetoken.google.com/myapp-dev",
  "aud": "myapp-dev",
  "auth_time": 1672772941,
  "user_id": "gmeTrLyWFOYGFZxKq1yeLZG8xZt1",
  "sub": "gmeTrLyWFOYGFZxKq1yeLZG8xZt1",
  "iat": 1672772941,
  "exp": 1672776541,
  "phone_number": "+16505550100",
  "firebase": {
    "identities": {
      "phone": [
        "+16505550100"
      ]
    },
    "sign_in_provider": "phone"
  }
}

image

For safety reasons I changed the app name, as it is already on production. As said, in works on every modern device we have, and I can reproduce it on a Pixel 5 emulator with API level 22.

Is this information sufficient?

@nielsenko
Copy link
Contributor

Thanks for the detailed information. This is enough for now. I will get back when I know more

@nielsenko
Copy link
Contributor

nielsenko commented Jan 3, 2023

This is more sinister than as such. It has to do with how older versions of android handles TLS certificates. The certificates from https://realm.mongodb.com are signed by lets-encrypt, which is dependent on the root certificate ISRG Root X1.

The list of platforms that support the ISRG Root X1 root certificate can be seen here: https://letsencrypt.org/docs/certificate-compatibility/. In particular you need Android >= 7.1.1

There is a dirty work-around to make these certificates work with old Android apps (>= 2.3.6), that you can read about here: https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021/. Unfortunately I don't think this will work with BoringSSL that is used by Dart / Flutter.

Basically you need configure the http client used to trust the root certificate. It is getting a bit late here, so this is just from the top of my head.

  final context = SecurityContext();
  context.setTrustedCertificatesBytes(isrgRootX1Cert);
  final client = HttpClient(context: context);
  final appConfig = AppConfiguration(appId, httpClient: client);
  ...

Will check up on it tomorrow.

@nielsenko nielsenko self-assigned this Jan 4, 2023
@Navil
Copy link
Author

Navil commented Jan 6, 2023

Thank your for this throughout information. Strange that no one ran this on an Android verison older than 7.1.1 before apparently.
Is this something you will fix on the end of realm, or shall I build the workaround in my app?

@nielsenko
Copy link
Contributor

nielsenko commented Jan 6, 2023

@Navil Yes, I will add the root certificate in the default http client we create, so you don't have to yourself. But the next release is held up by some regressions in realm-core 13, so you might want to do the fix on your side until then.

@nielsenko
Copy link
Contributor

final _pinnedClient = () {
  const isrgRootX1CertPEM = // The root certificate used by lets encrypt
      '''
subject=CN=ISRG Root X1,O=Internet Security Research Group,C=US
issuer=CN=DST Root CA X3,O=Digital Signature Trust Co.
-----BEGIN CERTIFICATE-----
MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC
ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL
wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D
LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK
4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5
bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y
sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ
Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4
FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc
SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql
PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND
TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1
c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx
+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB
ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu
b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E
U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu
MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC
5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW
9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG
WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O
he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC
Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5
-----END CERTIFICATE-----''';

  final context = SecurityContext();
  context.setTrustedCertificatesBytes(const AsciiEncoder().convert(isrgRootX1CertPEM));
  return HttpClient(context: context);
}();
...
final context = SecurityContext();
context.setTrustedCertificatesBytes(isrgRootX1Cert);
final client = HttpClient(context: context);
final appConfig = AppConfiguration(appId, httpClient: client);
...

@Navil
Copy link
Author

Navil commented Jan 6, 2023

Thank you very much for the fast help.
I just tested and can confirm, that it works with that change.

@nielsenko
Copy link
Contributor

@desistefanova Pointed out that this is actually documented here: https://www.mongodb.com/docs/realm/sdk/flutter/app-services/connect-to-app/#connect-using-android-7-or-older. I wasn't aware myself.

There is some discussions wrt #1088, if it should land or not. Since there exists a workaround, so you may have to keep doing this after the next release as well.

@blagoev
Copy link
Contributor

blagoev commented Feb 17, 2023

closing this since there is a workaround and we have #1088 which is in discussion.

@blagoev blagoev closed this as completed Feb 17, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 16, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
3 participants