Using OAuth2.0 and Retrofit to talk to the GitHub api on Android
Tags: android, mobile, kotlin, tristan
Published: 2023-07-10 14:46:19



## 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](https://developer.android.com/about/versions/12/behavior-changes-all#web-intent-resolution) 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
- [GitHub](https://github.com/thePlebDev/Clicker/tree/github)

### Introduction <a name="intro"></a>
- 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](https://dev.to/theplebdev/oauth20-and-android-login-with-github-and-get-the-authorization-code-40n3) and using the `authorization code` from the GitHub OAuth API in combination with [Retrofit](https://square.github.io/retrofit/). To finally get a `access token`, which allows us to make requests to the API on a behalf of a user.

### Dependencies needed <a name="need"></a>
- 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'

```
- depending on when you are reading this, you might need to update the dependencies. 

### The plan <a name="plan"></a>
- 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 <a name="endpoint"></a>
- The first thing that we need to do is to read [Github's documentation](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps) 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](https://dev.to/theplebdev/oauth20-and-android-login-with-github-and-get-the-authorization-code-40n3)
- **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"
}
```
- this is also an important information, because it determines what our response object will look like.


###2) Create the response object <a name="response"></a>
- 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,
)
```
- 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 <a name="client"></a>
- 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>

}

```
- 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 <a name="instance"></a>
- 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)
    }

}
```

### 5) Create the Repository <a name="repo"></a>
- 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)
    }
}

```
### 6) Collect the response <a name="collect"></a>
- 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")
        }
    }

}

```
- 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? <a name="next"></a>
- 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](https://twitter.com/AndroidTristan).