Token-based authentication & REST API Implementation for Android|Kotlin apps

Hirunika Karunathilaka
6 min readOct 7, 2021

--

Let’s see what is covered in this article series,

  • Ways to implement REST API in android | Kotlin
  • Token based authentication with Fuel
  • Token based authentication with Retrofit
  • Implement REST API service in android
  • Handle token expiry problem
  • Error handling for API calls
  • Structure project with MVVM pattern
  • Display response in view

When developing mobile applications, we have to communicate with the backend server to fetch resources that needs to be displayed in the mobile app. This process can be done by implementing REST APIS in android.

So, as the first phase, I will describe some ways you can use to implement this feature in your android app.

Ways to implement REST API in android | Kotlin

If you are not a fan of client libraries or wrappers, of course you can create your own implementation to connect with the backend resources. For this you can experiment with HttpUrlConnection or OkHttp and create a URL connection to work with.

But using a client library will make your work easy and overall it will support a complete functionality. Let’s see some REST clients we can use for this purpose.

Fuel Http Library

Fuel is a HTTP networking library developed for Android Kotlin projects. Since there are somewhat less amount of support for Kotlin, this is a good library to get your work done.

Fuel uses the HttpsURLConnection for HTTP requests

Retrofit Http Client

Retrofit is a REST Client for Java and Android. It makes it relatively easy to retrieve and upload JSON via a REST based webservice.

In Retrofit you configure which converter is used for the data serialization. Typically for JSON you can use GSon, but you can add custom converters to process XML or other protocols.

Retrofit uses the OkHttp library for HTTP requests.

As you can see, above two client libraries use two different underline libraries to make the HTTP requests. So these acts as wrappers for making the http connection for our network calls.

In this article I will discuss an implementation on how to retrieve an access token from an API management platform and how to use that token for subsequent api calls. Here, I will use the Retrofit library for that purpose.

However for those who wish to use Fuel, I will also share a sample code snippet and will discuss briefly about the flow.

But to get started in either way, you should create a basic android application and select Kotlin as the programming language.

Token based authentication with Fuel

Create a separate folder (“auth”) for handling the authentication and api configuration activities.

Create a class like ApiService as in here to basically get the token and test out the api calls.

Create a model class like AuthResult as in here to provide the response structure we are expecting when we retrieve the access token.

In addition to that we have to add the Fuel library dependency in the app/build.gradle file as below.

Also add the dependency for Gson to convert the api response to our AuthResult class.

//build.gradle(:app) filedependencies {
....
....

implementation 'com.github.kittinunf.fuel:fuel:2.3.1'
implementation 'com.google.code.gson:gson:2.8.8'
}

Since we are calling the backend api using internet , we need to give the permission for that in the AndroidManifest.xml file. Add below sentence before application tag.

<uses-permission android:name="android.permission.INTERNET" />

Since I’m trying to get the access token from an API management platform (like Apigee), I should have the required client Id, client secret and the required token url to call. As the grant type mechanism, we should use the “client_credentials” grant type.

But if you are trying to get an authorization token through user login as such , you can go for more advanced grant type mechanisms like through “Authorization code”. Then the flow will be bit different. You can research on this.

Let’s add content to AuthResult model class. Below are some properties that will be returned when calling my access token url. You can use postman or curl to send a request to your token url and know about the response of your api call beforehand.

package com.example.kotlintestapp.auth

data class AuthResult(
var access_token: String? = null,
var expires_in: Number,
var token_type: String? = null
)

Let’s add a function to get the access token in ApiService kotlin class.

package com.example.kotlintestapp.auth

import com.github.kittinunf.fuel.core.extensions.authentication
import com.github.kittinunf.fuel.httpGet
import com.github.kittinunf.fuel.httpPost
import com.github.kittinunf.result.Result
import com.google.gson.Gson

import java.lang.Exception

class ApiService {
private val clientId = "" //add your client id
private val clientSecret = "" //add your client secret
private val apigeeTokenUrl = "" // url to get the token
private val grantType = "client_credentials"

var token: String? = null
var tokenType: String? = null


private fun setAuthToken() {
try {
val (request, response, result) = apigeeTokenUrl.httpPost(listOf(
"grant_type" to grantType,
))
.authentication().basic(clientId, clientSecret)
.responseString()

when (result) {
is Result.Success -> {
var gson = Gson()
val tokenResultJson = gson.fromJson(result.value, AuthResult::class.java)
token = tokenResultJson!!.access_token!!
tokenType = tokenResultJson!!.token_type!!
Log.d(ContentValues.TAG, "token $token")
Log.d(ContentValues.TAG, "token type $tokenType")
}
is Result.Failure -> {
// handle error
}
}

}catch (e: Exception){
e.printStackTrace()
}
}

init {
setAuthToken()
}
}

Whats happening in the above function is when we load the AppService, it calls the setAuthToken method. Then it makes a http POST request to the apigee token url by setting the authentication header and grant type.

.authentication().basic(clientId, clientSecret)

Inside this above sentence, it encodes the client id and client secret together(“clientId”+”:”+”clientSecret”) to the base 64 and attach it to the request header.

If the result is a success, we can convert the result to our AuthResult class and assign the token and token type value in the class. But for the use of future api calls, it is a good to store the token in the sharedPreferences. Although if we save the token in the sharedPreferences, after the token expiry time, we need to refresh the token again. Stay tuned !!! we are going to address that issue in this article.

Let’s run the above code snippet. So you can call this class from the MainActivity in the onCreate function just to test.

override fun onCreate(savedInstanceState: Bundle?) {
val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
StrictMode.setThreadPolicy(policy)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
ApiService()

}

Debug the app (shift + F9). If there are no issues with the network call, you will see the logs in the debug console.

Now we have the token information with us. Let’s test a GET api call by setting our received token. You can add this function to the same ApiService class for testing purpose.

package com.example.kotlintestapp.auth

import android.content.ContentValues
import android.util.Log
import com.github.kittinunf.fuel.core.extensions.authentication
import com.github.kittinunf.fuel.httpGet
import com.github.kittinunf.fuel.httpPost
import com.github.kittinunf.result.Result
import com.google.gson.Gson

import java.lang.Exception

class ApiService {
private val clientId = "" //add your client id
private val clientSecret = "" //add your client secret
private val apigeeTokenUrl = "" // url to get the token
private val grantType = "client_credentials"

var token: String? = null
var tokenType: String? = null

private fun callApi(apiEndpoint: String, tokenType: String, token: String): Any {
val (request, response, result) = apiEndpoint
.httpGet()
.header(Pair("Authorization", "$tokenType $token"))
.responseString()

return when (result) {
is Result.Success -> {
Log.d(ContentValues.TAG, "Success ${result.value}")
}
is Result.Failure -> {
Log.d(ContentValues.TAG, "Failed")
}
}
}


private fun setAuthToken() {
try {
val (request, response, result) = apigeeTokenUrl.httpPost(listOf(
"grant_type" to grantType,
))
.authentication().basic(clientId, clientSecret)
.responseString()

when (result) {
is Result.Success -> {
var gson = Gson()
val tokenResultJson = gson.fromJson(result.value, AuthResult::class.java)
token = tokenResultJson!!.access_token!!
tokenType = tokenResultJson!!.token_type!!
Log.d(ContentValues.TAG, "token $token")
Log.d(ContentValues.TAG, "token type $tokenType")

}
is Result.Failure -> {
// handle error
println("error")
}
}

}catch (e: Exception){
e.printStackTrace()
}
}

init {
setAuthToken()
callApi("https://...../getUsers", tokenType!!, token!!)
}
}

In the callApi function, a GET request is sent with a bearer token authorization set in the header. All those are handled by the fuel library for you.

If you want to handle the token expiry issue with Fuel, you can save the expiry time also in the shared preferences in addition to the token and token type. Then once an api call request fails with a 401 response code, you can assume that one reason may be the token has expired. So you can check that and call the “setAuthToken” method again to get a new token and resume the failed api request with the new token.

But with Retrofit client library, there is an easier way to handle that !!!.

You can find the source code from here https://github.com/HirSK/android-api-retrofit.

For this tutorial that’s all folks !!!. We’ll meet in the next chapter to discuss following topics,

  • Token based authentication with Retrofit
  • Implement REST API service in android
  • Handle token expiry problem
  • Error handling for API calls
  • Structure project with MVVM pattern
  • Display response in view

Until then happy coding !!!

--

--