Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it still possible to do server side verification of tokens in Firebase 3?

Is it still possible to do server side verification of tokens in Firebase 3?

We generate custom tokens (JWT) on a server running Golang using our existing authentication system (using a Service Account). The token is used on an iOS client using

FIRAuth.auth()?.signInWithCustomToken(customToken) 

Until there it all works fine. But when we pass the client token to the server retrieved from:

FIRUser.getTokenWithCompletion({ token, error in ..}) 

we're not able to verify it. The JWT token is signed using RS256 and has an header.kid we can't recognize. The public key from the Service Account (which was used to sign the custom token) doesn't verify the client token. Is the public key needed to validate the client token available?

I know it's possible to validate client tokens using the "verifyIdToken" call in Java or Javascript, but we hope to stil be able to do this in Golang using a standard JWT library.

This all worked fine in Firebase 2 (using HS256 and the Firebase secret).

like image 326
Tim Rob Avatar asked May 24 '16 08:05

Tim Rob


People also ask

How long do Firebase auth tokens last?

Create custom tokens using the Firebase Admin SDK At a minimum, you need to provide a uid , which can be any string but should uniquely identify the user or device you are authenticating. These tokens expire after one hour.

Does Firebase token expire?

Firebase ID tokens are short lived and last for an hour; the refresh token can be used to retrieve new ID tokens. Refresh tokens expire only when one of the following occurs: The user is deleted.

How do you check if a token is valid or not?

There are two ways to verify a token: locally or remotely with Okta. The token is signed with a JSON Web Key (JWK) using the RS256 algorithm. To validate the signature, Okta provides your application with a public key that can be used.


1 Answers

The short answer is yes. The full answer is that, in most cases, we have a more appropriate tool now. So a lot depends on the use case you are trying to resolve.

The new SDK version is quite a bit more powerful, and we haven't done a great job of summarizing the capabilities. This seems like a good place to contrast the tools available and their uses, and then I'll tack on some third-party (i.e. Go) specific notes at the end.

Using an external authentication tool for client authentication

The primary use of minting custom tokens is to allow users to authenticate against an external/legacy auth mechanism you control, such as your LDAP server. The basic process for this is covered here: iOS, Android, Web.

Essentially, your service just mints the JWT token and passes this to the client. The client does the verification/authentication using the custom token you provide.

Authenticating your privileged workers

It's no longer necessary to use custom tokens to authenticate your server process. This is done by creating a service account, which is covered step-by-step in Adding Firebase to your Server. When done, you'll end up with a JSON file that contains a private key.

Then, you include your service account credentials by referencing that JSON using the serviceAccount attribute in firebase.initializeApp(), and you're in! That's documented here and looks like this (see link for Java version):

var firebase = require("firebase");  // Initialize the app with a service account, granting admin privileges firebase.initializeApp({   databaseURL: "https://databaseName.firebaseio.com",   serviceAccount: "./serviceAccountCredentials.json" }); 

Emulating users or limiting access from a server process

It's fairly trivial to emulate a user or to limit access (highly recommended) from a server process. You don't really need to mint a custom token for this anymore.

This just requires adding the databaseAuthVariableOverride into your call to database.initializeApp():

firebase.initializeApp({   databaseURL: "https://databaseName.firebaseio.com",   serviceAccount: "./serviceAccountCredentials.json",   databaseAuthVariableOverride: {     uid: "my-service-worker-or-user-uid"   } }); 

Validating client identity via security

First of all, you can usually avoid dealing with server-side verification if you are using Firebase Database, by having your client write to the database and using security rules to validate their identity. If your server listens on a path that requires authentication to write into, then this is already solved without any special security at the server.

By modeling this as an event queue, it creates a simple, modular, and scalable server worker strategy. See firebase-queue for some great Node.js tools. It supports 3.x.

Verifying client ID tokens on the server

If you aren't using the Realtime Database and need to receive client tokens (e.g. via REST calls) and verify that they are valid, you can do so by using verifyIdToken() as described here. This would look like the following:

auth.verifyIdToken(idToken).then(function(decodedToken) {   var uid = decodedToken.sub; }); 

If you then want to authenticate as that user to write to the database and enforce security, you would use the Emulating Users section above. In other words, call initializeApp() with a databaseAuthVariableOverride set to the appropriate uid.

Note that, if you try to call initializeApp() multiple times and run into an error similar to the following: Error: Firebase App named '[DEFAULT]' already exists. You can initialize multiple app contexts by adding a second argument to the initializeApp() call (e.g. database.initializeApp({...}, 'asUser'+uid)) and then reference that app instance by using firebase.database('asUser'+uid).ref(...). To read more on using multiple app instances, look here.

Java code available at the links above. Go and other third party solutions covered below.

Creating a token for use in the REST API

Michael Bleigh covered this scenario here and deserves some rep for working this out.

Creating tokens or verifying them via REST

This isn't supported. Sorry.

Golang and others: More to come

We're working on a Go token minting and verification library. We'll also be adding Python tools for this soon as well. No release date or ballparks for this. In the mean time, if you'd like to verify client ID tokens without using the official Firebase Node.js or Java libraries (which have built-in verification methods), you will need to ensure the ID token (which is a JWT) conforms to the following:

  • Its decoded header has an alg (algorithm) claim equal to "RS256".
  • Its decoded payload has an aud (audience) claim equal to your Firebase project ID.
  • Its decoded payload has an iss (issuer) claim equal to "https://securetoken.google.com/<projectId>".
  • Its decoded payload has a non-empty string sub (subject) claim. Note that this is the uid for that Firebase user.
  • Its decoded header has a kid (key ID) claim that corresponds to one of the public keys listed at https://www.googleapis.com/robot/v1/metadata/x509/[email protected].
  • You also need to use a JWT library to verify the token with the public key to prove the token was signed with the public keys' corresponding private key.

For Go, it looks like you can use jwt-go to decode and validate the client ID token.

like image 162
Kato Avatar answered Sep 20 '22 19:09

Kato