0
votes

Quick Background: I'm programming an API that is thought to be used "standalone" i.e. there is no frontend involved. API access should be possible directly from e.g. Postman or Curl with a Bearer token in the Authentication Header.

I was looking at Google Firebase and thought it is probably a really good fit because all of the authentication is already "builtin" and directly compatible with Google Cloud Functions. However after a weekend of experimenting I can not seem to figure out how to implement an REST API (With Google Cloud Functions) where the User can (In an web-interface) request an API token to interact with the API. I don't want to handle authentication myself. I really would love to use the Firebase authentication for the API.

Here is what the final process should look like:

  1. User logs into an web-interface with the standard Firebase Authentication process.
  2. User clicks on something like "Request API Key" and gets a key shown in the web-interface (e.g. abc...). that is generated by Firebase Authentication.
  3. User can make requests with e.g. curl to the API Hosted in Google Cloud Functions and just has to set the Authorization Header (Bearer abc...) and the "validation" of that token is handled by Firebase Authentication.

Here is what I already tried to generate the token:

admin.auth().createCustomToken(uid)
.then(function(customToken) {
    console.log(customToken);
})
.catch(function(error) {
    console.log('Error creating custom token:', error);
})

And then set the Token logged to the console in Postman as Bearer Token, and then use the following function to verify the token:

const authenticate = async (req, res, next) => {
if (!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) {
  res.status(403).send('Unauthorized');
  return;
}
const idToken = req.headers.authorization.split('Bearer ')[1];
try {

  const decodedIdToken = await admin.auth().verifyIdToken(idToken);
  req.user = decodedIdToken;
  next();
  return;
} catch(e) {
  console.log(e);
  res.status(403).send('Unauthorized');
  return;
}
}

Then I get this error

message: 'verifyIdToken() expects an ID token, but was given a custom token. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.'

I understand that if I would implement an web-interface I could grab the ID token from the devtools (?), but the token is then only valid 1 hour... What I need is a token that is valid "indefinitely" and can be generated and shown to the user.

I think I know that I have to use Custom Tokens somehow but can not figure out how to get them working... (https://firebase.google.com/docs/auth/admin/create-custom-tokens).

Thanks very much in advance everybody!

Best Rick

1

1 Answers

1
votes

You're trying to build an API management solution on top of Firebase and Cloud Functions. Custom tokens and ID tokens are not suitable for this purpose. Custom tokens are only meant to be used as a user authentication credential on end user devices, and ID tokens represent a successful auth response. Both types of tokens expire after an hour.

If you need long-lived, managed API keys, then you will have to implement them yourself. There's nothing built into Firebase that you can use out of the box. I once implemented such a solution as a prototype, where I generated a Firestore document each time a user signed in and requested an API key. Then I used the document ID as the API key, which I could validate in the Cloud Function.

const apiKey = req.headers.authorization.split('Bearer ')[1];
const doc = await admin.firestore().collection('apiKeys').doc(apiKey).get();
if (doc.exists) {
  next();
}

I also had to implement some local API key caching to make this work efficiently.

You might be able to avoid some of this work by using a solution like Google Cloud Endpoints (https://cloud.google.com/endpoints), although I don't have any personal experience with that. Finally, also look at open source solutions like https://wso2.com/api-management/ that enable you to set up your own API key management and gateway.