realm / realm-swift

Realm is a mobile database: a replacement for Core Data & SQLite
https://realm.io
Apache License 2.0
16.27k stars 2.14k forks source link

Invalid id token: ‘aud’ must be a string containing the client_id : google OAuth2.0 Client Id mismatch when signing in with android and apple platform #8111

Closed deepanshubalyan01 closed 1 year ago

deepanshubalyan01 commented 1 year ago

How frequently does the bug occur?

Description

So I am using google auth in my android and ios application. Now the application I created on atlas-app services allows only one client Id. But for android authentication to work, I need to add the web Client id in the google auth setting and for it to work on ios I need to add Ios client Id. otherwise one of them gives this aud error.

Stacktrace & log output

When I add ios Client Id android gives this error, signin on ios works.

AUTH_ERROR(realm::app::ServiceError:47): invalid id token: 'aud' must be a string containing the client_id
2023-01-25 03:06:22.969 21705-21705 System.err              com.friends.pets W      at io.realm.internal.network.NetworkRequest.onError(NetworkRequest.java:68)
2023-01-25 03:06:22.969 21705-21705 System.err              com.friends.pets W      at io.realm.internal.objectstore.OsJavaNetworkTransport.nativeHandleResponse(Native Method)
2023-01-25 03:06:22.969 21705-21705 System.err              com.friends.pets W      at io.realm.internal.objectstore.OsJavaNetworkTransport.handleResponse(OsJavaNetworkTransport.java:98)
2023-01-25 03:06:22.969 21705-21705 System.err              com.friends.pets                W   at io.realm.internal.network.OkHttpNetworkTransport$1.run(OkHttpNetworkTransport.java:102)
2023-01-25 03:06:22.970 21705-21705 System.err              com.sciforearth.pets                W   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
2023-01-25 03:06:22.970 21705-21705 System.err              com.friends.pets                W   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
2023-01-25 03:06:22.970 21705-21705 System.err              com.friends.pets                W   at java.lang.Thread.run(Thread.java:1012)

and when I replace it with webClient Id signin on android works and gives this error on iOS:

Error Domain=io.realm.app Code=24 "invalid id token: 'aud' must be a string containing the client_id" UserInfo={Server Log URL=https://realm.mongodb.com/groups/63b6d0cee8d6c1420b7fbed7/apps/63b6d39ea9e76e8f428c7f93/logs?co_id=63d050da927603235424f1f9, NSLocalizedDescription=invalid id token: 'aud' must be a string containing the client_id, HTTP Status Code=401}

Can you reproduce the bug?

Reproduction Steps

here is the android code binding.googleSigninButton.setOnClickListener(view1 -> { Intent intent = gsc.getSignInIntent(); startActivityForResult(intent, GOOGLE_REQUEST_Code); binding.progressBar4.setVisibility(View.VISIBLE); });

    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestIdToken(getString(R.string.default_web_client_id))
            .requestEmail()
            .build();
    gsc = GoogleSignIn.getClient(this, gso);
    oneTapClient = Identity.getSignInClient(this);
    signInRequest = BeginSignInRequest.builder()
            .setGoogleIdTokenRequestOptions(BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    // Your server's client ID, not your Android client ID.
                    .setServerClientId(getString(R.string.default_web_client_id))
                    // Only show accounts previously used to sign in.
                    .setFilterByAuthorizedAccounts(true)
                    .build())
            .build();
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == GOOGLE_REQUEST_Code){
        Task<GoogleSignInAccount> acc = GoogleSignIn.getSignedInAccountFromIntent(data);
        if(acc.isSuccessful()) {
            HandleSignInTask(acc);
        }
    }
}
public void HandleSignInTask(Task<GoogleSignInAccount> task){
    String token = task.getResult().getIdToken();
    if(token != null){
        Credentials cred = Credentials.google(token, GoogleAuthType.ID_TOKEN);

            App app =((Initialize)getApplication()).app;
            app.loginAsync(cred, result -> {
                if(result.isSuccess()) {
                    Log.i("TAG", "onResult: -->" );
                    startActivity(new Intent(Login.this, MainActivity.class));
                    finish();
                }
                else {
                    result.getError().printStackTrace();
                    Log.i("TAG", "googleAuthErrorMongo:--> "+ result.getError().toString());
                }
        }).addOnFailureListener(e -> Log.i(TAG, "onFailure: " + e.getLocalizedMessage()));
    }
    else{
        binding.progressBar4.setVisibility(View.GONE);
        Snackbar.make(binding.getRoot(),"Something went wrong",Snackbar.LENGTH_SHORT).show();
    }
}

and here is the ios code:

GIDSignIn.sharedInstance.signIn(withPresenting: self) { [self] signInResult, error in guard error == nil else { return }

        let credential = GoogleAuthProvider.credential(withIDToken: (signInResult?.user.idToken?.tokenString)!,
                                                       accessToken: (signInResult?.user.accessToken.tokenString)!)
        Auth.auth().signIn(with: credential) { result, error in
            guard error == nil else{
                print("error while signing in firebase.... \(error)")
                do{
                    try! Auth.auth().signOut()
                } catch _ {}
                return
            }

            signInResult?.user.refreshTokensIfNeeded { user, error in
                    guard error == nil else { return }
                    guard let user = user else { return }
                    let idToken = user.idToken
                let cred = Credentials.googleId(token: idToken?.tokenString ?? "nil")
                self.app.login(credentials: cred) { result in
                    do {
                        try  print("ios google auth successfull userId.. \(result.get().id)")

                        DispatchQueue.main.async {

                            let sb = UIStoryboard(name: "Main", bundle: nil)
                            let nextViewController = sb.instantiateViewController(withIdentifier: "MainViewController") as! ViewController
                            self.dismiss(animated: false)
                            self.present(nextViewController, animated: true)
                        }

                    } catch let error {print("error while signin in to realm--> \(error)")}
                }
                }
        }
    }

}

Version

master

What Atlas Services are you using?

Atlas App Services: Functions or GraphQL or DataAPI etc

Are you using encryption?

No

Platform OS and version(s)

every

Build environment

Xcode version: ...14.2 (14C18) Dependency manager and version: ...

leemaguire commented 1 year ago

Hi @deepanshubalyan01 This is noted in the docs: https://www.mongodb.com/docs/atlas/app-services/authentication/google/ could you follow the steps listed here and see if that helps?

deepanshubalyan01 commented 1 year ago

the way it works is that I need to pass my ios ClientId and reversed client ID in the info.plist file only then the google auth opens else it crashes. But for android To work in the google auth setting(realm app) I have put Web client id and secret. and iOS just won't work with that client Id as it needs iosClient Id configured. so No. you have to come up with multiple client id or something.

dianaafanador3 commented 1 year ago

@deepanshubalyan01 there is a similar issue where this was discussed https://github.com/realm/realm-swift/issues/7506 which could help to make this work on both Android and iOS.

leemaguire commented 1 year ago

Hi @deepanshubalyan01 did you try any of the mentioned workarounds?

dianaafanador3 commented 1 year ago

Closing this as there is no response from the user