Django DRF problem with authentication using oauth2

28 views Asked by At

I'm trying to setup user authentication with discord oauth2. Everything worked fine but now I get infinite loops between my auth endpoints, I've been struggling for hours and I can't figure why it doesn't work.

It basically works like this :

path("oauth2/login", discord_login, name="discord_login"),
path("oauth2/login/redirect", discord_login_redirect, name="discord_login_redirect"),
path("auth/user", get_authenticated_user, name='get_authenticated_user')

'oauth2/login' redirects me to discord oauth2 then it redirects me to 'auth/user' after authentication succeeded.

#@login_required(login_url="/oauth2/login")
def get_authenticated_user(request):
    print("get_authenticated_user : authenticated = ", request.user.is_authenticated)
    print("get_authenticated_user : request = ", request)
    authenticated_user = request.user
    print("get_authenticated_user : user = ", authenticated_user)
    serialized_user = serialize_user(authenticated_user)
    return JsonResponse(serialized_user)

def discord_login(request):
    return redirect(settings.SOCIAL_AUTH_DISCORD_REDIRECT_URI)

def discord_login_redirect(request):
    if request.user.is_authenticated:
        return redirect('/auth/user')
    user_data = exchange_code(request.GET.get('code'))
    if user_data is not None:
        user = authenticate(request, user=user_data)
        if user is not None:
            login(request, user)
            print("discord_login_redirect : User = ", user)
            print("discord_login_redirect : authenticated = ", request.user.is_authenticated)
            return redirect('/auth/user')
        else:
            return HttpResponse("Authentication failed")
    return HttpResponseForbidden("Authentication canceled by user")

As I've chosen to implement @login_required to '/auth/user', I get infinite loops between the 2 endpoints, It seems that user is authenticated but it doesn't recognize it.

Here are my logs :

11:49:27 web.1   |  Attempting to authenticate user with Discord ID:  xxx
11:49:27 web.1   |  User with Discord ID %s found. xxx
11:49:27 web.1   |  global_name  =  xxx
11:49:27 web.1   |  avatar  =  xxx
11:49:27 web.1   |  public_flags  =  64
11:49:27 web.1   |  flags  =  64
11:49:27 web.1   |  locale  =  fr
11:49:27 web.1   |  mfa_enabled  =  False
11:49:27 web.1   |  discord_login_redirect : User =  ID: xxx, Global Name: xxx, Avatar: xxx, Public Flags: 64, Flags: 64, Locale: fr, MFA Enabled: False, Last Login: 2024-02-18 10:49:23.736180+00:00, Connections: <QuerySet [<Connection: Connection object (25)>, <Connection: Connection object (26)>, <Connection: Connection object (27)>, <Connection: Connection object (28)>]>
11:49:27 web.1   |  discord_login_redirect : authenticated =  True
11:49:27 web.1   |  get_authenticated_user : authenticated =  False
11:49:27 web.1   |  get_authenticated_user : request =  <WSGIRequest: GET '/auth/user'>
11:49:27 web.1   |  get_authenticated_user : user =  AnonymousUser

When I'm on '/auth/user', I can see 'sessionid' and 'csrftoken' in the dev console but I'm still an AnonymousUser.

In my database, last_login is actualized :

levellink=# select * from social_discorduser;
date_joined          |         id          | global_name |              avatar              | public_flags | flags | locale | mfa_enabled |          last_login           |
----------+--------------+------------+-----------+----------+-----------+-------------------------
17:16:42.667697+01 |  xxx | xxx | xxx |           64 |    64 | fr     | f           | 2024-02-18 11:16:00.694995+01 |
#settings.py

ALLOWED_HOSTS = []
    SOCIAL_AUTH_DN_REDIRECT_URI = "http://localhost:8000"

INSTALLED_APPS = [
    'whitenoise.runserver_nostatic',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'social_django',
    'rest_framework',
    'corsheaders',
    'social'
]

AUTHENTICATION_BACKENDS = [
    'social.auth.DiscordAuthenticationBackend'
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'social_django.middleware.SocialAuthExceptionMiddleware',
]

CORS_ALLOWED_ORIGINS = ["xxx", "xxx"]

CORS_ALLOW_CREDENTIALS = True

SESSION_COOKIE_AGE = 3600
SESSION_EXPIRE_AT_BROWSER_CLOSE = False

Do you have any clue on how to fix that please ?

Thanks a lot !

1

There are 1 answers

0
Le Bateleur On

I've fixed it by overwriting 'get_user' in my AuthenticationBackend and renaming the file to 'backends.py'

What a waste of time...