How to Integrate Firebase Authentication with the Ktor Auth Feature

Why not let the experts handle your user management?

Laurence Sonnenberg
Level Up Coding

--

If you’re like me, when developing an application, you know security needs to be a priority; you also know that it takes great depth of security knowledge to develop a solid authentication system that’s good enough to ward off todays attacks. This is why it’s often best left to the experts to develop these sorts of systems — experts like those at Google who have built Firebase’s Authentication system, which is easy to implement and maintain for most small to medium sized apps… whether they be web or mobile.

I’m a huge fan of the Kotlin programming language, so I have recently started building backend applications using the open source, Jetbrains developed framework, Ktor. In this article I’m going to show you how to integrate Firebase Authentication with the Auth feature already provided by the Ktor framework.

We all know that recreating the wheel is often just a waste of developer time, so I have used the current JWT feature code as a starting point and edited it to use Firebase instead of a custom JWT implementation, so I must thank the amazing developers at Jetbrains who wrote the original code… thanks guys! :)

This article assumes basic knowledge of the Ktor framework — if you’d like to learn more about the basics though, there are loads of tutorials covering those topics online! I used quite a few of them when I was getting started recently.

First up we’re going to create a new Ktor project using the IntelliJ IDEA Ktor plugin. We’ll choose which features we’d like to use, and we’ll tell the plugin that we’d like to use the Kotlin Gradle DSL. You can choose how you’d like to deal with content negotiation, I’m using GSON. For the HTTPClient Engine I’m using Jetty, and of course we’ll also need to tick Authentication. I’ve also ticked call logging so I can see what endpoints I’ve called.

Once you’re done choosing features follow the prompts until you have an initialised project. To complete the Ktor setup replace the current build.gradle.kts file with the one below and load the changes.

Now let’s setup our Firebase Project and generate a new private key for the Firebase Admin setup. The Firebase docs are pretty good, so if you’re not sure how to create a Firebase project, head over here to find out. Once you have a new project, navigate to the project settings, then to service accounts. There you can click the generate new private key button.

This will download a json file which you then place in the resources directory of your project, and REMEMBER if you plan to push to a public repo, add it to your .gitignore file!

Great, we’re setup and can start looking at the code :)

First up, let’s add a few more Kotlin files. From your root directory, create the file auth/firebase/FirebaseAuth.kt, then create object files config/firebase/AuthConfig and config/firebase/FirebaseAdmin, and lastly create data class file model/User. Once you’re done your folder structure should look like the image below.

Let’s start with the Firebase Admin code. In the FirebaseAdmin file paste the below code (remember to change the name of the json file to the one you downloaded),

Then add the lineFirebaseAdmin.init() above the feature install code in your Application.kt file. This will use the credentials you downloaded to initialise your Firebase app.

Next up add the following code to your FirebaseAuth.kt file,

The above code supplies an AuthenticationProvider which is then built with the nested Configuration class. This Configuration class provides access to the token and a lambda function (which we will set up later) to supply the Principle (being the User).

Next we have the Authentication.Configuration.firebase extension function which will be doing all the actual work for us. Here we build the AuthenticationProvider, we then use it to setup an interceptor; inside this interceptor, we fetch the token and check that the token is valid. Lastly we invoke the lambda to fetch our Principle, and of course, we do this within a try/catch so that we can catch and handle any errors that might occur.

Now let’s move onto the AuthConfig and User files. The AuthConfig will supply the lambda function to our Configuration so that we can fetch our Principle and the the User file will be our data model.

Notice that our User data class above implements the Principle interface. This is because our Configuration is expecting that type. Once you’ve added the User data class code, add the below code to your AuthConfig file.

The above code supplies an extension function for our Configuration class, and as I mentioned earlier, this then supplies the lambda to fetch our Principle. Lastly we’ll edit our Application.kt file to use all the code we’ve added.

In the above code you can see that when the Authentication feature is installed we’ve used our firebase extension function and handed it our configure extension function. Now when we make any calls to authenticated endpoints, our application will look for a token in the request headers, if found the token will be validated and finally our User data will be added to the call and can be retrieved by calling call.principle<User>().

And with all of this, we can now signup/login with Firebase on our frontend and get a bearer token to use when making secure calls to our backend. We can let Firebase take care of things like refreshing the token, sending email address validation emails and updating a User’s email or password.

I hope this has been useful :) If you’d like the full project code it can be found on my GitHub: https://github.com/Yukigeshiki/ktor-firebase-auth and if you’ve spotted anywhere this can be improved, please let me know in the comments!

--

--