Firebase Auth with Ktor backend

Yev Kanivets
xorum.io
Published in
4 min readFeb 28, 2021

Firebase is usually considered a substitute for a "real" backend, mainly used by mobile teams to ship POC / MVP solutions without hiring backend developers and adding another technology (complexity) into a stack.

With the emergence of Ktor, it's now possible to write a real independent backend in Kotlin, which is widely popular among Android developers. See Backend for mobile engineers with Kotlin and Ktor for more details.

Does it mean that Firebase can't be useful for mobile development anymore? Of course, it doesn't! In this article, we will see how a few weeks of backend work can be saved using Firebase Authentication (free) feature.

Firebase Authentication provides backend services, easy-to-use SDKs, and ready-made UI libraries to authenticate users to your app. It supports authentication using passwords, phone numbers, popular federated identity providers like Google, Facebook and Twitter, and more.

Authentication with Ktor

Authentication is one of the most common features in any application, hence any backend. It's essential to know who is doing what and restrict access to users' data and actions.

Official Ktor documentation says:

Ktor supports authentication out of the box as a standard pluggable feature. It supports mechanisms to read credentials, and to authenticate principals.

Where the principal is something that can be authenticated: a user, a computer, a group, and credentials can be user/password combination, token, etc.

Once you add the dependency for ktor-auth in your build.gradle, you need to install Authentication feature directly to the application, and configure it.

This is an example from the Codeforces WatchR project's backend, which tries to replicate the famous "Bearer token" authentication with a unique token generated and mapped for every user.

Then we wrap routes, which need authentication with theauthenticate(auth) call (in our case user() endpoints). It's also needed to implement a separate set of routes for Sign In / Sign Up to generate bearer tokens (auth()).

To get the token in authenticated calls use call.request.headers["token"].

The complexity of the auth flow

As a mobile engineer, I had never thought about how complex the authentication flow can be from the backend side. It was taken for granted because we always had endpoints at our disposition.

But when we started to write backend ourselves, we confronted with so many complexities, including, but not limited to:

  • secure and reliable tokens generation, which isn't as simple as UUID.randomUUID()But may require a complicated setup and business-logic (see JWT and JWK documentation)
  • tokens rotation and refresh, so if they get exposed, hackers won't get life-long access to user accounts
  • 3rd party authentication using OAuth to be able to login with Google, Facebook, Apple, Twitter, GitHub, and so on
  • admin capabilities for managing authenticated users, resetting passwords, blocking fraudsters, etc.

With all these points coming up, we made 2 conclusions:

  • Backend developers deserve respect for dealing with all this mess 🙏
  • We don't want to handle it ourselves 😅

Authentication with Firebase

Fortunately, Firebase uses JWT authentication under the hood and gives access to bearer tokens from both admin and client SDKs. It means that you can delegate the whole authentication flow to Firebase and use generated tokens to authenticate users on your backend.

So you do implement Firebase Authentication exactly how you did before on the client-side (Android / iOS / Web) with the only addition of getting the JWT token from Firebase to attach to all your requests.

If you are using Ktor on the client-side as well (which I highly recommend), you can add an authorization header directly to HttpClient.

The only thing left is to check the Authorization header on the backend, which can be done quite easily thanks to https://github.com/desmondtzq/ktor-auth-firebase open-source project.

The project seems to be not supported very actively, so I recommend to copy/paste the FirebaseAuth.kt to your backend as it's the only source-code file there 😉

Also, you will need to add firebase-admin and ktor-auth dependencies to the build.gradle, which is expected. Now you can use Firebase Auth with Ktor backend and protect routes with authenticate("firebase").

FirebasePrincipal is a data class with a single field userId, and inherited from Principal from io.ktor.auth. But don’t forget to initialize Firebase Admin SDK. Otherwise, the project won’t compile.

This tiny extension will help you to get userId in any authorized endpoint by calling call.userId, which is very convenient.

Bottom line

Ktor is a flexible modular backend (and frontend) framework, which allows you to integrate many 3rd party solutions in a matter of hours to simplify life and save time for more creative tasks.

Firebase Authentication plays really nice with the Ktor backend and gives mobile developers the flexibility of having their own backend logic with old-good exhaustive APIs for authentication on mobile.

Featured in Kotlin Weekly #243 and .droidcon online webinar series.

--

--

Yev Kanivets
xorum.io

Technical Lead Mobile @ 360Learning | KMP enthusiast | Husband & dad | Marathon finisher