Table of contents
- What is OAuth2.0
- Setting up GitHub
- Getting started code
- Sending request to GitHub
- Receiving a response from GitHub
- Resources I used for this post
- Why am I not using AppAuth
The code
Update
- If the device you are targeting is running Android 12 or up, this tutorial will not work. Please read the official documentation on Web intent resolution, HERE, for modern implementation
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 only be us getting the
Authorization code
from GitHub. In the next tutorial we will exchange theAuthorization code
for a token which we can use to make requests.
What exactly is OAuth2.0?
If you are unfamiliar with what OAuth2.0 is or what it is trying to accomplish then I suggest you watch THIS video. Just make sure to watch it in 2.0x speed as it is a little longer.
For you visual learners I have this graph:
1) Client app opens a browser tab with the authorization request.
2) Authorization endpoint receives the authorization request,
authenticates the user, and obtains authorization.
3) Authorization server issues an authorization code to the
redirect URI.
4) Client receives the authorization code from the redirect URI (This blog post will only be covering up to this point)
5) Client app presents the authorization code at the token endpoint.
6) Token endpoint validates the authorization code and issues the tokens requested.
- I stole this graph from the Internet Engineering Task Force's paper on
OAuth 2.0 for Native Apps
, which can be found HERE. I highly recommend you read this paper a few times. Even after I write this blog post, I am going to reread it.
Setting up GitHub
- The first thing we need to do is head over to GitHub's developer settings, found HERE and create a new OAuth app. It should look something like this:
What I really want to draw your attention to is the
Authorization callback URL
. Technically speaking, it can be whatever you want. When the user successfully login through the Android browser app, it will send out a Implicit Intent to the Android OS and our app will use an Intent filter in combination with the callback URL to tell the Android OS that our app will be able to handle it. If that sounds confusing don't worry, it will makes sense once we start coding.Upon successful completion of your GitHub OAuth application you will be given access to the application's
Client Id
(Public identifier) andClient Secret
(Private Identifier). We will need both of these to handle make a request.
WARNING!!!! : you should never store the Client Id or Client Secret in a public repository.
Lets code
- Enough Talk, Lets code!!!!! Step one is to create a intent filter. We use an intent filter anytime we want to handle an implicit intent. If you are unfamliiar, an Intent is really just an abstract description of an operation to be performed. A implicit intent is just an Intent but it does not have a specific component specified
- Anytime there is an implicit intent, the Android system will search all apps for an intent filter that matches the intent. When the match is found, the system starts the matching activity.
- The intent filter will look something like this:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="callback"
android:scheme="whateveryourauthcallbackwas"
/>
</intent-filter>
The action android.intent.action.VIEW display's data to our app, gives us access to the
getData()
methodthe category android.intent.category.DEFAULT is set to state there is action to perform on the data
the category android.intent.category.BROWSABLE tells our app that this activity can be safely invoked from a browser
the
data
declares the type of the data accepted. Through the scheme and host, we are defining what sections of the response URI we want. For example:<scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>|<pathAdvancedPattern>|<pathSuffix>]
. By only defining the scheme and host. The response from GitHub will be something like this:urcallbackurl://callback?code=435974357435437
. The random collection of numbers is the Authorization code, which we will use to exchange for a token from GitHub in the next tutorial.
Sending a login Request to GitHub
- We actually don't want our app to know anything about the user's username and password. We are going to follow the
principle of least privilege
, which just means our app should only have information it needs. To accomplish this we are not going to login through our app, we are actually going to login through the Android's browser. How do we do this? We create and send out a implicit intent to the Android system. The intent will look like this:
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/login/oauth/authorize?client_id=$clientId&scope=repo&redirect_url=$redirectUrl")
)
- A better explanation of how to invoke a web browser with android HERE
- We are getting the information about what endpoint to hit through the documentation, found HERE
The
client_id
, andredirect_url
will be specific to your application.To make the actual request we can do something inside the onCreate() method like this:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val clientId = "yourclientId"
val redirectUrl = "yourredirecturl://callback"
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/login/oauth/authorize?client_id=$clientId&scope=repo&redirect_url=$redirectUrl"))
setContent {
Button(onClick={startActivity(intent)}) {
Text("Login with github", fontSize = 30.sp)
}
}
}
- The code above will create an intent and open the Android's browser making the user login. Upon a successful login the user will be redirected to our app, prompting the onResume() method to be called
Receiving a response
- Technically speaking, we are going to be receiving an implicit intent and we have already set up the intent filter to do just that. But now we have to get the data from the intent
- To retrieve the response from the intent, we can do so inside the onResume() method:
override fun onResume() {
super.onResume()
val uri:Uri? = intent.data
if(uri != null){
Log.d("GITHUB",uri.toString())
}
}
- Which if the login was successful, we will get the response of:
`urcallbackurl://callback?code=435974357435437`
- As stated earlier:
The random collection of numbers is the Authorization code, which we will use to exchange for a token from GitHub in the next tutorial.
- So in the next tutorial we are going to use the
Authorization code
to exchange for a token, which can be used to make requests on the user's behalf. If you are wondering why we have to use a code and then exchange it for a token, I really suggest you watch This video on what OAuth2.0 is
Why am I not using AppAuth?
- You have probably heard about AppAuthAndroid and it seems to be the go to SDK when dealing with OAuth2.0. However, I would like to get a better understanding of OAuth2.0 and have decided to manually implement it manually.
- Also, the documentation is deprecated and has not been updated since May of this year.
Resources:
- GitHub Documenation
- OAuth 2.0 for Native Apps paper by Internet Engineering Task Force
- What is OAuth2.0 video
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)