DEV Community

Cover image for Using OAuth2.0 and Retrofit to talk to the GitHub api on Android
Tristan Elliott
Tristan Elliott

Posted on • Edited on

Using OAuth2.0 and Retrofit to talk to the GitHub api on Android

2023-10-29 UPDATE!! PLEASE READ

  • If you are targeting Android 12 or up, the below example will not work.
  • Google has now changed the way Web intents are resolved. Please read the documentation, HERE to find out the proper implementation

  • I am planning to make a tutorial, however, if you are reading this I have not created on yet

The code

Introduction

  • I have embarked on my next app, a Twitch client app. This series will be all my notes and problems faced when creating this app.

  • This particular blog post will be us building on the information from the previous blog post and using the authorization code from the GitHub OAuth API in combination with Retrofit. To finally get a access token, which allows us to make requests to the API on a behalf of a user.

Dependencies needed

  • In order to properly use the retrofit we need the following dependencies inside out build.gradle(:app) file:
 //retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.google.code.gson:gson:2.10.1'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

Enter fullscreen mode Exit fullscreen mode
  • depending on when you are reading this, you might need to update the dependencies.

The plan

  • Retrofit can get a little confusing, so I have created a little numbered checklist that both you and I can use when we are working with Retrofit:

1) Find the endpoint

2) Create the response object

3) Create the client interface

4) Create the Retrofit instance

5) Create the Repository

6) Collect the response

1) Find the endpoint

  • The first thing that we need to do is to read Github's documentation and find the endpoint we need to make a request to. Per the documentation, we find out that the endpoint is a POST request to https://github.com/login/oauth/access_token. We also find out that the post request takes in 3 input parameters. client_id,client_secret and code. All of which we got from my previous tutorial
  • IMPORTANT: after reading the documentation, the request takes a header, Accept: application/json. This header will make the request return in JSON. If we do not provide this header, we will get a MalformedJsonException.
  • We can also see from the documentation the returned JSON form is:
{
  "access_token":"gho_16C7e42F292c6912E7710c838347Ae178B4a",
  "scope":"repo,gist",
  "token_type":"bearer"
}
Enter fullscreen mode Exit fullscreen mode
  • this is also an important information, because it determines what our response object will look like.

2) Create the response object

  • When we make a request with Retrofit, the response will be sent to our application in JSON(only if we provided the Accept: application/json header). We then to be able to take that JSON response and convert it to a Kotlin object. This process involves two parts,

1) GSON Converter Factory(we will see later)

2) Kotlin data class

  • So we can create a data class that will represent the data we want:
data class AccessToken(
    @SerializedName("access_token")
    val accessToken:String,
    @SerializedName("token_type")
    val tokenType:String,
)
Enter fullscreen mode Exit fullscreen mode
  • As you can see the annotations are used to determine which JSON field they belong to. I would also like to point out that this data class can be named anything, I simply chose AccessToken because it sounded appropriate.

3) Create the client interface

  • Now we can create an interface that Retrofit will use to send a Http request to our desired endpoint:
import retrofit2.http.POST
import retrofit2.Response
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.Headers

interface GitHubClient {

    @Headers("Accept: application/json")
    @FormUrlEncoded
    @POST("login/oauth/access_token/")
    suspend fun getAccessToken(
        @Field("client_id") client_id:String,
        @Field("client_secret") client_secret:String,
        @Field("code") code:String,
    ):Response<AccessToken>

}

Enter fullscreen mode Exit fullscreen mode
  • I believe the code is fairly self explanatory, however, I do want to point out our use of the suspend keyword. As the code will not work without it and throw an exception. Also, notice that we are only using part of the URL(the endpoint), login/oauth/access_token/. We will define the base of the URL when we create the Retrofit instance

4) Create the Retrofit instance

  • The Retrofit class will be used to create an implementation of our GitHubClient and allow us to use it to create requests. We will also use the GsonConverterFactory to convert the response into our AccessToken class. We will create a Retrofit instance like so:
object RetrofitInstance {
    private val retrofits by lazy{
        Retrofit.Builder()
            .baseUrl("https://github.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
    val api:GitHubClient by lazy {
        retrofits.create(GitHubClient::class.java)
    }

}
Enter fullscreen mode Exit fullscreen mode

5) Create the Repository

  • Now we can create a repository class that will access the RetrofitInstance and make a request to the GitHub API.
class GitHubRepo {

    suspend fun getAuthCode(
        clientId:String,
        clientSecret:String,
        code:String
    ):Response<AccessToken>{

        return RetrofitInstance.api.getAccessToken(clientId, clientSecret, code)
    }
}

Enter fullscreen mode Exit fullscreen mode

6) Collect the response

  • Now we can create a ViewModel and have a method that calls the method on our GitHubRepo and makes the request:
class HomeViewModel(
    val gitHubRepo: GitHubRepo = GitHubRepo()
): ViewModel(){

fun makeGitHubRequest(clientId:String,clientSecret:String,code:String) = viewModelScope.launch{
        val data = gitHubRepo.getAuthCode(
            clientId=clientId,
            clientSecret = clientSecret,
            code = code
        )
        if(data.isSuccessful){
            Log.d("GITHUB",data.body().toString())

        }else{
            Log.d("GITHUB", "NOT SUCCESSFUL")
        }
    }

}

Enter fullscreen mode Exit fullscreen mode
  • with that we should be able to see our access_token, which we can then use to make requests on the user's behalf.

What's next?

  • In the next tutorial I will clean up the code, put it in the proper architectural format. Also, we will use the access_token to make requests on the user's behalf and some good ole fashioned exception handling.

Conclusion

  • Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.

Top comments (0)