2
Google OpenId, OAuth2, OAuth1, Google+ Sign-in backends, docs at:
3
https://python-social-auth.readthedocs.io/en/latest/backends/google.html
5
from ..utils import handle_http_errors
6
from .open_id import OpenIdAuth
7
from .oauth import BaseOAuth2, BaseOAuth1
8
from ..exceptions import AuthMissingParameter
11
class BaseGoogleAuth(object):
12
def get_user_id(self, details, response):
13
"""Use google email as unique id"""
14
if self.setting('USE_UNIQUE_USER_ID', False):
17
return details['email']
19
def get_user_details(self, response):
20
"""Return user details from Google API account"""
21
if 'email' in response:
22
email = response['email']
23
elif 'emails' in response:
24
email = response['emails'][0]['value']
28
if isinstance(response.get('name'), dict):
29
names = response.get('name') or {}
30
name, given_name, family_name = (
31
response.get('displayName', ''),
32
names.get('givenName', ''),
33
names.get('familyName', '')
36
name, given_name, family_name = (
37
response.get('name', ''),
38
response.get('given_name', ''),
39
response.get('family_name', '')
42
fullname, first_name, last_name = self.get_user_names(
43
name, given_name, family_name
45
return {'username': email.split('@', 1)[0],
48
'first_name': first_name,
49
'last_name': last_name}
52
class BaseGoogleOAuth2API(BaseGoogleAuth):
53
def user_data(self, access_token, *args, **kwargs):
54
"""Return user data from Google API"""
56
'https://www.googleapis.com/plus/v1/people/me',
58
'access_token': access_token,
63
def revoke_token_params(self, token, uid):
64
return {'token': token}
66
def revoke_token_headers(self, token, uid):
67
return {'Content-type': 'application/json'}
70
class GoogleOAuth2(BaseGoogleOAuth2API, BaseOAuth2):
71
"""Google OAuth2 authentication backend"""
72
name = 'google-oauth2'
73
REDIRECT_STATE = False
74
AUTHORIZATION_URL = 'https://accounts.google.com/o/oauth2/auth'
75
ACCESS_TOKEN_URL = 'https://accounts.google.com/o/oauth2/token'
76
ACCESS_TOKEN_METHOD = 'POST'
77
REVOKE_TOKEN_URL = 'https://accounts.google.com/o/oauth2/revoke'
78
REVOKE_TOKEN_METHOD = 'GET'
79
# The order of the default scope is important
80
DEFAULT_SCOPE = ['openid', 'email', 'profile']
82
('refresh_token', 'refresh_token', True),
83
('expires_in', 'expires'),
84
('token_type', 'token_type', True)
88
class GooglePlusAuth(BaseGoogleOAuth2API, BaseOAuth2):
90
REDIRECT_STATE = False
91
STATE_PARAMETER = False
92
AUTHORIZATION_URL = 'https://accounts.google.com/o/oauth2/auth'
93
ACCESS_TOKEN_URL = 'https://accounts.google.com/o/oauth2/token'
94
ACCESS_TOKEN_METHOD = 'POST'
95
REVOKE_TOKEN_URL = 'https://accounts.google.com/o/oauth2/revoke'
96
REVOKE_TOKEN_METHOD = 'GET'
98
'https://www.googleapis.com/auth/plus.login',
99
'https://www.googleapis.com/auth/plus.me',
103
('refresh_token', 'refresh_token', True),
104
('expires_in', 'expires'),
105
('access_type', 'access_type', True),
109
def auth_complete_params(self, state=None):
110
params = super(GooglePlusAuth, self).auth_complete_params(state)
111
if self.data.get('access_token'):
112
# Don't add postmessage if this is plain server-side workflow
113
params['redirect_uri'] = 'postmessage'
117
def auth_complete(self, *args, **kwargs):
118
if 'access_token' in self.data: # Client-side workflow
119
token = self.data.get('access_token')
120
response = self.get_json(
121
'https://www.googleapis.com/oauth2/v3/tokeninfo',
122
params={'access_token': token}
124
self.process_error(response)
125
return self.do_auth(token, response=response, *args, **kwargs)
126
elif 'code' in self.data: # Server-side workflow
127
response = self.request_access_token(
128
self.ACCESS_TOKEN_URL,
129
data=self.auth_complete_params(),
130
headers=self.auth_headers(),
131
method=self.ACCESS_TOKEN_METHOD
133
self.process_error(response)
134
return self.do_auth(response['access_token'],
137
elif 'id_token' in self.data: # Client-side workflow
138
token = self.data.get('id_token')
139
response = self.get_json(
140
'https://www.googleapis.com/oauth2/v3/tokeninfo',
141
params={'id_token': token}
143
self.process_error(response)
144
return self.do_auth(token, response=response, *args, **kwargs)
146
raise AuthMissingParameter(self, 'access_token, id_token, or code')
149
class GoogleOAuth(BaseGoogleAuth, BaseOAuth1):
150
"""Google OAuth authorization mechanism"""
151
name = 'google-oauth'
152
AUTHORIZATION_URL = 'https://www.google.com/accounts/OAuthAuthorizeToken'
153
REQUEST_TOKEN_URL = 'https://www.google.com/accounts/OAuthGetRequestToken'
154
ACCESS_TOKEN_URL = 'https://www.google.com/accounts/OAuthGetAccessToken'
155
DEFAULT_SCOPE = ['https://www.googleapis.com/auth/userinfo#email']
157
def user_data(self, access_token, *args, **kwargs):
158
"""Return user data from Google API"""
159
return self.get_querystring(
160
'https://www.googleapis.com/userinfo/email',
161
auth=self.oauth_auth(access_token)
164
def get_key_and_secret(self):
165
"""Return Google OAuth Consumer Key and Consumer Secret pair, uses
166
anonymous by default, beware that this marks the application as not
167
registered and a security badge is displayed on authorization page.
168
http://code.google.com/apis/accounts/docs/OAuth_ref.html#SigningOAuth
170
key_secret = super(GoogleOAuth, self).get_key_and_secret()
171
if key_secret == (None, None):
172
key_secret = ('anonymous', 'anonymous')
176
class GoogleOpenId(OpenIdAuth):
178
URL = 'https://www.google.com/accounts/o8/id'
180
def get_user_id(self, details, response):
182
Return user unique id provided by service. For google user email
183
is unique enought to flag a single user. Email comes from schema:
184
http://axschema.org/contact/email
186
return details['email']