Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Google OAuth Signup in the backend #112

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 32 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,16 @@ Next follow these instructions.
```
python manage.py migrate
```
8. To run the server:
8. To setup Social Auth for backend see [this](#Setup-Social-Auth).

9. To run the server:
```
python manage.py runserver
```
9. Navigate to `http://localhost:8000/` in your browser.
10. To change the port you may run `python manage.py runserver <port_number>`
11. To run the migrations run: `python manage.py migrate`
12. You can terminate the process by `Ctrl+C` in your terminal.
10. Navigate to `http://localhost:8000/` in your browser.
11. To change the port you may run `python manage.py runserver <port_number>`
12. To run the migrations run: `python manage.py migrate`
13. You can terminate the process by `Ctrl+C` in your terminal.

Follow the given instructions for Login into the app.

Expand Down Expand Up @@ -133,21 +135,39 @@ Add it to your .env file as follows:
```
export SENDGRID_API_KEY=<your-sendgrid-api-key>
```
3. `GOOGLE_CALLBACK_URL` - For using Google authentication the **Callback URL** is required by Google API. Add this env variable in `.env` file or export it to use **Callback URL** which you used while setting Up Google App. The default value is: `http://localhost:3000/login`.

4. `SECRET_KEY` - This environment variable is required for running the backend. Add `SECRET_KEY` in `.env` file or export it by using `export SECRET_KEY=<YOUR SECRET KEY>`.

5. `DB_BACKEND` - This environment variable is used here to get the the backend class of the database. Different databases have different backends in django. You can read more about it [here](https://docs.djangoproject.com/en/3.1/ref/databases/). Its default backend is postgresql.

6. `DB_NAME` - This environment variable is required to get the name of the database. By default, its value is `osp`.

7. `DB_USERNAME` - This environment variable is required to get the **USERNAME** of the user with all privileges to the above mentioned database.

8. `DB_PASSWORD` - This environment variable is required to get the **password** of the above mentioned user i.e. the user with all the privileges to the database.

3. `SECRET_KEY` - This environment variable is required for running the backend. Add `SECRET_KEY` in `.env` file or export it by using `export SECRET_KEY=<YOUR SECRET KEY>`.
9. `DB_HOST` - It is used to get the database host from the env variables. For `docker` it must be set to `db` otherwise its default value is `localhost`.

4. `DB_BACKEND` - This environment variable is used here to get the the backend class of the database. Different databases have different backends in django. You can read more about it [here](https://docs.djangoproject.com/en/3.1/ref/databases/). Its default backend is postgresql.
10. `DB_PORT` - It is used to get the database port from the env variables. Different database backends have different ports. Its default value is of postgresql port i.e. `5432`.

5. `DB_NAME` - This environment variable is required to get the name of the database. By default, its value is `osp`.

6. `DB_USERNAME` - This environment variable is required to get the **USERNAME** of the user with all privileges to the above mentioned database.

7. `DB_PASSWORD` - This environment variable is required to get the **password** of the above mentioned user i.e. the user with all the privileges to the database.
# Setup Social Auth

8. `DB_HOST` - It is used to get the database host from the env variables. For `docker` it must be set to `db` otherwise its default value is `localhost`.
1. Create a Super User by running this command: `python manage.py createsuperuser`.
2. Login to [Django admin site](http://localhost:8000/admin/) using credentials of the previous step.
3. Go to **Sites dashboard** in admin site. (**URL**: http://localhost:8000/admin/sites/site/).
4. Click on `Add site` button and fill in the information as given in the image.

9. `DB_PORT` - It is used to get the database port from the env variables. Different database backends have different ports. Its default value is of postgresql port i.e. `5432`.
![site_id](https://user-images.githubusercontent.com/56037184/109974910-0fa79b00-7d20-11eb-9826-44fdf6d770f9.png)

**Note**: After saving this if the site id is not `1` then change the `SITE_ID` in settings.py with the new site id.
5. After this go to **Social Applications Dashboard**. (**URL**: http://localhost:8000/admin/socialaccount/socialapp/).
6. Add the credentials that you get after creating the Google app. Fill in the information as given in the image.

![social_add](https://user-images.githubusercontent.com/44670961/110095166-9f058a80-7dc2-11eb-85eb-afb109f46663.png)
**For creating Google App & Creating ClientId & Client Secret see [this docs](https://developers.google.com/adwords/api/docs/guides/authentication#create_a_client_id_and_client_secret).**
## Testing

To run the tests run: `python manage.py test`.
Expand Down
19 changes: 19 additions & 0 deletions main/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@
"corsheaders",
"osp",
"token_auth",
# For Social Authentication
"dj_rest_auth",
"django.contrib.sites",
"allauth",
"allauth.account",
"allauth.socialaccount",
"allauth.socialaccount.providers.google",
]

MIDDLEWARE = [
Expand Down Expand Up @@ -80,11 +87,16 @@
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"],
"DEFAULT_PARSER_CLASSES": ["rest_framework.parsers.JSONParser"],
"DEFAULT_AUTHENTICATION_CLASSES": (
"dj_rest_auth.jwt_auth.JWTCookieAuthentication",
"rest_framework.authentication.SessionAuthentication",
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
}

SITE_ID = 1

REST_USE_JWT = True

SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(days=2),
"REFRESH_TOKEN_LIFETIME": timedelta(days=30),
Expand Down Expand Up @@ -157,3 +169,10 @@
# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = "/static/"

ACCOUNT_EMAIL_VERIFICATION = "none"

if os.environ.get("GOOGLE_CALLBACK_URL"):
GOOGLE_CALLBACK_URL = os.getenv("GOOGLE_CALLBACK_URL")
else:
GOOGLE_CALLBACK_URL = "http://localhost:3000/login"
5 changes: 4 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ toml==0.10.1
typed-ast==1.4.1
urllib3==1.25.10
wrapt==1.12.1
zulip==0.7.0
zulip==0.7.0
django-allauth==0.44.0
dj-rest-auth==2.1.3
responses==0.12.1
79 changes: 79 additions & 0 deletions tests/test_google_oauth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import json

import responses
from allauth.socialaccount.models import SocialApp
from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site
from django.test import TestCase
from django.urls import reverse
from rest_framework.test import APIClient


class TestGoogleAuth(TestCase):
"""
Tests for Google Authentication !!
"""

def setUp(self):
self.client = APIClient()
self.google_signup_url = reverse("google_login")
self.payload = {"access_token": "1234567", "id_token": "789456123"}
social_app = SocialApp.objects.create(
provider="google",
name="Google",
client_id="123456123456123456654321",
secret="654321123456123456987456123",
)
site = Site.objects.get_current()
social_app.sites.add(site)

@responses.activate
def test_google_auth(self):
"""
Testing Google Auth SignUp !!
"""
self._get_google_response()
user_count = get_user_model().objects.all().count()

response = self.client.post(self.google_signup_url, data=self.payload, format="json")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check the payload @chinmaym07. Why are you posting access_token in the payload?
The payload must contain the thing that we pass from the frontend?

self.assertEquals(response.status_code, 200)
# assertion to check new user is created.
self.assertEquals(get_user_model().objects.all().count(), user_count + 1)

# Below two assertions are added to check REST_USE_JWT is True or not.
self.assertIn("access_token", response.data)
self.assertIn("refresh_token", response.data)

# Assertion to check second request will not create a new user
response = self.client.post(self.google_signup_url, data=self.payload, format="json")

self.assertEquals(get_user_model().objects.all().count(), user_count + 1)

def _get_google_response(self):
"""
Private methods to get response from Google API Calls.
"""

responses.add(
responses.POST,
"https://accounts.google.com/o/oauth2/v2/auth",
body=json.dumps({"access_token": "access_token", "id_token": "id_token"}),
status=200,
content_type="application/json",
)

responses.add(
responses.GET,
"https://www.googleapis.com/oauth2/v2/userinfo",
body=json.dumps(
{
"id": "456123",
"email": "[email protected]",
"picture": "https://lh3.googleusercontent.com/a-/saf456fq1fc894veqw1fsc2",
"type": "User",
"verified_email": "true",
}
),
status=200,
content_type="application/json",
)
6 changes: 5 additions & 1 deletion token_auth/urls.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from django.conf.urls import url
from django.urls import path
from django.urls import include, path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

from token_auth.views.google_oauth import GoogleLogin
from token_auth.views.register import RegisterView

urlpatterns = [
Expand All @@ -14,4 +15,7 @@
# login URLs
path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("refresh/", TokenRefreshView.as_view(), name="token_refresh"),
# social-authentication
path("google/", GoogleLogin.as_view(), name="google_login"),
url(r"^accounts/", include("allauth.urls"), name="socialaccount_signup"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why you are including all URLs of all-auth?

]
11 changes: 11 additions & 0 deletions token_auth/views/google_oauth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from dj_rest_auth.registration.views import SocialLoginView
from django.conf import settings


class GoogleLogin(SocialLoginView):
authentication_classes = [] # disable authentication
adapter_class = GoogleOAuth2Adapter
callback_url = settings.GOOGLE_CALLBACK_URL
client_class = OAuth2Client