firebase / firebase-admin-dotnet

Firebase Admin .NET SDK
https://firebase.google.com/docs/admin/setup
Apache License 2.0
370 stars 131 forks source link

Call to load credentials with FirebaseAdmin does not work #130

Closed WellspringCS closed 4 years ago

WellspringCS commented 4 years ago

Usually I post my issues on stack exchange, because I'm assuming the problem is mine. So I've done that...

But It occurs to me that on this one maybe I should log a bug. Sure seems to be one. So here's what I wrote...

I am working with FirebaseAdmin 1.9.1 and attempting to use the recommended method for this call:

FirebaseApp.Create(new AppOptions()  
{
  Credential = credential,
});

From all that I read, I can load the credential paramater via this...

var credential = await GoogleCredential.GetApplicationDefaultAsync();

or this

credential = GoogleCredential.FromFile("/your/path/to/glory/google-service-accounts.json");

And if the value of a special environment variable is set as so...

"GOOGLE_APPLICATION_CREDENTIALS": "/your/path/to/glory/google-service-accounts.json",

...the two approaches should produce the same, working, result.

Not so! Not so.

The 2nd version works, but the first, recommended, approach? Using GetApplicationDefaultAsync?

Not so much.

I have checked and re-checked, and the two strings containing "/your/path/to/glory/google-service-accounts.json" are identical, though obviously not the value I've pasted here.

GOOGLE_APPLICATION_CREDENTIALS I copied and pasted directly. And I can see it properly set in the environment variables.

In fact, just to add salt to my wounds, I tried this...

credential = GoogleCredential.FromFile(_configuration["GOOGLE_APPLICATION_CREDENTIALS"]);

And the credentials DID load.

hiranya911 commented 4 years ago

GoogleCredentials API is part of https://github.com/googleapis/google-api-dotnet-client, so that's where you should really report this. But in any case, I'd be extremely surprised if this turns out to be a bug. Application default credentials are the common and preferred way to use these APIs, and we will be dealing with multiple bug reports if there was a bug. We also have the following unit test that verifies this behavior:

https://github.com/firebase/firebase-admin-dotnet/blob/83222d3b44760603c5a41424e199b69eeebaff5c/FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAppTest.cs#L165-L179

How did you determine that it doesn't work? What errors are you getting?

WellspringCS commented 4 years ago

Thanks for your reply -- apologies for logging this issue in the wrong place!

Yes, it does seem strange and suspicious for me to be the only one with this problem... however the code is as shown above.

I don't get errors until a REST call activates the API.

The symptom is that the credentials go (in the below code) from having proper values for everything (Id, ProjectId, etc) to having essentially nothing set at all. I have this code in an ASP.NET Core 3.0 project, set up in ConfigureServices(). I can watch as I step through to below and see the first set to credential succeed and then the 2nd wipe it out.

    public class FireBaseService: IHostedService
    {
        private static IConfiguration _configuration;

         public FireBaseService(IConfiguration configuration)
            {
                _configuration = configuration;
            }

        public async Task StartAsync(CancellationToken cancellationToken) {

            GoogleCredential credential = null;

                credential = GoogleCredential.FromFile(_configuration["GOOGLE_APPLICATION_CREDENTIALS"]);
                credential = await GoogleCredential.GetApplicationDefaultAsync();
            FirebaseApp.Create(new AppOptions()  
            {
                Credential = credential,
            });
            return;
        }
        public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
    }
}
hiranya911 commented 4 years ago

What is the exact error you are getting?

I can watch as I step through to below and see the first set to credential succeed and then the 2nd wipe it out.

What does that mean? Does it get set to null? I would expect FirebaseApp.Create() to throw if the Credential option was null. So that cannot be it:

https://github.com/firebase/firebase-admin-dotnet/blob/83222d3b44760603c5a41424e199b69eeebaff5c/FirebaseAdmin/FirebaseAdmin/FirebaseApp.cs#L72-L75

Also try adding the following line to your code and ensure it prints the correct path:

Console.WriteLine(Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"));
hiranya911 commented 4 years ago

You can see here that the first thing it does is to look up the GOOGLE_APPLICATION_CREDENTIALS env variable:

https://github.com/googleapis/google-api-dotnet-client/blob/master/Src/Support/Google.Apis.Auth/OAuth2/DefaultCredentialProvider.cs#L84

My guess is that your env variable is not set correctly (or it is not set in a way that is visible to your running process). This causes it to fallback to one of the other credential discovery mechanisms, and ends up finding the wrong credentials.

WellspringCS commented 4 years ago

Cutting to the point: I did scrutinize that code yesterday, asking the same question. But (in a longer paragraph I started to write to you this morning, I realized I was telling you that GOOGLE_APPLICATION_CREDENTIALS was coming in via secrets.

Ooops. That's not environment.

I moved it and... problem solved. Thanks much!