How to integrate Google One Tap login with django-allauth? - django-allauth

How does one integrate the Google One Tap login experience with django-allauth?
django-allauth is integrated and working great for simple username/password logins.
I have Google OneTap's nicer user experience recognizing the user's authenticated Google account and offering to continue via that, sending a JWT auth token to Django.
Trying to find the simplest / cleanest way to register the new user account with the OneTap token and treat them as authenticated.
Appreciate any suggestions.
Refs:
https://developers.google.com/identity/one-tap/web
https://github.com/pennersr/django-allauth

Hacked something together, not as slick as one click login, (takes one extra step)
See more details here
https://twitter.com/DataLeonWei/status/1368021373151375361
All I did was changing the google redirect URL to the existing user log-in page with Google.
And add an additional view and replace google's data-login_uri with this view's URL.
#csrf_exempt
def google_one_tap_login(request):
login_url = PUBLIC_DOMAIN_NAME + '/accounts/google/login/'
return HttpResponseRedirect(login_url)
If someone has a better solution, please let me know.
My current hack is implemented on both sqlpad and instamentor, please feel free to check them out and see it in action.

Override allauth's account/login.html template and render the Google button (remember to replace <GOOGLE_APP_CLIENT_ID> and <HOMEPAGE>):
<div class="g_id_signin" data-type="standard" data-shape="pill"
data-theme="outline" data-text="signin_with" data-size="large"
data-logo_alignment="left"></div>
<div id="g_id_onload"
data-client_id="<GOOGLE_APP_CLIENT_ID>"
data-context="signin"
data-ux_mode="redirect"
data-login_uri="<HOMEPAGE>{% url 'google-login' %}?next={{ request.GET.next }}"
data-auto_prompt="false"></div>
<script src="https://accounts.google.com/gsi/client" async defer></script>
Install google-auth if you haven't already:
pip install google-auth
Register the google-login endpoint in your urls.py:
path('google-login', views.google_login, name='google-login'),
Define the google-login endpoint in your views.py, where you verify the Google ID token before redirecting to allauth's login URL for Google:
import logging
from django.conf import settings
from django.contrib import messages
from django.http import HttpResponseBadRequest
from django.shortcuts import redirect
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from google.oauth2 import id_token
from google.auth.transport import requests
from urllib import parse
#csrf_exempt
#require_POST
def google_login(request):
body_unicode = request.body.decode('utf-8')
body_params = parse.parse_qs(body_unicode)
csrf_token_cookie = request.COOKIES.get('g_csrf_token')
if not csrf_token_cookie:
return HttpResponseBadRequest('No CSRF token in Cookie.')
csrf_token_body = body_params.get('g_csrf_token')
if not csrf_token_body:
return HttpResponseBadRequest('No CSRF token in post body.')
if csrf_token_cookie != csrf_token_body[0]:
return HttpResponseBadRequest('Failed to verify double submit cookie.')
next_url = request.GET['next']
try:
token = body_params.get('credential')[0]
# noinspection PyUnusedLocal
idinfo = id_token.verify_oauth2_token(token, requests.Request(), settings.GOOGLE_APP_CLIENT_ID)
except ValueError as e:
logging.error(e)
return HttpResponseBadRequest('Failed to verify Google auth credentials.')
return redirect(settings.HOMEPAGE + '/accounts/google/login/?next=' + next_url)

Related

Did anyone manage to get the id token from google sign in (Flutter)

I am trying to connect my users with my back end server , i used the example from the official google sign in plugin for flutter :
https://pub.dartlang.org/packages/google_sign_in
the sign process goes fine and i get the username and email ect..
but i need the id Token to authenticate the user with my server.
Ps: Not using firebase , only google sign in.
Can anyone guide me how to get the id Token ?
You can try using this
_googleSignIn.signIn().then((result){
result.authentication.then((googleKey){
print(googleKey.accessToken);
print(googleKey.idToken);
print(_googleSignIn.currentUser.displayName);
}).catchError((err){
print('inner error');
});
}).catchError((err){
print('error occured');
});
You can get access token and id token more simple like this:
final result = await _googleSignIn.signIn();
final ggAuth = await result.authentication;
print(ggAuth.idToken);
print(ggAuth.accessToken);
Or you also can add it to try-catch to handle an error.
try {
final result = await _googleSignIn.signIn();
final ggAuth = await result.authentication;
print(ggAuth.idToken);
print(ggAuth.accessToken);
} catch (error) {
print(error);
}
or try like this if id token was null, it worked for me.
As the docs point out you need oauth2 client id of your backend to request idToken or serverAuthCode.
from firebase google sigin in authentication copy the Web SDK configuration
add paste in the following to res/values/strings.xml, That should work
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="default_web_client_id">{Web app Client id goes here}</string>
</resources>
The issue may be related to not using firebase. There is a google-services.json file which is given to you when you register your app in firebase, and you can use that with google_sign_in (this is the default way shown in the documentation).
I was getting null for the token value when trying to implement this without the google-services.json, but successfully signing into google.
If you don't want to use firebase, you have to jump through a couple hoops.
In google cloud console, register your app.
Then make sure you are 'in' your app that you just created in the top drop down menu.
in "apis and services" in the sidebar menu, go through the create Oauth consent screen menu, I don't remember having to fill out many fields, so leave them blank if you don't know what to put in.
then go to the "credentials" menu in the sidebar, and click "Create New Credentials", and select OAuth2 client ID. Make a web client, even though you're trying to use it with an android/ios app.
Make a file android/app/src/main/res/values/strings.xml
using the web client we just made, insert <?xml version="1.0" encoding="utf-8"?> <resources> <string name="default_web_client_id">YOUR WEB CLIENT ID</string> </resources> into the strings.xml file.
[edit] make one more client in the google console for android, and put in your local machine's sha1 key. This step is done for you automatically if you're using firebase. In this case, you have to create both the web client and one for your android device. In production, you'd be using a specific client for your production app.
That should do it I believe, might have missed a step.
I also wanted to verify on my backend that the incoming idtoken was valid, so I had to also make a service account (in the apis and services -> credentials page) and use that in my go server.
I'm still struggling to get this to work with ios, but the android side works great.
To retrieve the Is idToken worked for me:
1. The google-services.json file must be placed in /android/app/
2. you need to add to your /android/app/build.gradle
apply plugin: 'com.google.gms.google-services'
3. and to /android/build.gradle
classpath 'com.google.gms:google-services:4.3.4'
And that's it. GoogleSignIn will return a real idToken instead of null.
font: https://github.com/flutter/flutter/issues/12140#issuecomment-348720774
One more clean way to achieve this:
late Map<String, dynamic> userObject = {};
var res = await _googleSignIn.signIn();
var googleKey = await res!.authentication;
userObject.addAll({
'accessToken': googleKey.accessToken,
'idToken': googleKey.idToken,
'displayName': res.displayName ?? '',
'email': res.email,
'id': res.id,
'avatarUrl': res.photoUrl ?? '',
'serverAuthCode': res.serverAuthCode ?? '',
});
I was struggling with this issue for about a month. Turns out I was getting the same access token, even when the user tried restarting the app. This was painful because my app dealt with scopes and in case a user misses to check one or more scopes in his first sign in, the app wouldn't work at all, even if he/she signs in again and gives the permissions.
Workaround which worked for me: I called the googleSignIn.currentUser.clearAuthCache() method followed by googleSignIn.signInSilently(). This returns a GoogleSignInAccount which can be used for further authentication. My guess is that the clearAuthCache() method clears the token cache and hence a new token is created. This should get you a new access token and let your app make valid calls.
I sincerely request Google developers to solve this issue. For now, this workaround is the only thing that worked.
Try this:
When you create your GoogleSignIn object:
GoogleSignIn(
clientId: "YOUR CLIENT ID"
)
i hope it helps ;)

Send my own JWT when using social login (ex. google oauth2)

I have an authentication server where an user can login (user/password) and it sends back a token so the user can access a private api.
I want to implement social login (e.g. google oauth2) but the redirect flow of these logins prevent me to send back a token.
How can I achieve that ?
If understand you correct you want pass your custom data (token) to OAuth2 login process. If so you have state field in url for it. This field prevented during redirects and sent back to you result page.
Pice of sample code in python
state = any_data_base64_coded_or_references
flow = flow_from_clientsecrets(....)
next_page = str( flow.step1_get_authorize_url() + '&state=' + state );
But be carefull url can ba cutted in 255 bytes. So better pass references to your internal entry

Configure multiple login sessions using google oauth

I am using Google OAuth for Google signin with Odoo.
Everything works fine and I can sign in using google with no problem. However, I cannot open multiple sessions using my same google credentials.
For example, if I open two sessions, one in chrome and another in firefox, then the older session gets logged out.
I don't understand what's the problem because no matter how many sessions I start if I log in using my username and password separately, without using google OAuth, none of the sessions get logged out - works fine.
I was wondering it has got something to do with the code, so I did a lot of tweaks but nothing works. I saw that at one point it cannot get the session information of older sessions. However my question is not about the code.
My question is, is there any configuration or setting to be set in google OAuth or Odoo 8 which lets users have multiple sessions at the same time or is there any setting while using google OAuth with Odoo that I need to know for this?
Any idea would be really helpful as I've been struggling for days with this. Thanks!
I have build a module for Odoo V9. Without this module, Odoo save only one token. But when you use odoo in multi computer, you use one token for each computer.
By default odoo don't support multi token. You need to modify the code of module auth_oauth.
With this module it save all token, like that you can have multi connection.
You can donwload and instal this module : https://github.com/IguanaYachts/auth_oauth_multi_token.git
class ResUsers(models.Model):
_inherit = 'res.users'
oauth_access_token_ids = fields.One2many('auth.oauth.multi.token', 'user_id', 'Tokens', copy=False)
oauth_access_max_token = fields.Integer('Number of simultaneous connections', default=5, required=True)
#api.model
def _auth_oauth_signin(self, provider, validation, params):
res = super(ResUsers, self)._auth_oauth_signin(provider, validation, params)
oauth_uid = validation['user_id']
user_ids = self.search([('oauth_uid', '=', oauth_uid), ('oauth_provider_id', '=', provider)]).ids
if not user_ids:
raise openerp.exceptions.AccessDenied()
assert len(user_ids) == 1
self.oauth_access_token_ids.create({'user_id': user_ids[0],
'oauth_access_token': params['access_token'],
'active_token': True,
})
return res
#api.multi
def clear_token(self):
for users in self:
for token in users.oauth_access_token_ids:
token.write({
'oauth_access_token': "****************************",
'active_token': False})
#api.model
def check_credentials(self, password):
try:
return super(ResUsers, self).check_credentials(password)
except openerp.exceptions.AccessDenied:
res = self.env['auth.oauth.multi.token'].sudo().search([
('user_id', '=', self.env.uid),
('oauth_access_token', '=', password),
('active_token', '=', True),
])
if not res:
raise
If you follow the steps above you will be able to successfully configure Google Apps (Gmail) with OpenERP via the OAuth module. The only thing i was missing is an extra step I found in a youtube video; you have to:
Go to Settings - Users
To the users you want to give OAuth access, send them a password reset by using the "Send reset password instructions by email" option.
Ask your users (or yourself) to use the link they receive in their email, but, when they open it, they will only see the log in screen with the "Log in with Google" option. (no typical change password option available)
Use the proper Google account and voila! - Now it connects smoothly.
The Youtube video that show how to log in with Google in OpenERP: http://www.youtube.com/watch?v=A-iwzxEeJmc
and if configuration of Oauth2 and odoo see this link for more detail
https://odootricks.wordpress.com/2014/09/18/setting-up-google-apps-authentication-for-odoo/

The correct way to implement login with google account

What is the correct way to implement user login with google account in web2py? I can not use janrain (for some reason there is no google option when choosing widgets in my account, but google is configured as a provider.)
This is how I did it. Put this in models/db.py and don't forget to define your client_id and client_secret above.
import json
import urllib2
from gluon.contrib.login_methods.oauth20_account import OAuthAccount
class googleAccount(OAuthAccount):
AUTH_URL="https://accounts.google.com/o/oauth2/auth"
TOKEN_URL="https://accounts.google.com/o/oauth2/token"
def __init__(self):
OAuthAccount.__init__(self,
client_id=client_id,
client_secret=client_secret,
auth_url=self.AUTH_URL,
token_url=self.TOKEN_URL,
approval_prompt='force', state='auth_provider=google',
scope='https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email')
def get_user(self):
token = self.accessToken()
if not token:
return None
uinfo_url = 'https://www.googleapis.com/oauth2/v1/userinfo?access_token=%s' % urllib2.quote(token, safe='')
uinfo = None
try:
uinfo_stream = urllib2.urlopen(uinfo_url)
except:
session.token = None
return
data = uinfo_stream.read()
uinfo = json.loads(data)
return dict(first_name = uinfo['given_name'],
last_name = uinfo['family_name'],
username = uinfo['id'], email=uinfo['email'])
auth.settings.actions_disabled=['register',
'change_password','request_reset_password','profile']
auth.settings.login_form=googleAccount()
Probably should be a comment but I don't have enough points:
Janrain deprecated support for Google's OpenID authentication in early 2015 since Google also deprecated it. Janrain now supports Google+ for authentication and this should be available as a provider in your Janrain Dashboard.
https://support.janrain.com/hc/communities/public/questions/203662006-Upcoming-changes-to-Google?locale=en-us
If you aren't seeing Google+ as an option then please try contacting Janrain Support at support.janrain.com.

Apache Oltu Spring Security OAuth2 and Google Integration

The reference being purely taken from following sites:-
http://syntx.io/integrating-your-java-spring-mvc-webapp-with-facebook-doing-the-oauth-dance/
http://www.oodlestechnologies.com/blogs/OAuth-2.0-implementation-in-Spring-Framework
I've developed String Security OAuth2 Facebook integration example, Now I'm looking forward to developed the Security OAuth2 Google (and later Github) integration example where AppID and Secret will be provided to get "access_token" and "refresh_token" etc to be used to access the protected resources like UserDetails etc..
So, first step will be register App on http://code.google.com/apis/console. So it gives me "Client ID" and "Client secret", also I've configured Redirect URI, Done !
Now I've started writing actual Apache OAuth client, but I'm not sure what parameters I need to provide (similarly I provide for Facebook Integration, those parameters were easily available on facebook,while doing google search, but not found for Google), Please provide me suggestions what values should be given for the following blank parameters -
I think I've provided enough information, so any guidance / help / links is appreciated.
OAuthClientRequest request = OAuthClientRequest
.authorizationLocation("")
.setClientId("3kT21Hlkzzt5eV1")
.setRedirectURI("http://localhost:8080/apache-oltu/google/redirect")
.setResponseType("")
.setScope("")
.buildQueryMessage();
The following code is developed for callback
private void getAccessToken(String authorizationCode) throws OAuthSystemException, OAuthProblemException {
OAuthClientRequest request = OAuthClientRequest
.tokenLocation("")
.setGrantType()
.setClientId("3kT21H5EO3zzt5eV1")
.setClientSecret("1kT21Hdlkzzt5eV1")
.setRedirectURI("http://localhost:8080/apache-oltu/google/redirect")
.setCode()
.buildBodyMessage();
Added the following code to get protected resources like user profile:
request= new OAuthBearerClientRequest("https://www.googleapis.com/auth/userinfo.profile").
setAccessToken(oAuthResponse.getAccessToken()).
buildQueryMessage();
See here for a complete example:
http://mail-archives.apache.org/mod_mbox/oltu-user/201503.mbox/%3CA562FE5D3662044186474F4174F11DAE13044C639F#iowajhnex126.iowa.gov.state.ia.us%3E
I've developed Apache Oltu and Spring integration example and it's working fine at my end.
You need to enable the Google+ API as suggested by #prtk_shah. Thanks.
You need to go to the https://console.developers.google.com/project?authuser=0 and click on your project, in my case it's "apache-oltu", in your open project find option "APIs and auth" --> APIs. search for Google+ API and enable it.
Here you should be able to see this screen.
So, I will modify your code below it should be like this:
(IMP) - Your client ID should be like this, For Ex: (755670439314-jcumfghnkmcm72hf40beikvoatknstml.apps.googleusercontent.com), Please make sure it is correct. Fyi - use as it is provided by google developer console
OAuthClientRequest request = OAuthClientRequest
.authorizationLocation("https://accounts.google.com/o/oauth2/auth")
.setClientId("3kT21Hlkzzt5eV1.apps.googleusercontent.com")
.setRedirectURI("Give your projects redirect URI")
.setResponseType("responsecode")
.setScope("openId profile email")
.buildQueryMessage();
The callback code should be:
private void getAccessToken(String authorizationCode) throws OAuthSystemException, OAuthProblemException {
OAuthClientRequest request = OAuthClientRequest
.tokenLocation("https://accounts.google.com/o/oauth2/token")
.setGrantType(GrantType.AUTHORIZATION_CODE)
.setClientId("give your complete client id")
.setClientSecret("give your secret")
.setRedirectURI("This will be your callback or Redirect URL (Give it correctly)")
.setCode(authorizationCode)
.buildBodyMessage();
Here is what I'm getting in my example, just wanted to show you
Hope this will be helpful.

Resources