Google APIs OAuth in Django
Tags: django, webdev, python, codenewbie
Published: 2020-10-09 00:06:57

Making an authentication system with google sign-in is a relatively simpler task to do. It can be easily done using Firebase authentication. But the problem comes when we need to access Google APIs of our users such as Google Calendar, Gmail, Drive etc. The main problem is getting the user tokens and storing them. So, that our application can access the Google APIs of the user once they've granted the access and not asking them to authenticate again and again.

So, here is how you can integrate Google OAuth with your Django application and retrieve, store the user tokens. Which can be used to create authenticated requests to Google APIs through `google-api-python-client`.

## Objective
In this article, I am going to show you how you can integrate Google OAuth with your Django application and store the user tokens for future use, accessing the Upcoming Events in the user's Google Calendar using the stored credentials.

## Prerequisites
I'm going to assume that you've already created a project in [Google API Console](https://console.developers.google.com/), enabled the Google Calendar API for your project, setup an OAuth consent screen and you have a `client_id.json` file.

I'm also assuming that you have already initialized a django application.

## Let's Start

First of all, you need to install `google-apis-oauth-django` to setup oauth and `google-api-python-client` to access Google APIs using the following command.

```bash
pip install google-apis-oauth-django google-api-python-client
```

First of all create a `Sign In With Google` button that redirects users to an url say `google_oauth/redirect/`. First you need to create a view for redirecting users. In your `views.py` add the following code.

```python
import os
import google_apis_oauth

from django.shortcuts import HttpResponseRedirect

# The url where the google oauth should redirect
# after a successful login.
REDIRECT_URI = 'http://localhost:8000/google_oauth/callback/'

# Authorization scopes required
SCOPES = ['https://www.googleapis.com/auth/calendar']

# Path of the "client_id.json" file
JSON_FILEPATH = os.path.join(os.getcwd(), 'client_id.json')

def RedirectOauthView(request):
    oauth_url = google_apis_oauth.get_authorization_url(
        JSON_FILEPATH, SCOPES, REDIRECT_URI)
    return HttpResponseRedirect(oauth_url)
```

Now in your `urls.py`, You can include this view by doing something like

```python
urlpatterns = [
    ...,
    path('google_oauth/redirect/', RedirectOauthView)
]
```

Now when a user clicks on that `Sign In With Google` button they would be redirected to a google oauth screen. After a successful login they would be redirected to the `REDIRECT_URI` that we have specified above i.e. `google_oauth/callback/`.

So, we need to write a view for that as well. In that view we can now successfully retreive the user credentials as they are successfully authenticated by doing something like this.

```python
def CallbackView(request):
    try:
        # Get user credentials
        credentials = google_apis_oauth.get_crendentials_from_callback(
            request,
            JSON_FILEPATH,
            SCOPES,
            REDIRECT_URI
        )

        # Stringify credentials for storing them in the DB
        stringified_token = google_apis_oauth.stringify_credentials(
            credentials)

        # Store the credentials safely in the DB
        ...

        # Now that you have stored the user credentials you
        # can redirect user to your main application.
        ...
    except exceptions.InvalidLoginException:
        # This exception is raised when there is an inavlid
        # request to this callback uri.
```

Adding this view in the `urls.py`.

```python
urlpatterns = [
    ...,
    path('google_oauth/callback/', CallbackView)
]
```

Now, as you have the user's credentials. You can access the Google APIs by the following method.

```python
import google_apis_oauth
from googleapiclient.discovery import build

# Load the stored credentials in a variable say 'stringigied_token'

# Load the credentials object using the stringified token.
creds = google_apis_oauth.load_credentials(stringified_token)

# Using credentials to access Upcoming Events
service = build('calendar', 'v3', credentials=creds)
now = datetime.datetime.utcnow().isoformat() + 'Z'
print('Getting the upcoming 10 events')
events_result = service.events().list(
    calendarId='primary', timeMin=now,
    maxResults=10, singleEvents=True,
    orderBy='startTime').execute()
events = events_result.get('items', [])

if not events:
    print('No upcoming events found.')
for event in events:
    start = event['start'].get('dateTime', event['start'].get('date'))
    print(start, event['summary'])
```

That's it! Similarly you can use these credentials to access other Google APIs as well.