I configured the login with google in a Django project. I'm able to get the name and last name but the user is saved with an empty email. I configured the scope in this way:
SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [
'profile',
'email'
]
But the email continues saving as "". Am I writing the scopes in bad way?
Try this
SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile'
]
it will collect user email and profile name store it into USER model.
Related
My app running on Django with Django allauth allows signup/login only via Google OAuth. Therefore when a user is registered, his social oauth details are saved to All-auth Social Accounts model and the token data saved in Social Application Tokens model.
We want the users to be logged-in as long as possible, without granting/revoking access regularly.
Question 1: The default expiry is set as 1 hour from the registration time. How can I extend this programmatically and for how long (can it be never-expire?)
Currently, a user logged in at 5:00 and I get the following data from credentials.to_json():
{
"token": "ya29.A0ARrdaM8YXPM35RXPv7UK-pXLZvWG49T-MgCZ5wMse2ADMXOZJOWFJKMaq1PkobADLptM5YX5mnrliS2yCCESqCk0NTaZJkfe6inK94j6WQMFZWIT_xRyBTOX4W3dUEiuLhHFpQcD5vS-x_Y22pUzxwgI23pp",
"refresh_token": "1//0gYC8oucHhTBVCgYIARAAGBASNwF-L9IrCG7c5IJCBMVznUrytGEFsJbsObAFvmNBoQbHHGA1KESyBWgmudEVogbes8ski87q_5g",
"client_id": "blablabla.apps.googleusercontent.com",
"client_secret": "xyzsecret"}
No other data is returned.
At 6:05, the credentials.to_json() is exactly the SAME AS ABOVE.
But to fetch any Google/Youtube API data, I get the following error in server logs:
google.auth.exceptions.RefreshError: The credentials do not contain the necessary fields need to refresh the access token.
Question 02: When there's a Refresh Token available already, why the error?
As per the docs, it refreshes the token automatically few minutes before the expiry. What am I missing?
I already had "access_type": "offline" in the providers settings. I also tried adding "prompt": "consent", but no effect.
Django Settings:
INSTALLED_APPS = [
"allauth",
"allauth.account",
"allauth.socialaccount",
"allauth.socialaccount.providers.google",
...
]
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
"allauth.account.auth_backends.AuthenticationBackend",
]
SOCIALACCOUNT_PROVIDERS = {
"google": {
"SCOPE": [
"profile",
"email",
"https://www.googleapis.com/auth/youtube",
"https://www.googleapis.com/auth/youtube.readonly",
"https://www.googleapis.com/auth/youtube.upload",
"https://www.googleapis.com/auth/youtube.force-ssl",
],
"AUTH_PARAMS": {
"access_type": "offline",
"prompt": "consent",
},
},
}
And the Django Views snippet related to OAuth:
import googleapiclient.discovery
import googleapiclient.errors
from allauth.socialaccount.models import SocialAccount, SocialApp
from google.oauth2.credentials import Credentials
def get_credentials_google(user):
app_google = SocialApp.objects.get(provider="google")
account = SocialAccount.objects.get(user=user)
user_tokens = account.socialtoken_set.first()
creds = Credentials(
token=user_tokens.token,
refresh_token=user_tokens.token_secret,
client_id=app_google.client_id,
client_secret=app_google.secret,
)
return creds
def get_youtube_account(user):
api_service_name = "youtube"
api_version = "v3"
credentials = get_credentials_google(user)
youtube = googleapiclient.discovery.build(
api_service_name, api_version, credentials=credentials
)
return youtube
def get_youtube_videos(request):
youtube = get_youtube_account(request.user)
request = youtube.liveBroadcasts().list(
part="id, snippet, contentDetails, status",
broadcastStatus="completed",
broadcastType="all"
)
response = request.execute()
return response
Note: There's no front-end framework I'm using django with django template UI.
How can I extend this programmatically and for how long (can it be never-expire?)
You cant access tokens expire after one hour this is standard. You can use the refresh token to request a new access token as you need
When there's a Refresh Token available already, why the error? As per the docs, it refreshes the token automatically few minutes before the expiry. What am I missing?
Refresh tokens are used to request a new access token approximately five minutes before its due to expire.
google.auth.exceptions.RefreshError: The credentials do not contain the necessary fields need to refresh the access token.
Sounds like your not setting the client object properly. Something here is not set right. Also remember if your app is still in testing your refresh token will expire after seven days and you will need to reauthorize your test users.
creds = Credentials(
token=user_tokens.token,
refresh_token=user_tokens.token_secret,
client_id=app_google.client_id,
client_secret=app_google.secret,
)
I made registration via social networks using the allauth library.
Added the necessary settings:
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = "email".
and applications:
"allauth", #registration
"allauth.account", # registration
"allauth.socialaccount", # registration
"allauth.socialaccount.providers.vk", # registration via VK.
and in urls.py I also wrote:
url(r"^accounts/", include("allauth.urls"))
The problem is that sometimes the provider after registration may not provide an email.
And my users are identified using mail.
Signup:
I want the user to be redirected to a page with an email entry and send a confirmation link to this email after the suppliers confirm the entered data is correct.
Signin:
I want to return the JWT token to the user after confirming the providers that the entered data is correct
How to implement a signin/signup system in Django DRF JWT with allauth library?
(apparently I need to write custom views, but I tried - unsuccessfully)
I have a VueJS/Django rest framework application and working on the confirmation email when a user signup.
My frontend is on another URL than my backend so I try to configure djoser to put the activation link with the good domain.
I finally managed to do it kind of adding DOMAIN and SITE_NAME informations but the result is not as expected because my domain name is surrounded by brackets.
In my settings Django I have:
DOMAIN = 'localhost:8080',
SITE_NAME = 'Frontend',
DJOSER = {
'PASSWORD_RESET_CONFIRM_URL': '#/password/reset/confirm/{uid}/{token}',
'USERNAME_RESET_CONFIRM_URL': '#/username/reset/confirm/{uid}/{token}',
'ACTIVATION_URL': 'activate/{uid}/{token}',
'SEND_ACTIVATION_EMAIL': True,
'SERIALIZERS': {},
}
But the result in the email is:
You're receiving this email because you need to finish activation process on ('Frontend',).
Please go to the following page to activate account:
http://('localhost:8080',)/activate/MzE/an7e2w-73af66245317921904307cc266f4983e
Thanks for using our site!
The ('Frontend',) team
Does anyone have an idea why these brackets pop here?
Instead of:
DOMAIN = 'localhost:8080',
SITE_NAME = 'Frontend',
try without comma.
DOMAIN = 'localhost:8080'
SITE_NAME = 'Frontend'
A comma form a tuple.
In my Django app, I have a used google oauth2 for login, so when a user signs up, the first_name, last_name and username are automatically added to the User model and can be viewed through the admin panel. But the email addresses of the user are not being added, why is it so? Is there any way we can add the email address to the User model when the user signs up using OAuth?
By default (if you do not specify SCOPE), profile scope is requested, and optionally email scope depending on whether or not SOCIALACCOUNT_QUERY_EMAIL is enabled. See django-allauth.
Optionally, you can specify the scope to use as follows:
SOCIALACCOUNT_PROVIDERS = {
'google': {
'SCOPE': [
'profile',
'email',
],
'AUTH_PARAMS': {
'access_type': 'online',
}
}
}
Valid scopes include: email, phone, address, aq:name, aq:location. The default is to request a user’s name, and email address if SOCIALACCOUNT_QUERY_EMAIL=True. You can request and require a verified email address by setting SOCIALACCOUNT_EMAIL_VERIFICATION=True and SOCIALACCOUNT_EMAIL_REQUIRED=True.
UPDATE
See also configuration for SOCIALACCOUNT_EMAIL_VERIFICATION.
So I'll give full disclosure from the get-go that I am quite new to both Django and django-allauth.
Now that that is out of the way, the problem that I am having is that when a user logs in via a social site, (I have been trying Google and Facebook), none of the data retrieved from the site is pulled into the user's data fields. After authenticating, the user is still prompted to enter an email, and all name fields are left blank. I tried to fix this manually by creating a custom adapter, but that did not work either. From using print statements, I can see that the data is being fetched from the site just fine -- it just isn't being saved to the user's attributes.
Correct me if I'm wrong, but by reading the documentation and the some of the source of django-allauth, I am under the impression that social authorization automatically saves the user's email and first and last names via the populate_user(self, request, sociallogin, data): hook in the DefaultSocialAccountAdapter class, so I really shouldn't even have to deal with workarounds.
Thus, I'm guessing that I am just doing something foolish that is messing this up for me... Although if there is a clever workaround that will fix this problem, I'd be fine with that, for lack for a better solution.
Note: Using Django 1.7 and Python 3.4.1
EDIT: Django-allauth is succeeding in creating a User and linking the user to a social account, which contains all of the data fetched from the social site, but none of that data is populating the fields within the User object, like email, first_name, and last_name.
Here are my django-allauth configuration settings in settings.py:
ACCOUNT_AUTHENTICATION_METHOD = "email"
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = "required"
ACCOUNT_USERNAME_REQUIRED = False
SOCIALACCOUNT_AUTO_SIGNUP = True
# The following line was uncommented when I was trying to use my own adapter
# SOCIALACCOUNT_ADAPTER = 'profiles.profile_adapter.ProfileAdapter'
SOCIALACCOUNT_PROVIDERS = {
'facebook':
{ 'SCOPE': ['email'],
'AUTH_PARAMS': {'auth_type': 'reauthenticate'},
'METHOD': 'oauth2',
'LOCALE_FUNC': lambda request: 'en_US'},
'google':
{ 'SCOPE': ['https://www.googleapis.com/auth/userinfo.profile'],
'AUTH_PARAMS': { 'access_type': 'online' } },
}
And here is the code I had in my custom adapter (Which, by using print statements, I could tell was getting used and processing the correct data) where I tried to manually save the fields into the user object
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
class ProfileAdapter(DefaultSocialAccountAdapter):
def pre_social_login(self, request, sociallogin):
'''
Check for extra user data and save the desired fields.
'''
data = sociallogin.account.extra_data
user = sociallogin.account.user
print("LOGS: Caught the signal -> Printing extra data of the account: \n" + str(data))
if 'first_name' in data:
user.first_name = data['first_name']
elif 'given_name' in data:
user.first_name = data['given_name']
if 'last_name' in data:
user.last_name = data['last_name']
elif 'family_name' in data:
user.last_name = data['family_name']
user.save()
Note The above code creates a user in the database that is not linked to any social account, but contains the correct first and last names. Then the user is redirected to a form saying they are logging in with a social account and is prompted for an email address. Once this form is submitted, the original user created is overwritten by a new user that is linked to a social account, contains the email entered into the form, but does not have first or last name fields populated.
The problem was that when an email was not included with the data fetched from the social media site, django-allauth would ask for an email in a subsequent form to create the account with. When the account is then created from this form, django-allauth would not use the data fetched from the social media to populate fields. I think that this is a problem with django-allauth.