ganders
ganders

Reputation: 7432

Loading data from Firebase database which requires authentication throws error firebase could not parse auth token

I have a website that utilizes SQL Server on Azure for all of it's data. I'm partnering with another company to get additional, supplemental information for specific records that exist in my database.

When those "specific reccords" are being viewed, I want to provide another link to retrieve that supplemental information from the Firebase database.

So, I'm trying to write a service that will retrieve this data, here's what I've written so far as a PoC:

private readonly string firebaseUrl = "https://{myproject}.firebaseio.com/";
private readonly string authToken = "x:xxxxxxxxxxx:xxx:xxxxxxxxxxxxxxxx";

public async Task<IEnumerable<InMatchStat>> GetInMatchStats()
{
    try
    {
        var firebase = new FirebaseClient(firebaseUrl, new FirebaseOptions { AuthTokenAsyncFactory = () => Task.FromResult(authToken) });

        var stats = await firebase.Child("my/collection/path").OnceAsync<InMatchStat>();

        if (stats == null || !stats.Any())
        {
            return null;
        }

        return await Convert(stats.AsEnumerable());
    }
    catch (Exception exception)
    {
        var message = exception.ToString();
    }

    return null;
}

This is the error that I'm getting back from Firebase when it tries to execute the var stats = await firebase.Child().... call:

firebase could not parse auth token

Here's a link to the FirebaseDatabase.NET Github page: https://github.com/step-up-labs/firebase-database-dotnet

In case that link goes dead in the future, here's the exact sample that I'm trying to replicate that is shown on that site:

var auth = "ABCDE"; // your app secret
var firebaseClient = new FirebaseClient(
  "<URL>",
  new FirebaseOptions
  {
    AuthTokenAsyncFactory = () => Task.FromResult(auth) 
  });

And the query example from that page:

var firebase = new FirebaseClient("https://dinosaur-facts.firebaseio.com/");
var dinos = await firebase
  .Child("dinosaurs")
  .OrderByKey()
  .StartAt("pterodactyl")
  .LimitToFirst(2)
  .OnceAsync<Dinosaur>();

foreach (var dino in dinos)
{
  Console.WriteLine($"{dino.Key} is {dino.Object.Height}m high.");
}

Where am I going wrong with my implementation?

Upvotes: 4

Views: 3879

Answers (1)

ganders
ganders

Reputation: 7432

Just want to get this updated as I finally figured out the solution, for me...

Here's where I got the solution from: https://github.com/step-up-labs/firebase-database-dotnet/issues/60

This version passes the email address and password to get the authentication token. Then once we have the token, it gets passed to the Firebase client like before.

(Note: I needed to add the FirebaseAuthentication.net nuget package)

public async Task<IEnumerable<InMatchStat>> GetInMatchStats()
{
    const string firebaseUrl = "https://xxxxxxxxxxxxxx.firebaseio.com/";
    const string firebaseUsername = "[email protected]";
    const string firebasePassword = "xxxxxxxx";
    const string firebaseApiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

    bool tryAgain = false;
    FirebaseAuthLink token = null;

    try
    {
        var auth = new FirebaseAuthProvider(new FirebaseConfig(firebaseApiKey));

        do
        {
            try
            {
                token = await auth.SignInWithEmailAndPasswordAsync(firebaseUsername, firebasePassword);
            }
            catch (FirebaseAuthException faException)
            {
                // checking for a false tryAgain because we don't want to try and create the account twice
                if (faException.Reason.ToString() == "UnknownEmailAddress" && !tryAgain)
                {
                    // create, then signin
                    token = await auth.CreateUserWithEmailAndPasswordAsync(firebaseUsername, firebasePassword, "Greg", false);
                    tryAgain = true;
                }

                throw;
            }
            catch (Exception)
            {
                throw;
            }
        }
        while (tryAgain);

        var firebase = new FirebaseClient(firebaseUrl, new FirebaseOptions { AuthTokenAsyncFactory = () => Task.FromResult(token.FirebaseToken) });
        var stats = await firebase.Child("my/collection/path").OnceAsync<InMatchStat>();

        if (stats == null || !stats.Any())
        {
            return null;
        }

        //return await Convert(stats.AsEnumerable());
    }
    catch (Exception exception)
    {
        var message = exception.ToString();
    }

    return null;
}

Upvotes: 3

Related Questions