ConnectyCube / connectycube-flutter-samples

Code samples for Flutter, based on ConnectyCube platform
https://developers.connectycube.com/flutter/
Apache License 2.0
85 stars 91 forks source link

Login with Phone authenticated using Firebase #35

Closed asongkai closed 3 years ago

asongkai commented 4 years ago

Hi,

I able to login with Firebase as per documentation but not able to login to chat.

String accessToken = await firebaseUser.getIdToken(true);
        signInUsingFirebase(PROJECT_ID, accessToken)
            .then((cubeUser) {
          print(cubeUser.toJson());
        })
            .catchError((error){});

image

Code:

CubeUser cubeUser = CubeUser(
    id: G.loggedInUser.id,
    login: G.loggedInUser.phone,
    password: DEFAULT_PASS,
    email: G.loggedInUser.email,
    fullName: G.loggedInUser.name,
    phone: G.loggedInUser.phone);

print(cubeUser.toJson());

if (CubeSessionManager.instance.isActiveSessionValid()) {
  _loginToCubeChat(context, cubeUser);
} else {
  createSession(cubeUser).then((cubeSession) {
    print("session:  ${cubeSession.toJson()}");
    _loginToCubeChat(context, cubeUser);
  }).catchError(_processLoginError);
}
void _loginToCubeChat(BuildContext context, CubeUser user) {
  CubeChatConnection.instance.login(user).then((cubeUser) {
    setState(() {});
  }).catchError(_processLoginError);
}

void _processLoginError(exception) {
  log("Login error $exception", TAG);
  showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text("Login Error"),
          content: Text("Something went wrong during login to ConnectyCube"),
          actions: <Widget>[
            FlatButton(
              child: Text("OK"),
              onPressed: () => Navigator.of(context).pop(),
            )
          ],
        );
      });
}

Error Log:

I/flutter (27584): ChatList Visibility code is 0.0
I/flutter (27584): {full_name: Hmong THAO, email: null, login: 8562096729763, phone: 8562096729763, website: null, last_request_at: null, external_user_id: null, facebook_id: null, twitter_id: null, password: xxasBUM3gQs36bhj, oldPassword: null, custom_data: null, avatar: null, tag_list: null, id: 100, created_at: null, updated_at: null}
I/flutter (27584): State: XmppConnectionState.SocketOpening
I/flutter (27584): CB-SDK: CubeChatConnection: Chat connection SocketOpening
I/chatty  (27584): uid=10323(com.oudomsup.ocwa) 1.ui identical 5 lines
I/flutter (27584): CB-SDK: CubeChatConnection: Chat connection SocketOpening
I/flutter (27584): State: XmppConnectionState.SocketOpened
I/flutter (27584): sending: <?xml version='1.0'?>
I/flutter (27584): <stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams'
I/flutter (27584): to='chat.connectycube.com'
I/flutter (27584): xml:lang='en'
I/flutter (27584): >
I/flutter (27584): unread MSG count is 0
I/flutter (27584): ChatList Visibility code is 1.0
E/flutter (27584): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: [cloud_firestore/not-found] Some requested document was not found.
E/flutter (27584): #0      MethodChannelDocumentReference.update (package:cloud_firestore_platform_interface/src/method_channel/method_channel_document_reference.dart:59:7)
E/flutter (27584): <asynchronous suspension>
E/flutter (27584): #1      DocumentReference.update (package:cloud_firestore/src/document_reference.dart:98:22)
E/flutter (27584): #2      FirebaseController.setUserState (package:OCWA/Controllers/firebaseController.dart:240:62)
E/flutter (27584): #3      _ChatState.initState.<anonymous closure> (package:OCWA/pages/chat/chat.dart:136:35)
E/flutter (27584): <asynchronous suspension>
E/flutter (27584): #4      _ChatState.initState.<anonymous closure> (package:OCWA/pages/chat/chat.dart)
E/flutter (27584): #5      SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
E/flutter (27584): #6      SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1063:9)
E/flutter (27584): #7      SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:971:5)
E/flutter (27584): #8      _rootRun (dart:async/zone.dart:1190:13)
E/flutter (27584): #9      _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (27584): #10     _CustomZone.runGuarded (dart:async/zone.dart:997:7)
E/flutter (27584): #11     _invoke (dart:ui/hooks.dart:251:10)
E/flutter (27584): #12     _drawFrame (dart:ui/hooks.dart:209:3)
E/flutter (27584):
I/flutter (27584): response: <?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='chat.connectycube.com' id='33bdd27d-e081-460d-8d37-fa8ff4162814' version='1.0' xml:lang='en'>
I/flutter (27584): !!!!handle response <xmpp_stone><?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='chat.connectycube.com' id='33bdd27d-e081-460d-8d37-fa8ff4162814' version='1.0' xml:lang='en'></stream:stream></xmpp_stone>
I/flutter (27584): !!!!!!! PARSED<xmpp_stone><?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='chat.connectycube.com' id='33bdd27d-e081-460d-8d37-fa8ff4162814' version='1.0' xml:lang='en'></stream:stream></xmpp_stone>
I/flutter (27584): processInitialStream
I/flutter (27584): unread MSG count is 0
I/flutter (27584): response: <stream:features><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features>
I/flutter (27584): !!!!handle response <xmpp_stone><stream:features><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features></xmpp_stone>
I/flutter (27584): !!!!!!! PARSED<xmpp_stone><stream:features><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features></xmpp_stone>
I/flutter (27584): Negotating features
I/flutter (27584): ELEMENT true
I/flutter (27584): negotiating starttls
I/flutter (27584): sending: <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
I/flutter (27584): ACTIVE FEATURE: <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
I/flutter (27584): response: <proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
I/flutter (27584): !!!!handle response <xmpp_stone><proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/></xmpp_stone>
I/flutter (27584): !!!!!!! PARSED<xmpp_stone><proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/></xmpp_stone>
I/flutter (27584): startSecureSocket
I/flutter (27584): XmppConnectionState.SocketOpened
I/flutter (27584): sending: <?xml version='1.0'?>
I/flutter (27584): <stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams'
I/flutter (27584): to='chat.connectycube.com'
I/flutter (27584): xml:lang='en'
I/flutter (27584): >
I/flutter (27584): response: <?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='chat.connectycube.com' id='33bdd27d-e081-460d-8d37-fa8ff4162814' version='1.0' xml:lang='en'>
I/flutter (27584): !!!!handle response <xmpp_stone><?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='chat.connectycube.com' id='33bdd27d-e081-460d-8d37-fa8ff4162814' version='1.0' xml:lang='en'></stream:stream></xmpp_stone>
I/flutter (27584): !!!!!!! PARSED<xmpp_stone><?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='chat.connectycube.com' id='33bdd27d-e081-460d-8d37-fa8ff4162814' version='1.0' xml:lang='en'></stream:stream></xmpp_stone>
I/flutter (27584): processInitialStream
I/flutter (27584): response: <stream:features><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features>
I/flutter (27584): !!!!handle response <xmpp_stone><stream:features><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features></xmpp_stone>
I/flutter (27584): !!!!!!! PARSED<xmpp_stone><stream:features><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features></xmpp_stone>
I/flutter (27584): Negotating features
I/flutter (27584): ELEMENT true
I/flutter (27584): sending: <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">ADEwMC0zNDcyAHh4YXNCVU0zZ1FzMzZiaGo=</auth>
I/flutter (27584): ACTIVE FEATURE: <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
I/flutter (27584):   <mechanism>PLAIN</mechanism>
I/flutter (27584):   <mechanism>ANONYMOUS</mechanism>
I/flutter (27584):   <mechanism>PLAIN_FAST</mechanism>
I/flutter (27584): </mechanisms>
I/flutter (27584): response: <failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>
I/flutter (27584): !!!!handle response <xmpp_stone><failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure></xmpp_stone>
I/flutter (27584): !!!!!!! PARSED<xmpp_stone><failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure></xmpp_stone>
I/flutter (27584): State: XmppConnectionState.AuthenticationFailure
I/flutter (27584): State: XmppConnectionState.Closing
I/flutter (27584): CB-SDK: CubeChatConnection: Chat connection AuthenticationFailure
I/chatty  (27584): uid=10323(com.oudomsup.ocwa) 1.ui identical 5 lines
I/flutter (27584): CB-SDK: CubeChatConnection: Chat connection AuthenticationFailure
I/flutter (27584): ELEMENT true
I/flutter (27584): ACTIVE FEATURE: <sm xmlns="urn:xmpp:sm:3"/>
I/flutter (27584): CB-SDK: LoginScreen.BodyState: Login error ChatConnectionException: Open connection error: AuthenticationFailure
I/flutter (27584): response: </stream:stream>
I/flutter (27584): !!!!handle response
I/flutter (27584): Handle secured connection done
I/flutter (27584): State: XmppConnectionState.Closed
I/flutter (27584): CB-SDK: CubeChatConnection: Chat connection Closed
I/chatty  (27584): uid=10323(com.oudomsup.ocwa) 1.ui identical 5 lines
I/flutter (27584): CB-SDK: CubeChatConnection: Chat connection Closed
TatankaConCube commented 4 years ago

@asongkai just use 'token' as a password for the user. For it before call _loginToCubeChat(context, cubeUser); do

// get current ConnectyCube session token and set as user's password
String token = CubeSessionManager.instance.activeSession?.token;
cubeUser.password = token;

More detail in our documentation.

asongkai commented 4 years ago

Thank you for response!

I'm not sure what is really happening, I do as mentioned but still not able to login

Error Log:

I/flutter (26426): CB-SDK: : *********************************************************
I/flutter (26426): *** RESPONSE *** 201 *** 916d7423-9bfd-4bf4-a8e2-58d1804d958d ***
I/flutter (26426): HEADERS
I/flutter (26426):   {connection: keep-alive, cache-control: max-age=0, private, must-revalidate, set-cookie: _mkra_ctxt=39641ae6a6e83b9b4e66cc7f5d81667c--201; path=/; max-age=5; HttpOnly; secure, status: 201 Created, transfer-encoding: chunked, date: Sat, 17 Oct 2020 00:00:15 GMT, access-control-allow-origin: *, strict-transport-security: max-age=31536000,max-age=15768000;, content-type: application/json; charset=utf-8, x-xss-protection: 1; mode=block, server: nginx/1.16.1, x-request-id: d60d5eff-7339-448f-b808-aeea4efe4233, cb-token-expirationdate: 2020-10-17 02:00:14 UTC, connectycube-rest-api-version: 0.1.1, x-runtime: 0.021856, etag: W/"4fe0f78a28b91bcaf0814758c1a9a247", x-frame-options: SAMEORIGIN, x-content-type-options: nosniff}
I/flutter (26426): BODY
I/flutter (26426):   {"session":{"id":18343448,"user_id":0,"application_id":3472,"nonce":3161826250,"token":"f6181faa591cd70390b1ec045e84bffc9d000d90","ts":1602892815,"created_at":"2020-10-17T00:00:15Z","updated_at":"2020-10-17T00:00:15Z"}}
I/flutter (26426): 
I/flutter (26426): CB-SDK: : =========================================================
I/flutter (26426): === REQUEST ==== e1f408f2-a527-4e33-84a1-1406265f2dac ===
I/flutter (26426): REQUEST
I/flutter (26426):   POST https://api.connectycube.com/session 
I/flutter (26426): HEADERS
I/flutter (26426):   {Content-type: application/json, ConnectyCube-REST-API-Version: 0.1.1, CB-SDK: Flutter 0.5.0, CB-Token: f6181faa591cd70390b1ec045e84bffc9d000d90}
I/flutter (26426): BODY
I/flutter (26426):   {"application_id":"3472","auth_key":"2SQ7ewuGSdVvA6f","nonce":"292839984","timestamp":"1602892816","signature":"73c0466a899148858b870c070863b2f20908c66c","user":{"login":"8562096729763","password":"f6181faa591cd70390b1ec045e84bffc9d000d90"}}
I/flutter (26426): 
I/flutter (26426): CB-SDK: : *********************************************************
I/flutter (26426): *** RESPONSE *** 401 *** e1f408f2-a527-4e33-84a1-1406265f2dac ***
I/flutter (26426): HEADERS
I/flutter (26426):   {connection: keep-alive, set-cookie: _mkra_ctxt=475cb6b3cf998eb82441327fa0736d57--401; path=/; max-age=5; HttpOnly; secure, cache-control: no-cache, status: 401 Unauthorized, transfer-encoding: chunked, date: Sat, 17 Oct 2020 00:00:17 GMT, access-control-allow-origin: *, strict-transport-security: max-age=31536000, content-type: application/json; charset=utf-8, x-xss-protection: 1; mode=block, server: nginx/1.16.1, x-request-id: 97591e6f-dd31-495b-8484-c8475e308719, connectycube-rest-api-version: 0.1.1, x-runtime: 0.025420, x-frame-options: SAMEORIGIN, x-content-type-options: nosniff}
I/flutter (26426): BODY
I/flutter (26426):   {"errors":["Unauthorized"]}
I/flutter (26426): 
I/flutter (26426): CB-SDK: LoginScreen.BodyState: Login error ResponseException: 401: {"errors":["Unauthorized"]}

Updated Code:

createSession()
          .then((cubeSession) {
        CubeUser cubeUser = CubeUser(
            id: G.loggedInUser.id,
            login: G.loggedInUser.phone,
            password: CubeSessionManager.instance.activeSession?.token,
            email: G.loggedInUser.email,
            fullName: G.loggedInUser.name,
            phone: G.loggedInUser.phone);

        if (CubeSessionManager.instance.isActiveSessionValid()) {
          String token = CubeSessionManager.instance.activeSession?.token;
          cubeUser.password = token;
          _loginToCubeChat(context, cubeUser);
        } else {
          createSession(cubeUser).then((cubeSession) {
            String token = CubeSessionManager.instance.activeSession?.token;
            cubeUser.password = token;
            _loginToCubeChat(context, cubeUser);
          }).catchError(_processLoginError);
        }
      })
          .catchError((error) {});
TatankaConCube commented 4 years ago

You misunderstood me, you have to use the token as a password only for chat connection, not everywhere. It means you have to authorize via Firebase phone auth first, then use this token for chat login.

asongkai commented 4 years ago

Hi,

I used the following code it works but I have another question,

loginToChat() async {
    createSession()
        .then((cubeSession) async {
      CubeUser cubeUser = CubeUser(
          id: G.loggedInUser.id,
          login: G.loggedInUser.phone,
          password: CubeSessionManager.instance.activeSession?.token,
          email: G.loggedInUser.email,
          fullName: G.loggedInUser.name,
          phone: G.loggedInUser.phone);

      if (CubeSessionManager.instance.isActiveSessionValid()) {
        String token = CubeSessionManager.instance.activeSession?.token;
        cubeUser.password = token;
        print('Token valid');
        print(cubeUser.toJson());
        _loginToCubeChat(context, cubeUser);
      } else {
        print('Token invalid');
        String accessToken = await FirebaseAuth.instance.currentUser.getIdToken(true);
        signInUsingFirebase(PROJECT_ID, accessToken)
            .then((cubeUser) async {
          String token = CubeSessionManager.instance.activeSession?.token;
          cubeUser.password = token;
          print('password: $token');
          createSession(cubeUser).then((cubeSession) {
            _loginToCubeChat(context, cubeUser);
          }).catchError(_processLoginError);
        })
            .catchError((error){
          print(error);
        });
      }
    })
        .catchError((error) {});
  }

Do I need to create a new Session token and login to chat every time the app open? or Connectycube manage the session like Firebase instance?

because I tried to put them in separate method only response like "unauthenticate", "session invalid".

TatankaConCube commented 4 years ago

No, in the current realisation of our Flutter SDK we don't have an automatic session management, you have to realise it by yourself.

asongkai commented 4 years ago

As I mentioned above once I can login and created the user session if I close the app and reopen the session has gone which can't use other feature like chat or video call that's force me to login every time I open my app and the process of logging in is so slow too which make my app load slow at the start.

asongkai commented 4 years ago

The demo app also same if I close the app and reopen the session has gone the same, need to select a user again and login again

So, once I authenticated with firebase and I try to create the user session token in a separate thread it only show me "Unauthorized" message on response so the solution for my case now is like I posted the code above

I mentioned firebase instance because "Yes, I have to do the user session by myself in order to redirect user to login or home screen" but I don't have to authenticate again or login again to be able to use the chat or video feature.

but current case is once I logged in I can use but if I close the app and reopen and go to use chat or video it said "Unauthenticated"

TatankaConCube commented 4 years ago

As I said before, the current version of our SDK doesn't have a session manager yet and you can realize it by yourself. There can be oriented steps:

asongkai commented 4 years ago

Thank you very much I will give that try

asongkai commented 4 years ago

Hi,

I do as you mentioned by why the token expiry date is always null

      String accessToken =
            await FirebaseAuth.instance.currentUser.getIdToken(true);
        signInUsingFirebase(PROJECT_ID, accessToken).then((cubeUser) async {
          String token = CubeSessionManager.instance.activeSession?.token;
          cubeUser.password = token;
          createSession(cubeUser).then((cubeSession) {
            services.setValue('token', cubeSession.token);
            services.setValue('token_expire', cubeSession.tokenExpirationDate);
            print('token_token: ${cubeSession.token}');
            print('token_expire: ${cubeSession.tokenExpirationDate}');
            _loginToCubeChat(context, cubeUser);
          }).catchError(_processLoginError);
        }).catchError((error) {
          print(error);
        });

What's wrong?

image

TatankaConCube commented 4 years ago

why the token expiry date is always null

we found the issue on the SDK side, we will provide fixes in the next release, thank you for your checks.

TatankaConCube commented 3 years ago

@asongkai today we released version 0.5.1 with required fixes for your issue. But pay attention, you should use this way for getting the expiration date CubeSessionManager.instance.getTokenExpirationDate(); because any successful API request prolongs the token validity for 2 hours. More in our documentation for server API.

TatankaConCube commented 3 years ago

Closing. If you have a similar issue in the latest version, please create a new ticket with a description according to templates.