I am using drf-social-oauth2
for social authentication in django
. When I make a request to backend using following json
"grant_type": "convert_token",
"client_id": "QhT0Z....u3m5f",
"client_secret":"W2DMVGg.....CfhO",
"backend":"google-oauth2",
"token": "ya29.a0Ael9sCNIcDes5Zb85GJCGWj9ok5kmCH8oBAWWJP9gGRu1Mzrqgtkw6Ut4WE- aOaj0S5Fpf4IrZYjp8bYST93u6yb-MWIHzp3zmtUffbzKnA5VoKlvQ7aC5cSbCauBe4ckTn18XH0_3tWYn5QNg3D2bJqw6H1EAaCgYKARISARISFQF4udJhR0eV5UmE8pvApsrTCMq-8w0165"
then following response
is returned
access_token:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6IjVaU2tncnpJUlNIczlrd3liNUhrQXoyOFNwVVZnZCJ9.FRk7hYDP0ndlBpH3L2jkdNpO3kopRcLqCFfx-6C5GKA"
expires_in: 27791.630586
refresh_token:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbiI6IjdibURRUk54ckdLbVJiczR5UGd0ZTJidVNPMklQRyJ9.r5wH-RqhzN2DaG5uUF4Z7F-8ufPgBTUPn7fWLVFwt3k"
scope: "read write"
token_type: "Bearer"
By default if this response is returned the user profile and email should automatically gets saved in the db but the drf-social-oauth2 is only returning the access tokens and is not saving user data.
So when I make request to fetch user, following error occurs
RelatedObjectDoesNotExist at /api/v1/user/
UserProfile has no student.
Following is my written code
settings.py
INSTALLED_APPS = [
...
'oauth2_provider',
'social_django',
'drf_social_oauth2',
'users',
...
]
AUTH_USER_MODEL = 'users.UserProfile'
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
'drf_social_oauth2.authentication.SocialAuthentication',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
}
AUTHENTICATION_BACKENDS = (
# Google OAuth2
'social_core.backends.google.GoogleOAuth2',
# Facebook OAuth2
'social_core.backends.facebook.FacebookAppOAuth2',
'social_core.backends.facebook.FacebookOAuth2',
# Instagram OAuth2
'social_core.backends.instagram.InstagramOAuth2',
# drf_social_oauth2
'drf_social_oauth2.backends.DjangoOAuth2',
# Django
'django.contrib.auth.backends.ModelBackend',
)
ACTIVATE_JWT = True
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = os.getenv("G_APP_ID")
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.getenv("G_APP_SECRET")
# Define SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE to get extra permissions from Google.
SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
]
...
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
...
'social_django.context_processors.backends',
'social_django.context_processors.login_redirect',
],
},
},
]
urls.py
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('api/v1/auth/', include('drf_social_oauth2.urls', namespace='drf')),
path('admin/', admin.site.urls),
path('api/v1/', include('users.urls')),
]
managers.py
from typing import Optional
from django.contrib.auth.models import BaseUserManager, User
class UserProfileManager(BaseUserManager):
def create_user(self, email: str, name: Optional[str] = None, password: Optional[str] = None) -> User:
"""Create a new user profile"""
if not email:
raise ValueError('User must have an email address')
print("===================================", email)
email = self.normalize_email(email)
user = self.model(email=email, name=name)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email: str, password: str, name: Optional[str] = None) -> User:
"""Create a new superuser profile"""
user = self.create_user(email, name, password)
user.is_superuser = True
user.is_staff = True
user.save(using=self._db)
return user
models.py
from .managers import UserProfileManager
class UserProfile(AbstractBaseUser, PermissionsMixin):
name = models.CharField(max_length=100, null=True, blank=True)
email = models.EmailField(unique=True)
is_staff = models.BooleanField(default=False)
print("I'm here")
objects = UserProfileManager()
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
class Student(models.Model):
user = models.OneToOneField(UserProfile, on_delete=models.CASCADE)
grade = models.CharField(max_length=100, null=True, blank=True)
school = models.ForeignKey(School, on_delete=models.CASCADE, null=True, blank=True)
phone = models.CharField(max_length=50, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'students'
def __str__(self):
return self.user.name
I've checked online, consulted chatGPT but nothing working. I expect the drf-social-oauth2 to save user profile and email while returning the tokens.