Tivix / django-rest-auth

This app makes it extremely easy to build Django powered SPA's (Single Page App) or Mobile apps exposing all registration and authentication related functionality as CBV's (Class Base View) and REST (JSON)
www.tivix.com
MIT License
2.41k stars 661 forks source link

Google OAuth2 not working or missing documentation #403

Open TeoTN opened 6 years ago

TeoTN commented 6 years ago

Hi! I am trying to figure out how to prepare Google OAuth2 authentication where there are two applications (frontend & backend) with the former initiating the process and the latter handling the actual authentication.

I have tried multiple approaches but none of them worked:

Approach 1

There is an endpoint /api/auth/google that is an instance of SocialLoginView:

class GoogleLogin(SocialLoginView):
    adapter_class = GoogleOAuth2Adapter

The frontend starts the authentication by opening a popup with url: https://accounts.google.com/o/oauth2/v2/auth and following query parameters:

client_id: [REDACTED],
scope: email,
response_type: token,
redirect_uri: [BACKEND]/api/auth/google,

Google redirects to [BACKEND]/api/auth/google/#access_token=[REDACTED]&token_type=Bearer&expires_in=3600 but the response is HTTP 405:

{
    "detail": "Method \"GET\" not allowed."
}

Unfortunately, there are a few problems with that:

Approach 2

Let's use Authorization Code Grant flow. The frontend starts the authentication by opening a popup with url: https://accounts.google.com/o/oauth2/v2/auth and following query parameters:

client_id: [REDACTED],
scope: email,
response_type: code,
redirect_uri: [BACKEND]/api/auth/google,

I have adjusted the /api/auth/google view to match the "documentation" in library code:

class GoogleLogin(SocialLoginView):
    adapter_class = GoogleOAuth2Adapter
    client_class = OAuth2Client
    callback_url = '[BACKEND]/accounts/google/login/callback' # Django-allauth

Again, this leads to GET method not allowed...

Approach 3

Let's add some code to handle GET requests the way POSTs are handled:

    def get(self, request, *args, **kwargs):
        self.request = request
        self.serializer = self.get_serializer(
            data=self.request.query_params,
            context={'request': request}
        )
        self.serializer.is_valid(raise_exception=True)

        self.login()
        return self.get_response()

This, in turn, leads to an error:

OAuth2Error at /api/auth/google/
Error retrieving access token: b'{\n  "error" : "redirect_uri_mismatch"\n}'

Let me add, that obviously I've triple-checked callback URLs in Google Developers Console.

Is there any setup with django-rest-auth and django-allauth that leads to fully-fledged authentication with Google OAuth2 and 2 parties? Why is the documentation on Social Authentication so scarce?

rustanacexd commented 6 years ago

I agree that docs on social auth is so scarce.

TeoTN commented 6 years ago

Is there anyone that could explain how the library should actually be used?

akasranjan005 commented 6 years ago

I don't know if this is the right approach or not, but what i have done is used django allauth for social login and redirected the user to further pages and django auth automatically stores the user login details.

The api call to the backend is done via frontend app and in my settings.py i have setup a Login Redirect url

yedengbp commented 6 years ago

@TeoTN
Get any luck to figure out a correct configuration?

TeoTN commented 6 years ago

Not at all, I gave up using the library. It seems to be unsupported.

rustanacexd commented 6 years ago

same. @TeoTN what library are you using right now? we use auth0 for now

dgilge commented 6 years ago

I've just written a small tutorial on this topic which hopefully brings some light into the darkness: https://gist.github.com/dgilge/dbe9260208aadee535cef7c412a1162e

(I didn't open any PRs yet because I first wanted to see what people think about my implementation.)

gonzafirewall commented 5 years ago

I have the same problem may be this help I made some custom changes but the results are good. https://medium.com/@gonzafirewall/google-oauth2-and-django-rest-auth-92b0d8f70575 I not make any pr because may be the major change need to be made on django allauth project. I dont know.

Aibier commented 5 years ago

It works for me when i changed redirect_url to localhost:8000

And note that it takes to update your settings in google console. add the http://localhost:8000/api/v1/auth/google in your google developer console project settings.

in the settings.py GOOGLE_REDIRECT_URL = 'http://localhost:8000/api/v1/auth/google'

class GoogleLogin(SocialLoginView): adapter_class = GoogleOAuth2Adapter callback_url = settings.GOOGLE_REDIRECT_URL client_class = OAuth2Client serializer_class = SocialLoginSerializer

def get(self, request):
    """
    Get google authorization code and make an internal
    post request to allow social media login or register
    """
    code = request.GET.get('code')
    state = request.GET.get('state')
    response = Response({
        'status': 'Bad request',
        'message': 'Invalid request, please try again later.'
        }, status=status.HTTP_400_BAD_REQUEST)
    if code is not None:
        data = {
            'code': code,
            'state': state
        }
        self.serializer = self.get_serializer(
            data=data, context={'request': request})
        serializer_is_valid = False
        try:
            serializer_is_valid = self.serializer.is_valid(
                raise_exception=True)
        except OAuth2Error:
            serializer_is_valid = False
        if serializer_is_valid:
            self.login()
            response = self.get_response()
    return response
janokruta commented 5 years ago

None of above worked in my case. I've created a stackoverflow post. Do someone know how to fix it? https://stackoverflow.com/questions/57252301/google-login-in-django-rest-framework-allauth-rest-auth

michaelhenry commented 4 years ago

Install allauth from my forked repo.

You can install via pip

pip install --upgrade git+https://github.com/michaelhenry/django-allauth.git

then use the GoogleOAuth2RestAdapter

from rest_auth.registration.views import SocialLoginView
from allauth.socialaccount.providers.google.views import GoogleOAuth2RestAdapter

class GoogleLogin(SocialLoginView):
    adapter_class = GoogleOAuth2RestAdapter

and in urls.py

from django.urls import path
from .views import GoogleLogin

urlpatterns = [
    path('v1/auth/google/', GoogleLogin.as_view(), name='google_login'),
]

and that's it. Please let me know if you have some questions.