python-social-auth / social-core Goto Github PK
View Code? Open in Web Editor NEWPython Social Auth - Core
License: BSD 3-Clause "New" or "Revised" License
Python Social Auth - Core
License: BSD 3-Clause "New" or "Revised" License
I am trying to include support to authentication using the google API with facebook. However, if
AUTHENTICATION_BACKENDS = (
'social_core.backends.amazon.AmazonOAuth2',
'social_core.backends.facebook.FacebookOAuth2',
'django.contrib.auth.backends.ModelBackend'
),
for example. The facebook authentication works. On the other hand, if
AUTHENTICATION_BACKENDS = (
'social_core.backends.google.GoogleOAuth2',
'social_core.backends.facebook.FacebookOAuth2',
'django.contrib.auth.backends.ModelBackend'
)
. I get 'module 'xml.etree.ElementTree' has no attribute '_IterParseIterator'. I am concluding that the problem is in the Google module.
Are there any other changes I need to make to get #18 merged?
I'm currently developing a custom backend and facing a really frustrating issue with .netrc and Authorization
headers.
The backend I'm creating is a oAuth2 backend, that uses headers (Bearer token) to communicate the access_token.
The issue happens as soon as we want to retrieve the data with the user_data
call, this method calls self.get_json
that does a requests call.
It should call the url given in the get_json
call with the headers:
Authorization: Bearer ...
The requests
module checks for a .netrc
file in the home folder ( ~/
). As soon as it finds it it's replacing the Authorization header. Described in their documentation: http://docs.python-requests.org/en/master/user/authentication/#netrc-authentication
Instead of the bearer header it's sending the following:
Authorization: Basic ...
There could be an option to disable netrc in the social get_json
call. To disable it internally, inside a requests.Session
instance:
s = requests.Session()
s.trust_env = False
But the problem is that it also disables the system proxy settings. Source: http://docs.python-requests.org/en/master/api/#requests.Session.trust_env
How can we work around this issue somehow? What would be the best implementation to maybe manipulate the trust_env on the requests calls?
v0.1.0
Remove Facebook2OAuth2 and Facebook2AppOAuth2 backends (port from #1046 by browniebroke)
This small line almost took down our production system. I would appreciate if you would really stick with Semantic Versioning. If you remove or change behavior you should to make a major release.
Happy New Year
-Joe
Microsoft Graph documentation says that AzureAD endpoints are used, and so it would make sense to use AzureAD Oauth2 backend.
My biggest doubt is in SOCIAL_AUTH_AZUREAD_OAUTH2_RESOURCE
where I though the correct value would be https://graph.microsoft.com/v1.0/me
Unfortunately, I always get this error:
The application named https://graph.microsoft.com/v1.0/me was not found in the tenant named ****.
I think this is related to the fact that graph is not considered a resource by Azure AD but the documentation is a little scarce.
For my needs, I configured a new backend:
def user_data(self, access_token, *args, **kwargs):
"""Grab user profile information from microsoft."""
response = self.get_json('https://graph.microsoft.com/v1.0/me',
headers={'Authorization': 'Bearer ' + access_token})
return response
I would like assistance to understand if I should fork my developments or if I'm doing something wrong about AzureAD backend.
Note: I am using python-social-auth
with Django 1.9
Is there any way to request different scopes depending on which user is logging in? I have followed this documentation to enable private repos if private
is in the query string. This is what it looks like:
from social.backends.github import GithubOAuth2 as SocialGithubOAuth2
class GithubOAuth2(SocialGithubOAuth2):
"""
A GitHub OAuth backend that adds private repo scope if private is in the query string.
"""
def get_scope(self):
scope = super(GithubOAuth2, self).get_scope()
if self.data.get('private'):
scope = scope + ['repo']
return scope
And here are my default scopes:
SOCIAL_AUTH_GITHUB_SCOPE = [
'user',
'read:org',
'public_repo',
'admin:repo_hook',
]
I'd really like to be able to change the scope depending on the user that is logging in, not just based on the query string.
My app requests the minimum scope at signup (public repos only). Then the user can enable private repos later on, in which case I redirect them to login with private=1
in the query string. That adds the repo
scope when authenticating with GitHub. Then some time will go by, they'll get logged out, and next time they login they'll go right back to the public-only scope.
I need to be able to capture the user that is logging in and change their scope with GitHub when authenticating. Is there any way to accomplish this with python-social-auth?
The docs say that SOCIAL_AUTH_EMAIL_VALIDATION_FUNCTION should take three arguments, but it now seems to take a fourth: partial_token
. It's not in the documentation for email validation. I see it mentioned in the pipeline section, but it's unclear what changes should be made to make legacy code function. Can this be added to the documentation in more detail?
As far as I can tell, it's because the id_token
is passed to do_auth
, which causes it to be passed to user_data
in turn (via do_auth
).
But an id_token
apparently can't be used as an access_token
and causes a...
Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.
...error. Which I'm guessing is because the request is unauthenticated.
The tokeninfo endpoint for google+ should contain everything the backend needs, though. If there's a way to check for client side flow in user_data
(like passing in a token_type
argument or something?), it's possible that the user_data method can skip making an additional request.
Was able to work around this by subclassing GooglePlusAuth
and returning None
from user_data
since I'm only using the client-side flow.
from social_core.backends.google import GooglePlusAuth
class CustomGooglePlusAuth(GooglePlusAuth):
def user_data(self, *args, **kwargs):
return None
In my django application I have 2 tables: auth_user
and social_auth_usersocialauth
.
And the problem is in that the same user has different ids in these tables (auth_user.id
and social_auth_usersocialauth.user_id
).
So I got a problem when I wanted to figure out who is 2000th user on my site, each collection has it's own object with id = 2000.
Which of them is more reliable? The only option to register user was social auth backend.
I have configured the library to only fetch email and username from Facebook backend using the settings property SOCIAL_AUTH_USER_FIELDS
.
However, the user is always created with the first_name and last_name fields populated.
I have also tried with the SOCIAL_AUTH_FACEBOOK_SCOPE
and PROTECTED_USER_FIELDS
but those fields always get populated.
I have being debugging and I see that the fields are not fetched from Facebook but they are generated anyways from the fullname.
Is there anyway to avoid set those fields in the user object?
Makes it a bit hard to track down errors when the exception doesn't note that using id_token
is possible.
#49 pr for refactored a string for the auth url as well as doc url updated to more maintained version of oauth docs for that community of devs.
Is there a way to get the login URL that social auth uses to initial a login, for use in Python code rather than in some specific framework's templating language?
Django's template uses <a href="{% url "social:begin" "google-oauth2" %}">Google+</a>
but it would be super useful (for third party, proxied logins) to be able to call that url("social:begin", "google-oauth2")
with some kind of namespacing so that the url(...)
function name doesn't collide.
How/where can this function be imported/called from?
(And would it be possible to put this in the docs for future searcher-of-information?)
It's possible to force google to display the account chooser screen when the user is redirected to the auth
endpoint by including a prompt
query parameter. This SO post goes into a bit more detail.
My app has users logging in and out with different Google accounts, and the default google auth endpoint seems to remember the last account they'd authed with, and sharply bypasses the account chooser.
I'm able to get the desired behaviour by adding params['prompt'] = 'select_account'
to social_core.backends.oauth.BaseOAuth2.auth_params
:
def auth_params(self, state=None):
client_id, client_secret = self.get_key_and_secret()
params = {
'client_id': client_id,
'redirect_uri': self.get_redirect_uri(state)
}
if self.STATE_PARAMETER and state:
params['state'] = state
if self.RESPONSE_TYPE:
params['response_type'] = self.RESPONSE_TYPE
params['prompt'] = 'select_account' ## <---- Adding in forced account chooser
return params
I'm not exactly sure the best way to make this configurable, being the many levels of abstraction in this lib. Think you could point me in the right direction and I'll submit a PR @omab ?
Simple addition of a param to pass to the Slack auth URL.
We're working on social network post tool and user sometimes want to add a single post to the multiple facebook accounts f.e.
So he must to sign to all of them first.
Does python social auth allow to do it?
I followed the instructions on the backend documentation page for Stripe, and used this backend authentication code:
SOCIAL_AUTH_AUTHENTICATION_BACKENDS = (
...
'social_core.backends.stripe.StripeOAuth2',
...
)
When I tried to use <a href="{% url 'social:begin' 'stripe' %}">Stripe</a>
in a template, I got the following error:
Replacing with SOCIAL_AUTH_AUTHENTICATION_BACKENDS
with AUTHENTICATION_BACKENDS
fixed the problem, and my link succesfuly routed me to the Stripe OAuth Login page.
@omab In 25ca1f5 you have added new dependence pyjwkest
. With this new requirement every python-social-auth
user has to install Cryptodome
with build-essential libgmp3-dev python3-dev
debian packages (more than 50mb).
Is it possible to use extras_require
in setup.py
to download that kind of dependencies optionally?
The personaname (display name on the profile) ist not unique and can therefore lead to errors, when multiple users with the same name try to log on. The steamid would provide a number as the username but is unique throughout Steam.
Assume there are two users - User A and User B.
User A is logged in the browser.
Now User B, opens his email and clicks on the email confirmation link in the same browser. So, on confirmation the social backend of User B will get connected to User A's account.
Solution
Logout user before email confirmation in mail_validation
pipeline.
@omab Check this, seems like a security issue.
Instead of checking value of expires_in key for capturing the value of expired in UserSocialAuth model's extra_param attribute, expires key is checked in response dict and null value is stored against expires in UserSocialAuth model's extra_param auth.
response = {
"access_token": <access_token>,
"expires_in" : <time_in_seconds>,
"token_type": "bearer"
}
Facebook API version 2.8 can be used to reproduce the error.
Facebook API documentation
I read the source code of open_id.py, and found that the default URL is None(URL = None
)
I want to config this URL in my project settings.py, How shoud I config?
ps: I don't think that modify the URL in the source code is a good idea.
I'm upgrading to the latest social auth (migrating to the new packages) and getting an error when clicking on the validation link (I'm not using the new partial pipeline continuation since it's not yet released in social-auth-core-1.2.0).
Versions:
social-auth-app-django==1.1.0
social-auth-app-django-mongoengine==1.0.0
social-auth-core==1.2.0
social-auth-storage-mongoengine==1.0.0
Traceback:
Request Method: GET
Request URL: http://localhost:8000/complete/email/?verification_code=92788337441c4b3ea260680786300aab&next=/&[email protected]
Django Version: 1.9.6
Python Version: 2.7.10
Installed Applications:
('django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sitemaps',
'django_mongoengine',
'django_mongoengine.mongo_auth',
'bootstrap3',
'django_extensions',
'social_django_mongoengine',
'django_countries',
'localflavor',
'static_sitemaps',
'vendop',
'corsheaders',
'compressor',
'users',
'vgroups',
'notifications',
'vendors',
'categories',
'tz_detect',
'gamification',
'feed',
'reviews',
'api',
'best_vendor',
'sharing',
'blog',
'simple_cms',
'storages',
'quotes',
'locations',
'sitemap',
'search',
'social_network',
'trade_shows',
'enterprise',
'dj_static')
Installed Middleware:
('corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'users.middleware.UserRoutingMiddleware',
'users.middleware.UserLastSeenMiddleware',
'users.middleware.UserAgent',
'users.middleware.IsEnterpriseUser',
'django.contrib.messages.middleware.MessageMiddleware',
'social_django.middleware.SocialAuthExceptionMiddleware',
'tz_detect.middleware.TimezoneMiddleware')
Traceback:
File "/Users/dblado/.virtualenvs/vendop/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
149. response = self.process_exception_by_middleware(e, request)
File "/Users/dblado/.virtualenvs/vendop/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
147. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/dblado/.virtualenvs/vendop/lib/python2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
57. response = view_func(request, *args, **kwargs)
File "/Users/dblado/.virtualenvs/vendop/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view
58. return view_func(*args, **kwargs)
File "/Users/dblado/.virtualenvs/vendop/lib/python2.7/site-packages/social_django/utils.py" in wrapper
50. return func(request, backend, *args, **kwargs)
File "/Users/dblado/.virtualenvs/vendop/lib/python2.7/site-packages/social_django/views.py" in complete
28. redirect_name=REDIRECT_FIELD_NAME, *args, **kwargs)
File "/Users/dblado/.virtualenvs/vendop/lib/python2.7/site-packages/social_core/actions.py" in do_complete
37. partial = partial_pipeline_data(backend, user, *args, **kwargs)
File "/Users/dblado/.virtualenvs/vendop/lib/python2.7/site-packages/social_core/utils.py" in partial_pipeline_data
178. partial = backend.strategy.partial_load(partial_token)
File "/Users/dblado/.virtualenvs/vendop/lib/python2.7/site-packages/social_core/strategy.py" in partial_load
91. return partial_load(self, token)
File "/Users/dblado/.virtualenvs/vendop/lib/python2.7/site-packages/social_core/pipeline/utils.py" in partial_load
58. args = partial.args
File "/Users/dblado/.virtualenvs/vendop/lib/python2.7/site-packages/social_core/storage.py" in args
274. return self.data.get('args', [])
Exception Type: AttributeError at /complete/email/
Exception Value: 'str' object has no attribute 'get'
I'm sure I'm just missing something simple but been pounding on it for a few hours and out of options.
I tried using SOCIAL_AUTH_SAML_EXTRA_DATA to get the extra attributes into UserSocialAuth.extra_data but I don't believe this has been implemented yet. I suppose it could be done by subclassing SAMLAuth and overriding _check_entitlements() but I think that would be an abuse of what that method is for. Probably the right fix is to implement a SAMLAuth().extra_data(). I'll take a stab at it but wanted to submit this issue to track it. Please someone correct me if I'm wrong.
Currently the partial pipeline heavily depends on the current framework session capabilities, this makes it really hard to resume a pipeline from another browser, a quite common pattern when a user clicks a validation link from an email and it popups in another browser.
Ideally, the pipeline state should be stored in a way that will allow such resume scenario.
I would like to have two endpoints
/auth/login
/auth/check_user
The first would create user account if it doesn't exist or login if it does.
The second would return user data if he has an account in or throw an exception if he doesn't. Any way to do this?
Authentication Pipeline mentions social_core.pipeline.user.create_user
, but this doesn't look like it could be endpoint specific.
The second endpoint would be used by an external service (another platform).
Util function sanitize_url from here is vulnerable to open redirect attack if redirect_to is something like '////evil.com'. In this case urlparse(redirect_to)[1]
equals ''
, netloc
is set to hosts[0]
and value of redirect_to is returned.
def sanitize_redirect(hosts, redirect_to):
if redirect_to:
try:
# if redirect_to is '////evil.com', urlparse(...)[1] is ''
netloc = urlparse(redirect_to)[1] or hosts[0] # so we set netloc = hosts[0]
except (TypeError, AttributeError):
pass
else:
if netloc in hosts: # yes, netloc in hosts
return redirect_to # returning '////evil.com'
https://github.com/python-social-auth/social-core/blob/master/social_core/backends/line.py#L39
I actually get a success response when calling user_data
like below, but being processed as error because it contains statusMessage
:
{u'displayName': u'George Lee',
u'mid': u'XXXXX',
u'pictureUrl': XXXXX',
u'statusMessage': u'My status'}`
I'm trying to setup social-core, social-core-django, and Azure AD backend to authenticate using Azure Active Directory. The initial authentication works and creates a User and User Social Auth. However, subsequent attempts to authorize result in:
Some relevant information:
None
User.Read
permission)What I've tried so far:
Key questions:
upn
back to the client? Is it in the JWT?I'm going to follow up with Microsoft Azure AD support to understand why the UPN is not being returned given my configuration, and will include their response
I'm using the partial pipeline decorator to upgrade the OAuth scopes when a User signs in with GitHub. My decorated action checks the scopes returned from GitHub against an expected set and redirects back to GitHub asking for the correct ones if they differ. This was done so users can have 1 of N sets of scopes that my application needs. I can't know which set to ask for on sign in so I don't ask GitHub for any, who return the empty set and I then upgrade them to the correct set.
An [cut down] example of my action is below:
@partial
def ensure_github_scope(response, backend, strategy, user=None, *args, **kwargs):
level = get_cookie(strategy.request, 'oauth_level')
scopes = set(x for x in response['scope'].split(',') if x)
BASIC_SCOPE = ['repo', 'write:public_key', 'user:email']
WEBHOOK_SCOPE = ['repo', 'write:public_key', 'user:email', 'admin:org_hook']
next_url = backend.strategy.session_get('next', '/')
# user is authenticated _and_ expected to have basic scope
if level == 'basic' and not set(BASIC_SCOPE).issubset(scopes):
return upgrade(level='basic', next_url=next_url)
# user is authenticated _and_ expected to have webhooks scope
if level == 'upgraded' and set(WEBHOOK_SCOPE).issubset(scopes):
return upgrade(level='upgraded', next_url=next_url)
Pre #7 this was working well since the action got the current response
and I could test the scopes out there. However response
is now the serialised one from before the pipeline was paused. Is this the expected behaviour? If so, how can I get the current response data in my pipeline action?
According to IETF, one of the fields in an OAuth2 response should be expires_in
.
So far all the providers I've worked with return this field but I have no way to work with it because a time stamp of the access token is not saved.
I've added a pipeline where I add expires_on
to the EXTRA_DATA that is basically:
expires_on = int(time.time()) + int(expires_in)
This way I can get my access_token
allways valid (django code!):
social = request.user.social_auth.get(provider='my-backend')
if social.extra_data['expires_on'] <= int(time.time()):
strategy = load_strategy()
social.refresh_token(strategy)
return social.extra_data['access_token']
I have availability to do this improvement myself (fork, push) but I would like to have some feedback.
My idea would be to alter the class BaseOAuth2
(OAuth1 doens't have expires_in, at least in RFC) with:
expires_in = response.get('expires_in', '') or \
kwargs.get('expires_in')
if expires_in not '':
data['psa_expires_on'] = int(time.time()) + int(expires_in)
else:
data['psa_expires_on'] = None
I added psa
to the beginning because at least AzureAD Oauth2 protocol replies with expires_on
, precisely with this implementation (epoch time)
In the long term, something interesting would be to include a method, like the one I have at the beginning of this issue, to obtain the access token. It would be an alternative to social.extra_data['access_token']
and would assure the token obtained is valid.
Hi @omab: was wondering if you know of a technique to get all of the data out of EXTRA_DATA
(for example in saml.py) through the extra_data
method without explicitly naming all the keys in EXTRA_DATA
?
As proposed by @haikuginger here, what if we can pass in a special field that indicates to the algorithm that we want every key that appears? We're definitely open to implementing it and opening a PR if you think that's a good idea. Would love to also continue contributing.
Hello,
OAuth2 RFC provides the following information on the successful response:
access_token
(REQUIRED)token_type
(REQUIRED)expires_in
(RECOMMENDED; The lifetime in seconds of the access token. If omitted, the authorization server SHOULD provide the expiration time via other means or document the default value.)refresh_token
(OPTIONAL)scope
(OPTIONAL, if identical to the scope requested by the client; otherwise, REQUIRED.)Having this in mind some parameters could be common in the extra data for OAuth2:
access_token
token_type
expires_in
Having this in mind I I purpose that in BaseOAuth2
we start having something like this: EXPIRES_IN_KEY = 'expires_in'
and EXPIRES_IN_DEFAULT = None
.
This can be used in extra_data() to save the lifetime in seconds of the access token complementing the auth_time
and making it possible to use access_token expired() at all times (for OAuth2).
PS: Is there any reason why currently the expires_in
is expire
in most backends and also the name used for expiration_timedelta()?
In my opinion, this method should be changed from expires
to expires_in
to comply with the RFC and backward compatible assured.
This discussion started in StackOverflow and I think it should be continued here.
The google-oauth2 allows anyone to inject any text which gets reflected on the web app.
This can be used to misguide user which may become the victim of social engineering.
I'e found this blog post which might help -
https://www.sagara.net/2014/08/30/authentication-fails-with-access_denied-error-while-using-microsoft-owin-security-google-3-0-0/
access_token_expired has the following logic:
def access_token_expired(self):
expiration = self.expiration_timedelta()
return expiration and expiration.total_seconds() <= 0
Why not:
class UserMixin(object):
...
RACE_CONDITION_TIMEOUT = 2
...
def access_token_expired(self):
expiration = self.expiration_timedelta()
return expiration and expiration.total_seconds() <= RACE_CONDITION_TIMEOUT
The strategies could override this value (thinking, for example, in creating a settings option for Django)
I incorrectly mocked the user endpoint response from the Asana API, so the backend doesn't work. I have a fix.
copied from omab/python-social-auth#1011
should support https://gitlab.com/ and on premises installation (custom urls)
i tried to make own using this blog:
http://widerin.net/blog/weblate-gitlab-oauth-login/
in weblate, but got some errors:
weblate_1 | ERROR Internal Server Error: /accounts/complete/GitLab/
weblate_1 | Traceback (most recent call last):
weblate_1 | File "/app/local/lib/python2.7/site-packages/django/core/handlers/exception.py", line 39, in inner
weblate_1 | response = get_response(request)
weblate_1 | File "/app/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 249, in _legacy_get_response
weblate_1 | response = self._get_response(request)
weblate_1 | File "/app/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
weblate_1 | response = self.process_exception_by_middleware(e, request)
weblate_1 | File "/app/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
weblate_1 | response = wrapped_callback(request, *callback_args, **callback_kwargs)
weblate_1 | File "/app/local/lib/python2.7/site-packages/django/views/decorators/cache.py", line 57, in _wrapped_view_func
weblate_1 | response = view_func(request, *args, **kwargs)
weblate_1 | File "/app/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
weblate_1 | return view_func(*args, **kwargs)
weblate_1 | File "/app/local/lib/python2.7/site-packages/social/apps/django_app/utils.py", line 51, in wrapper
weblate_1 | return func(request, backend, *args, **kwargs)
weblate_1 | File "/app/local/lib/python2.7/site-packages/social/apps/django_app/views.py", line 28, in complete
weblate_1 | redirect_name=REDIRECT_FIELD_NAME, *args, **kwargs)
weblate_1 | File "/app/local/lib/python2.7/site-packages/social/actions.py", line 44, in do_complete
weblate_1 | user = backend.complete(user=user, *args, **kwargs)
weblate_1 | File "/app/local/lib/python2.7/site-packages/social/backends/base.py", line 41, in complete
weblate_1 | return self.auth_complete(*args, **kwargs)
weblate_1 | File "/app/local/lib/python2.7/site-packages/social/utils.py", line 246, in wrapper
weblate_1 | return func(*args, **kwargs)
weblate_1 | File "/app/local/lib/python2.7/site-packages/social/backends/oauth.py", line 385, in auth_complete
weblate_1 | state = self.validate_state()
weblate_1 | File "/app/local/lib/python2.7/site-packages/social/backends/oauth.py", line 88, in validate_state
weblate_1 | raise AuthStateMissing(self, 'state')
weblate_1 | AuthStateMissing: Session value state missing.
so yeah, maybe some one more familiar with psa can add it to be included in distribution and be documented
The kwargs passed to BaseAuth.authenticate()
are ignored:
social-core/social_core/backends/base.py
Lines 73 to 74 in c03e669
self.strategy.request
is None
. However, the strategy passed in as a kwarg is the instance that has been used for much of the process prior to the call to authenticate
. kwargs['strategy'].request
contains the request made to the server to complete authentication.
This is important for my team because we rely on the request for multi-tenancy. We pull the site/tenant from the strategy's request, and from there get the associated configuration: https://github.com/edx/ecommerce/blob/master/ecommerce/social_auth/strategies.py#L12.
I propose modifying
self.strategy = self.strategy or kwargs.get('strategy')
self.redirect_uri = self.redirect_uri or kwargs.get('redirect_uri')
to
self.strategy = kwargs.get('strategy', self.strategy)
self.redirect_uri = kwargs.get('redirect_uri', self.redirect_uri)
-python3-openid==3.0.10 # via social-auth-core
+python-openid==2.2.5 # via social-auth-core
We're using a domain-forwarded setup in which the code itself runs on project-plus-random-prefix.ourstagingserver.org
but this code is accessed through project-staging.ourserver.org
(which acts as router for a number of different requests, one set of those being django routes, others being completely different things). When using Google Auth (oauth2) we can't seem to point the google callback to project-staging.ourserver.org/soc/complete/google-oauth2
because the redirect_url that the social auth library adds into the login is for project-plus-random-prefix.ourstagingserver.org
, and I cannot seem to find anything in the docs that explain how to tell social auth what the actual redirect uri should be.
I did find SOCIAL_AUTH_LOGIN_REDIRECT_URL
in http://python-social-auth-docs.readthedocs.io/en/latest/configuration/settings.html#urls-options but this documentation seems to suggest this is a path rather than a full URL, so if this value can be used for a fully qualified URL, can the docs be updated to explicitly mention that? And if not, what is the correct way to make sure social-auth uses the domain that it needs to be using for auth to succeed?
(We tried setting that to a full URL but that didn't seem to make things work...)
Hello!
I've done everything according to the instruction - https://github.com/omab/python-social-auth/blob/master/MIGRATING_TO_SOCIAL.md
But during the last step (manage.py migrate
with updated code) i'm getting an error:
django.db.migrations.graph.NodeNotFoundError: Migration social_django.0004_auto_20170312_1222 dependencies reference nonexistent parent node (u'social_django', u'0003_alter_email_max_length')
But as I can see, all migration files are at their proper places:
ls -lah /var/venv/python27/local/lib/python2.7/site-packages/social_django/migrations
total 68K
drwxr-xr-x 2 root root 4.0K Mar 12 17:39 .
drwxr-xr-x 3 root root 4.0K Mar 12 17:36 ..
-rw-r--r-- 1 root root 4.3K Mar 12 17:36 0001_initial.py
-rw-r--r-- 1 root root 3.4K Mar 12 17:36 0001_initial.pyc
-rw-r--r-- 1 root root 783 Mar 12 17:36 0002_add_related_name.py
-rw-r--r-- 1 root root 1.3K Mar 12 17:36 0002_add_related_name.pyc
-rw-r--r-- 1 root root 690 Mar 12 17:36 0003_alter_email_max_length.py
-rw-r--r-- 1 root root 1.3K Mar 12 17:36 0003_alter_email_max_length.pyc
-rw-r--r-- 1 root root 567 Mar 12 17:36 0004_auto_20160423_0400.py
-rw-r--r-- 1 root root 1.1K Mar 12 17:36 0004_auto_20160423_0400.pyc
-rw-r--r-- 1 root root 1.3K Mar 12 17:22 0004_auto_20170312_1222.py
-rw-r--r-- 1 root root 513 Mar 12 17:36 0005_auto_20160727_2333.py
-rw-r--r-- 1 root root 989 Mar 12 17:36 0005_auto_20160727_2333.pyc
-rw-r--r-- 1 root root 1.1K Mar 12 17:36 0006_partial.py
-rw-r--r-- 1 root root 1.5K Mar 12 17:36 0006_partial.pyc
-rw-r--r-- 1 root root 0 Mar 12 17:36 __init__.py
-rw-r--r-- 1 root root 168 Mar 12 17:36 __init__.pyc
After some strace
'ing I've discovered, that manage.py migrate
is looking for migration files in absolutely different place for some reason:
11211 stat64("/var/venv/python27/local/lib/python2.7/site-packages/django/contrib/auth/migrations/0003_alter_user_email_max_length", 0xbedb3448) = -1 ENOENT (No such file or directory)
11211 open("/var/venv/python27/local/lib/python2.7/site-packages/django/contrib/auth/migrations/0003_alter_user_email_max_length.arm-linux-gnueabihf.so", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
11211 open("/var/venv/python27/local/lib/python2.7/site-packages/django/contrib/auth/migrations/0003_alter_user_email_max_length.so", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
11211 open("/var/venv/python27/local/lib/python2.7/site-packages/django/contrib/auth/migrations/0003_alter_user_email_max_lengthmodule.so", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
Maybe, you can help me understand, why does it behaves in such way?
Thanks!
The fallback https://github.com/python-social-auth/social-core/blob/master/social_core/pipeline/user.py#L40 generates a str
in python 2.7. This later raises a TypeError
when calling unicodedata.normalize('NFKD', value)
in the contributed slugify
.
Hello,
I'm using this package on production and from time to time I see an error poping in my logs when Facebook returns a non-ascii language error message to social-auth.
Here is the full error stack:
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
File "django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "django/core/handlers/base.py", line 262, in process_exception_by_middleware
response = middleware_method(request, exception)
File "social_django/middleware.py", line 40, in process_exception
message = self.get_message(request, exception)
File "social_django/middleware.py", line 59, in get_message
return six.text_type(exception)
File "social_core/exceptions.py", line 49, in __str__
msg = super(AuthCanceled, self).__str__()
The error message that was returned by Facebook was the following: 차단된 URL: 리다이렉트 URI가 앱의 클라이언트 OAuth 설정에서 허용되어 있지 않기 때문에 리다이렉트할 수 없었습니다. 클라이언트와 웹 OAuth 로그인이 켜져 있고 모든 앱 도메인이 유효한 OAuth 리다이렉트 URI인지 확인하세요.
.
I believe the error happens when social-auth is trying to retrieve the error_message
parameter returned.
When refresh_token()
from storage.py
is called the value of auth_time
is not updated (the value of the access_token
and so on is updated).
My code:
self.social = user.social_auth.get(provider='custom')
if self.social.access_token_expired():
strategy = load_strategy()
self.social.refresh_token(strategy)
The value of the access_token
is updated but not the auth_time
.
My solution was adding two lines:
self.social.extra_data['auth_time'] = int(time.time())
self.social.save()
But there must be a better solution because every time the token is refreshed this is assumed.
Perhaps this is something Django-specific, but the UID isn't getting stored.
I have added 500px backend in #52. Is it enough for PR?
It looks like this patch:
incorrectly pases id_token
into access_token
parameter in def do_auth()
which is in backends/oauth.py
Here is a screenshot from django runserver_plus
:
This is the related stackoverflow question that I posted:
https://stackoverflow.com/questions/44474913/403-error-because-id-token-being-used-as-access-token-in-django-python-soc
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.