firebase / firebase-admin-node

Firebase Admin Node.js SDK
https://firebase.google.com/docs/admin/setup
Apache License 2.0
1.63k stars 371 forks source link

support standard credential interfaces #334

Open ptone opened 6 years ago

ptone commented 6 years ago

Feature request to support standard Google credential interfaces to support more custom credential integrations.

https://github.com/google/google-auth-library-nodejs

Currently this library uses bespoke approaches such as: https://github.com/firebase/firebase-admin-node/blob/5d43af1e29c2afcbb84fa168e720874fa4211e4f/src/firestore/firestore.ts#L90

google-oss-bot commented 6 years ago

Hmmm this issue does not seem to follow the issue template. Make sure you provide all the required information.

google-oss-bot commented 6 years ago

Hey there! I couldn't figure out what this issue is about, so I've labeled it for a human to triage. Hang tight.

hiranya911 commented 6 years ago

I ran into several issues last time I tried supporting google-auth credentials (can't remember what those were exactly right now). But if you want to support more custom credentials, you can do so by implementing the Credential interface provided by the Admin SDK: https://firebase.google.com/docs/reference/admin/node/admin.credential.Credential

hiranya911 commented 5 years ago

@ptone can you comment on how you think this should be exposed to the developers? What should the admin.initializeApp() method accept? I'm making some progress towards natively supporting google-auth-library, but what they consider to be "standard" Google Credentials are quite, umm, unusual (at least compared to other languages).

These are the options I can think of:

Option 1

This is what other Node.js GCP libraries support. But this doesn't support refresh token credentials, which is something we do support today.

// service account
admin.initializeApp({
  keyFilename: 'path/to/serviceAccount.json',
});

// or
admin.initializeApp({
  credentials: {client_email, private_key},
});
// ADC
admin.initializeApp();

Option 2

This has more in common with how the credentials are exposed in other languages (Java, Go, C# etc). Notice that this calls a bunch of async APIs at the initialization, which causes problems when trying to initialize the app in the global scope.

import {auth} from 'google-auth-library';

// service account OR refresh tokens
const file = require('path/to/file.json');
admin.initializeApp({
  credentials: auth.fromJSON(file),
});
// service accounts ONLY
const credentials = await auth.getClient({
  keyFilename: 'path/to/serviceAccount.json'
});
admin.initializeApp({credentials});

// or
const credentials = await auth.getClient({
  credentials: {client_email, private_key},
});
admin.initializeApp({credentials});
// ADC
admin.initializeApp();

// or
const credentials = await auth.getClient();
admin.initializeApp({credentials});
hiranya911 commented 5 years ago

Option 3

import {GoogleAuth} from 'google-auth-library';

// service account
admin.initializeApp({
  credentials: new GoogleAuth({
     keyFilename: 'path/to/serviceAccount.json',
  }),
});

// ADC
admin.initializeApp({
  credentials: new GoogleAuth(),
});

// this might work for refresh tokens
const credentials = require('path/to/file.json');
admin.initializeApp({
  credentials: new GoogleAuth({credentials});
})
hiranya911 commented 5 years ago

GCP Node.js libraries seem to follow the configuration mechanism outlined here: https://github.com/googleapis/google-cloud-node/blob/master/docs/authentication.md

ptone commented 5 years ago

Thanks for looking at this @hiranya911

I recall Python libs having the cleanest interface definition of a token, basically duck type so long as you have a refresh method, and a access_token and expiration set of attributes. The client library will call your refresh method as needed.

So I see this less about initializing with the well-known credential data, and more about providing an interface. In go with would be the tokensource https://godoc.org/golang.org/x/oauth2#TokenSource

Anything that can provide a token, can be used with the client-libs.

hiranya911 commented 5 years ago

Thanks @ptone. I think in our case that interface is Credential: https://firebase.google.com/docs/reference/admin/node/admin.credential.Credential. Admin SDK already accepts any object that implements this interface.

However, it seems all the Node.js GCP libraries are designed to work with only 2 types of credentials:

  1. service account credentials
  2. application default credentials

This means APIs like Firestore and GCS will not work with custom credentials. I will follow up with the GCP Node.js team and try to figure out what their thinking here is.