How To Authorize a User Using the GitHub OAuth API , Python and Flask: Part Two.
Build and Test the Application Locally.
In the previous article, we set up the development environment. In this article we will build and test the application locally. So what exactly does the application do and how does it work? For a start, it simply allows us to register and authenticate a user. Rather than coming up with a new username and email address, our users use the information already held by GitHub to register and authenticate.
This application has two parts:
- User Registration for new users
- User authentication for returning users
For this series of articles we will simply authenticate a user and later on we will create a registration module. For the application to work, we need a client id and client secret both of which are given out by GitHub once you register your app with them. Once those two are obtained:
- We start by sending out a GET request to
https://github.com/login/oauth/authorize?client_id=client_id
with the client id given earlier on; - Then GitHub sends back a
request token
to acallback URL
that was specified during registration; - Using this request token, the client id and client secret, we can then send a POST request to
https://github.com/login/oauth/access_token?client_id=client_id&client_secret=client_secret&code=request_token
to get an access token; - Using the access token, we send a GET request to
‘https://api.github.com/user'
to get the users data.
The application will have three routes:
- The
/index
route for testing out the application. Accepts GET requests and serves out JSON response of the form:
- The
/home
route that serves out the home page. This contains a button that a user can click to start the authentication process.
- The
/github/callback
route that handles the authentication. Shows a prompt to the user to authorize our application then displays the user data on a dashboard:
Application registration
Head on over to GitHub OAuth and register a new application:
Set the Application name to any name that you want, the Homepage URL as http://127.0.0.1:5000 and Authorization callback URL as http://127.0.0.1:5000/github/callback. After registering the application, in the resulting page, click on the Generate a new client secret button.
Create a .env
file at the project root and add the following:
CLIENT_ID=xxxxxxxxxxxxxxx
CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
The Application Design
The main focus of this application is the back-end design, so little consideration is given to the front-end. We will have two main functions:
get_request_token()
that will take in aclient id
,a client secret
andan access token
and give us back arequest token
get_user_data()
that will take in arequest token
and give ususer data
. Once we have theuser data
we can then get the user data and display them on a simpledashboard
.
The application requirements
Open up requirements.txt
and add the following project requirements. The flask
module is used to build the API, the requests
module will be used to make requests to the GitHub API, python-dotenv
will be used to load environment variables while gunicorn
will be used in production to run our application:
Then open up requirements-dev.txt
and add the following:
Commitizen
will be used to format our commit messages, pre-commit
will be used to run our pre-commit hooks at every commit and pytest
will be used to test our code. Add the following to the Makefile
:
The Makefile
simplifies our commands. The four make targets update the pip utility, install production requirements, install development requirements, runs the application and tests the application respectively. Create a file named setup.cfg
at the project root and add the following:
This file provides configuration for the flake8
and isort
tools that are used to ensure code quality. More on them in a different tutorial. Create another file named .pylintrc
at the project root and add the contents of this .pylintrc file.
This file contains configurations for the pylint
tool. Add the following to pytest.ini file
:
This file provides configuration for pytest
.
The index route
Start by creating the following tests for the index route; the conftest.py
that will hold configurations for our tests:
For testing the index route, we will have two unit tests under the tests/unit/test_index.py
:
- One tests to assure us that on a GET request to the index, we get a response code of 200 indicating the request was successful.
- The other test assures us that in case a method other than GET such as POST results in a 405 method not allowed error.
To run the tests we will install the project requirements then use Make
to run them. The pytest
configuration are found in the pytest.ini
file shown above, while for flake8
and isort
, setup.cfg
configures them. The .pylintrc
file configures the pylint
tool; all these tools will be run against our codes at each commit. At the command-line:
make install
make install-dev
make test
The tests will fail,so let us create the application for them; in the API/__init__.py
file, add the following:
Then in the API/routes.py
add the following:
We also need some environment variables that will be used by the flask application i.e the FLASK_ENV and FLASK_APP. Open the .env
at the project root and add the following:
Now try running the tests and they will pass:
make test
The home route
For testing the /home route
and /github/callback
functionality, we will have to mock the GitHub API. I will go through that in a different post. Check out the API/tests
folder for the other tests. For now let’s just write out the code for the home route:
For the application to run, we have to supply the client id and client secret. For that, let us create the application configuration. Open API/config.py
and add the following:
This file loads configuration from environment variables. The values are loaded form the .env
file using the load_dotenv()
function from the dotenv
module. The variables include:
- CLIENT_ID that we obtained earlier on from GitHub.
- CLIENT_SECRET that we also obtained earlier on.
Now create the template used to render the home page. Create a folder named templates
within the API
folder, then create a file named home.html
and add the following:
This template will be rendered when the /home
route is accessed. It is passed the client id, which forms part of the URL accessed when the GitHub Login
button is pressed. To run the application, create a file called manage.py at the project root and add the following:
At this point, run the application.
make run
and access the /home
endpoint. The home page is rendered:
The callback route
Next, we create the callback route, /github/callback
that will authenticate the user and display their information. Add the following to API/routes
:
There are two methods that need creation, get_access_token()
and get_user_data()
. Open API/helpers.py
and add the following:
To display the user data, the /github/callback
route renders a dashboard using the user data obtained from GitHub. Create a dashboard.html
file in the API/templates
folder and add the following:
At this point, the application is ready to run. At the command-line start the application and then navigate to http://127.0.0.1:5000/home. Click on the GitHub Login button, then authorize the application. You will then be redirected to the callback route that displays your user data:
And that’s it, you have successfully used the GitHub OAuth API to authenticate a user. To finish it off, let us push the code to GitHub;
git add .
git commit -m “feat: created and deployed the auth app locally.”
This will probably create errors, due to the pre-commit hooks that we set up in the previous article. In case they inconvenience your workflow, just disable them from the .pre-commit-config.yml
file, by commenting them out. Otherwise just correct the errors indicated and re-run the above commands until no more errors appear. Then push your code to GitHub:
git push
Create a pull request against the development branch and merge it. In this part two of the series:
- We described how to authorize a user using the GitHub OAuth API.
- We created an app with the GitHub OAuth API.
- We then created three routes for implementing user authentication using the GitHub OAuth API.
- We tested and deployed the application locally.
In the next article, the code will be deployed to Heroku. The code for this application is here github-oauth-app. I am Lyle, a junior software engineer with a passion for developing, testing and deploying scalable services. You can find me on twitter, linkedin, github and here’s my portfolio. See you next time.