Integrating Firebase Authentication

I need to integrate Firebase Authentication into Apigee. Specifically, I need to make use of the Admin SDK in order to create custom tokens and then verify them on subsequent calls. It appears that a Java Callout might be able to satisfy my needs - one for a login flow which creates the custom token and another that will sit in the policy chain for all calls requires authentication. I suppose I always have the option just to create a NodeJs app proxy that does all this. How should I approach this problem?

4 7 3,083
7 REPLIES 7

Hi Danny, I am facing similar problem right now and looking for suggestions. Currently using Firebase for backend, and would like to create an API and manage it with Apigee. Where should we authenticate api calls? Were you able to find a good approach to solving this.

Thanks

/Viktoria

Hi Danny and Viktoria

I'm not sure you two are asking the same question.

Also I'm not a Firebase expert, but I know enough to be dangerous.

With that as prelude, here are some remarks, maybe this will be helpful . First let me address Danny's somewhat old question.

Firebase has lots of capabilities. I think of it as a broad "backend as a service" for mobile apps and many others. Among those capabilities

  • authentication subsystem supporting email/password login, phone login, 3rd party signin, signup quotas, all sorts of stuff
  • a cloud-based JSON data store called Firestore
  • crash analytics framework (Crashylytics?)
  • Cloud functions
  • Hosting
  • Cloud storage
  • and more

When Danny says "I want to integrate Firebase Authentication into Apigee".. that's easy.

Firebase Authentication is the piece of the firebase platform that allows user authentication with a variety of options. Firebase supplies "SDKs" (or packaged libraries) that allow you to drop in a few lines of HTML markup into a webapp, or a few lines of Objective-C into your iOS app (etc), to allow authentication.

There is also a REST API supporting Firebase Authentication. For example, to perform basic User auth with email + password, the request looks like this:

curl "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=$FIREBASE_AUTH_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"email":"dchiesa@example.com","password":"Secret!!","returnSecureToken":true}'

And in response you get a JSON payload like this:

{
  "kind": "identitytoolkit#VerifyPasswordResponse",
  "localId": "iM6wwpmIHlbcuYPVRUQqbWah3Os1",
  "email": "dchiesa@example.com",
  "displayName": "",
  "idToken": "eyJhbGciOiJSU.eyJpc3MiOiJodHRwczovL3NlY3VyZXRv.BwsBPNcBhDe_-eTzCrbas-c8j0VuFF6Rw",
  "registered": true,
  "refreshToken": "AEu4IL3a_f4l9SCLY021vK_v",
  "expiresIn": "3600"
}

The idToken is a JWT, signed by Google (Firebase Authentication) using RS256. The payload contents look like this:

{
  "iss": "https://securetoken.google.com/my-firestore-project",
  "aud": "my-firestore-project",
  "auth_time": 1552414729,
  "user_id": "iM6wwpmIHlbcuYPVRUQqbWah3Os1",
  "sub": "iM6wwpmIHlbcuYPVRUQqbWah3Os1",
  "iat": 1552414729,
  "exp": 1552418329,
  "email": "dchiesa@example.com",
  "email_verified": false,
  "firebase": {
    "identities": {
      "email": [
        "dchiesa@example.com"
      ]
    },
    "sign_in_provider": "password"
  }
}

Since this is just a JWT, like any other JWT, you can verify it within Apigee Edge using a standard VerifyJWT policy. You don't need a Java callout. The Verify looks like this:

<VerifyJWT name='VerifyJWT-1'>
  <Algorithm>RS256</Algorithm>
  <Source>inbound.jwt</Source>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <PublicKey>
    <JWKS ref='jwksResponse.content'/>
  </PublicKey>
  <Issuer ref="expected_issuer"/>
</VerifyJWT>

...where jwksResponse.content is the contents of this URL :

https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com

This is the "well known" URL for JWK used by Google Firebase Authentication....your proxy must GET that URL via ServiceCallout.


In a few days you will be able to use the much cleaner approach of:

<VerifyJWT name="VerifyJWT-1">
    <Algorithm>RS256</Algorithm>
    <Source>inbound.jwt</Source>
    <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
    <PublicKey>
        <JWKS uri="https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com"/>
    </PublicKey>
    <Issuer ref="expected_issuer"/>
</VerifyJWT>

In summary, to use Firebase Authentication with Apigee Edge, configure the client app to:

  • authenticate with Firebase Authentication and obtain a JWT idToken in some way
  • send in the JWT idToken in a header or otherwise with API requests handled by Apigee Edge

And then configure the Apigee Edge proxy to use VerifyJWT as described above.

If the VerifyJWT succeeds, then the proxy can be assured that the identity asserted in the JWT is authentic, and the user has been authenticated by Google Firebase Authentication.

At that point the proxy can do anything you like with that information.

Dino,

Thank you for the response.

The amount of integration work ended up being pretty hefty, so we opted to deploy a Node proxy and made use of the firebase admin sdk for nodejs. I barely scratched the surface on policies - the JWT one looks very good.

Viktoria, I deployed a traditional nodejs express server on Apigee. The client passed the ID Token in the Authorization header and I used the firebase admin sdk to verify the token. You maybe looking for something requiring less work, so I would definitely look at the JWT policy.

Viktoria, you asked

Currently using Firebase for backend, and would like to create an API and manage it with Apigee. Where should we authenticate api calls?

Firebase Authentication is a good way to authenticate a user. By "authentication" we imply "verifying that the user is who s/he says /she is." In the old days this was almost always done with a username + password check. Now Firebase Auth allows all sorts of other options, including multi-factor auth, 3rd party signin, Github signin, and so on.

There is a distinct "authentication" that you might want to consider, and that is "client authentication" - basically answering the question, "is the client app a known entity." Here the world has settled on the idea of "client credentials" , that is to say, credentials that are known by and used by the client app. This might be as simple as a client id and secret. Or the credentials might be a public/private keypair issued to the client. Or a TLS certificate, and so on.

Apigee Edge can perform client authentication in a number of ways.

  • The client can present a client id AND secret. This is done with the client_credentials grant type in the OAuthV2 flow
  • The client could present a client ID, AND... something HMAc-signed with the secret. For example, a self-signed JWT that uses algorithm HS256 and using the client secret as the key. Since Apigee Edge also knows the secret (it's a "shared secret"), Apigee Edge can verify that JWT and then be assured the client is bonafide.
  • If the client possesses a private key, the client can send an RSA-signed JWT, and Apigee Edge can verify the identity in the same way.
  • If the client has a specific TLS cert, Apigee Edge can verify the cert fingerprint or SN on the cert.

There may be other options.

After authenticating the client in one of these ways, the API Proxy can trust that the client is known. Separately the API proxy may wish to authenticate the user. This can be done with Firebase Auth, or via some other mechanism .

With both the client and the user authenticated, Apigee Edge can issue a token to the requesting app. The app can then present the token with each API request, and Apigee Edge can quickly verify that token on future calls. If the token is valid, then Apigee Edge can invoke the Firebase backend. If not, then Apigee Edge will return a 403 or 401 (or etc) code to the API client.

Does this help?

Thank you both for your answers. I am would like to build a REST API and use tools that Apigee has to help. I have some data stored in firebase and I would like to share some of the data with people and other business thru an API. I am using Firebase Auth Rest API to sign up a user, to get an idToken. I am wondering if this is a token that user attaches to make api calls or is that a token used only for authentication and for authorization a new token is required. @Dino-at-Google you mention that when the client and the user authenticated, Apigee Edge can issue a token to the requesting app, but how can firebase know that that token is allowed and what user is allowed to do and what data can be accessed? Can you also issue that type of token using firebase? @Danny Baggett is admin sdk the only way to verify the token, I saw that you can do that as well using the Rest API by issuing a POST request to the Auth verifytoken endpoint?

Thank you again!

The authentication subsystem in Firebase is distinct from the backend store, as far as I am aware. as I said, I am not a Firebase expert, but that is my understanding.

how can firebase know that that token is allowed and what user is allowed to do and what data can be accessed

Because the authentication of the user (and client) is distinct from the backend datastore, There is no "knowing". The Firebase Firestore doesn't "know" about the idToken. It isn't the case that the backend store will verify the id_token before granting access.

The id_token is just an identifier. The system that issued the token is called "Firebase Authentication", but this authentication subsystem is independent of the Firebase Firestore. The two things are in the same toolbox, They have the same family name, but they're not integrated in the way you are imagining, I don't think.

This is where an API Management solution can help.

Rather than allowing the client to send the id_token directly into Firestore to request data, you can insert Apigee Edge as a proxy between the client and the backend. Now the client sends the id_token to Apigee Edge, and you can design your Apigee Edge API Proxy to

  • verify the id_token: is it signed by someone I trust (eg Firebase Authentication)?
  • authorize the request: once the id_token is verified, Apigee Edge can trust the subject claim in the token, and can then check "does this person have authorization to get the data it is requesting? or to change the data it is trying to change?"

How you perform that latter step - the authorization check - is up to you. Apigee Edge doesn't explicitly have an authorization engine in it. In other words it does not include a subsystem that allows you to configure a set of rules that says: person A is allowed to do X, Y and Z. Person b is allowed to do X and Y, but not Z. And so on.

It is possible if your needs are simple to codify that into a simple table.

Or, if your needs are super simple, then you can do it within Apigee Edge as a Condition.

Eg, if the case is "if the username is X, then allow the request, otherwise don't." then you can code that in Apigee Edge.

or if the case is "if the email address has X domain, then allow." Those kinds of simple blanket rules can be coded in Apigee Edge simply. If it's complicated and involves lots of different rules, then you might want to externalize the authorization decision into a table, or external system.

helpful?

Can you also issue that type of token using firebase?

Earlier I said that Apigee Edge can issue a token. That might be confusing because... in the situation we are discussing, it is Firebase that isseus the id token. So you might wonder, why do I need Apigee Edge to issue a token, too?

The only reason is to simplify the authorization flow. An Id token can be 512 bytes or 1k. Apigee edge can issue an opaque token that is 28-32 bytes, and it carries the same information. You don't need to deisgn your Apigee Edge proxy to issue this kind of opque token. You can if you like.

I don't believe you can configure Firebase Authentication to issue this kind of opque token. As far as I am aware, Firebase Authentication issues id tokens.

so can you help me how to authenticate firestore with in apigee when client is not sending firebase/firestore token