Can't create a Firebase Auth Wrapper with WebControlSDK

Hello, Firebase provides excellent authentication tools.

I could follow these two tutorials and make simple websites to work:

https://www.youtube.com/watch?v=hb85pYZSJaI

https://www.youtube.com/watch?v=CvkCjfHts9A

What I need to accomplish is to have a wrapper for it, so I can use it on my web apps.

I tried following the webSDK manual to do that, but I’m not having success so far. I have already developed some wrappers myself, but I’m stuck at this one.

Can you guys please give me some pointers?

At present, the issue at hand is this annoying message on the web console:

Error: Could not find the FirebaseUI widget element on the page. firebaseui.js:185:92

I know it is there, I can see it on web inspector. Perhaps it can’t be seen by Javascript because it is embedded in an iframe?

Below is the code supplied by Firebase that searchs for the FirebaseUI widget, which I have put in the ‘Firebase_Widget_Init’ constant in my web app:

[code]

[/code]

This code is called on the HTMLHeader Event of the WebControlWrapper.

[code]Public Shared Function HTMLHeader(CurrentSession as WebSession) as String
If Not IsLibraryRegistered(CurrentSession, JavascriptNamespace, “lbmdataFireBaseUI”) Then
RegisterLibrary(CurrentSession, JavascriptNamespace, “lbmdataFireBaseUI”)
Dim sa() As String

sa.Append Firebase_Initialization
sa.Append Firebase_Widget_Init

'Dim kp As String
'kp = Join(sa, EndOfLine.UNIX)

Return join(sa,EndOfLine.UNIX)

End If
End Function
[/code]

For some reason the web app is also failing to load the HTML, on the setter below:

mHTML = value If ControlAvailableInBrowser() Then ExecuteJavaScript("Xojo.get('" + me.ControlID + "').innerHTML = '" + value + "';") End If

Any ideas?

Well, after a lot of struggling with it I finally managed to get this Firebase Auth thing working on Xojo… sort of. It feels clunky and awkward, or I’m just being too demanding of myself.

In order for it to work I had to first understand that the login widget should not be handled by Xojo. There is an awful lot of javascript to it so it is best to let it sit on a standalone webpage just as shown on the youtube videos above (first post).

As my need is to have an authentication method, I only have to deal with the second part, the “firebase.auth().onAuthStateChanged” part.

This is how I did it:

1 - Created a WebControlWrapper with the following objects:

Constants:

Public Const a_Logout as String = function logOut(){
	firebase.auth().signOut();
}
Public Const Firebase_Action as String =     firebase.auth().onAuthStateChanged(function(user) {
        var res = [];
          var myuser = document.getElementById("user");
          var mynome = document.getElementById("nome");

        if (user) {
          // User is signed in.
          uid = user.uid;
          dname = user.displayName;
          myuser.innerHTML = uid;
          mynome.innerHTML = dname;

           document.cookie = "user=" + uid;
           document.cookie = "nome=" + dname;
	
	res.push(uid);
	res.push(dname);

       Xojo.triggerServerEvent('<<Controle>>', 'Logado', res);
	
        } else {
            uid = null;
            dname = null;

          myuser.innerHTML = "-";
          mynome.innerHTML = "-";

            document.cookie = "user=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
            document.cookie = "nome=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";

	var d = new Date();

	res.push("deslogado");
	res.push(d);

       Xojo.triggerServerEvent('<<Controle>>', 'Deslogado', res);

        }
      });

Public Const Firebase_Init as String = <script src="https://www.gstatic.com/firebasejs/5.8.0/firebase.js"></script>

Public Const Firebase_Main as String = // Initialize Firebase
	var config = {
		apiKey: "YOURFIREBASEAPI",
		authDomain: "YOURFIREBASEDOMAIN",
		databaseURL: "YOURFIREBASEDATABASEURL",
		projectId: "YOURPROJECTID",
		storageBucket: "YOURSTORAGEBUCKET",
		messagingSenderId: "YOURMESSAGESENDERID"
	};
    firebase.initializeApp(config);

Public Const JavascriptNamespace as String = lbmdata_firebaseui

Event Definitions:

Event Deslogado(dado As Variant)
Event Logado(dado As Variant)

Event Handlers:

Sub SetupCSS(ByRef Styles() as WebControlCSS) Handles SetupCSS
  Styles(0).Value("visibility") = "visible"
End Sub

Function SetupHTML() Handles SetupHTML as String
  Return "<div id=""" + self.ControlID + """>" + html + "</div>"
End Function


Sub Shown() Handles Shown
  Init

End Sub

Methods:

Public Sub Init()
  Dim par As String
  
  par = ReplaceAll(Firebase_Action, "<<Controle>>", self.ControlID)
  par = par + EndOfLine.UNIX + a_Logout
  
  Self.HTML = par
End Sub


Public Sub Logout()
  Session.Cookies.Remove("user")
  Session.Cookies.Remove("nome")
  
  Self.HTML = "logOut();"
End Sub

Properties:

Public Property HTML as String
Get
  Return mHTML
End Get

Set
  mHTML = value
  If ControlAvailableInBrowser() Then
    ExecuteJavaScript(value)
    
  Else
    MsgBox("Firebase Widget not available in browser!")
    
  End If
End Set

End Property

Private Property mHTML as String

Shared Methods:

Public Shared Function HTMLHeader(CurrentSession as WebSession) as String
  If Not IsLibraryRegistered(CurrentSession, JavascriptNamespace, "lbmdataFireBaseUI") Then
    RegisterLibrary(CurrentSession, JavascriptNamespace, "lbmdataFireBaseUI")
    
    Dim sa() As String
    
    sa.Append Firebase_Init
    sa.Append "<script>"
    sa.Append Firebase_Main
    sa.Append a_Logout
    sa.Append "</script>"
    
    Return join(sa,EndOfLine.UNIX)
    
  End If
End Function

In my first tests I used some HTML divs in a page, set as a WebPageSource, whose content is below:

<div id="user">UID</div>
<div id="nome">NOME</div>

It worked, but I couldn’t figure how to trigger the Xojo events called by Xojo.triggerServerEvent('<<Controle>>', 'Deslogado', res); and Xojo.triggerServerEvent('<<Controle>>', 'Logado', res);

So… I embedded the WebControlWrapper (named as FireBase_APL) in a WebContainer along with a WebButton, a WebTimer, a WebTextArea. The button and the textarea area for developing and testing purposes only. The Timer is important for the overall result.

These are the parameters added to the WebContainer:

Event Definitions:

Event Deslogou()
Event Logou(nome As String, uid As String)

Properties:

Private Property logado as Boolean = False
Private Property logadoold as Boolean = True

The code in the Action event of the button is this:

FireBase_APL.Logout

And the code in the Timer.Action event is this:

Dim dd As new Date
Dim j() As String = Array(Session.Cookies.Value("user"), Session.Cookies.Value("nome"))

txt_Feedback.AppendText Join(j) + " - " + dd.ShortTime + EndOfLine

If j(0) = "" Then
logado = False
If Not logado And logadoold Then
RaiseEvent Deslogou
End If
logadoold = False

Else
logado = True
If logado And Not logadoold Then
RaiseEvent Logou(j(0), j(1))
End If
logadoold = True

End If

This is how it works:

The FirebaseUI Widget (not shown here) must have its “signInSuccessUrl” parameter set to your Xojo Web App URL, including the port, if it is a standalone deployment. On CGI deployment (my case), the URL must include the “app.cgi” part.

When the web app receives focus from the browser, the javascript “firebase.auth().onAuthStateChanged” is fired. I have set it to create cookies for the user name and uid (and fire a Xojo triggerevent, that DOES NOT work!).

The timer on the WebContainer checks whether these cookies are set or not and depending on the result, the Events “Logado” (portuguese for logged) and “Deslogado” are raised and treated at the webpage.

I would really appreciate some help in making the Xojo.triggerServerEvents to work. That way I could get rid of the cookies, timer and WebContainer.

For the time being, I consider this to be a working solution!

@Leonidas Brasileiro
Did you try the quick start tutorial in the WebSDK pdf? It specifically shows how to use TriggerServerEvent.

For instance… I don’t see here that you implemented the Event named ExecuteEvent which is where the event comes first, and then you are responsible for dispatching to your Event Definitions if necessary.

@Greg O’Lone, thanks a lot for your input!

You were right, ExecuteEvent wasn’t being handled at all in the WebControlWrapper.

I just set the code below and now it works as smooth as silk!

Function ExecuteEvent(Name as String, Parameters() as Variant) Handles ExecuteEvent as Boolean
  Select Case Name
    
  Case "Logado"
    Logado(Parameters)
    
  Case "Deslogado"
    Deslogado(Parameters)
    
  End Select
  
End Function

I also simplified the Firebase_Action constant to:

Public Const Firebase_Action as String = firebase.auth().onAuthStateChanged(function(user) {
    var res = [];
    var opcao = '';
    if (user) {
          // User is signed in.
          uid = user.uid;
          dname = user.displayName;
          res.push(uid);
          res.push(dname);
          opcao = 'Logado';
	
    } else {
        uid = null;
        dname = null;
        var d = new Date();
        res.push("deslogado");
        res.push(d);
        opcao = 'Deslogado';
    }
    Xojo.triggerServerEvent('<<Controle>>', opcao, res);
      });

After these changes, I got rid of the Webcontainercontrol and set the wrapper all by itself in a webpage… Just added a WebTextAre a for showing some output from the ‘Logado’ and ‘Deslogado’ events and a Webbutton to call Logout method.

It just works!