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).
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.
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.
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.
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:
alg
(algorithm) claim equal to "RS256"
.aud
(audience) claim equal to your Firebase project ID.iss
(issuer) claim equal to "https://securetoken.google.com/<projectId>"
.sub
(subject) claim. Note that this is the uid
for that Firebase user.kid
(key ID) claim that corresponds to one of the public keys listed at https://www.googleapis.com/robot/v1/metadata/x509/[email protected]
. For Go, it looks like you can use jwt-go
to decode and validate the client ID token.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With