Error calling signout after gapi.auth.authorize - google-plus

I'm using client side login for google+. The access token expires in 1 hour. Calling gapi.auth.signOut() does not log the user out after the token has expired. I'm trying to re-authorise the user if his token has expired by calling gapi.auth.authorize with client_id, scope and immediate = true parameters. After calling this method, gapi.auth.signOut() doesn't work. I am not able to understand why is it.
Here is the code:
var google = {
signOut: function() {
var token = gapi.auth.getToken();
if(!token) {
var params = {
'client_id': global.clientid,
'session_state': global.sessionState,
'response_type':'token'
}
gapi.auth.checkSessionState(params, function(state){
if(state == true) {
google.doSignOut();
} else {
google.silentAuthorize(function(data){
google.doSignOut();
});
}
});
} else {
google.doSignOut();
}
},
doSignOut: function() {
gapi.auth.signOut();
google.loggedin = false;
},
silentAuthorize: function(callback) {
var params = {};
params.client_id = global.clientid;
params.immediate = true;
params.scope = "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/plus.login"
gapi.auth.authorize(params, callback);
}
}
calling google.signOut works fine while the token hasn't expired. But once the token has expired or I simple call google.silentAuthorize() with a callback, calling gapi.auth.signOut() starts throwing an error:
TypeError: Cannot read property 'clear' of null
Been trying to figure this out for 4 hours now, any help is highly appreciated!

I couldn't find anyway to renew token from front end, so I switched to hybrid method of using google auth. I now revive the session every time it is about to expire within php.

Related

OAuth 2Client: Invalid token signature

I wanted to handle my user auth by google.
async verify(token) {
try {
const ticket = await client.verifyIdToken({
idToken:token,
audience: '245409008225-isc00em81fk0vs423pm4jmgc2hcma5jj.apps.googleusercontent.com',
});
const payload = ticket.getPayload();
return payload
} catch (error) {
console.log(error)
}
this code works fine, only for first time to create user in DB. And i save this token to localstorage and retrieve it every time to validate that user is authentificated. Here is my code:
async isAuth(token) {
if (!token) {
false
}
const userData = tokenService.verify(token);
const tokenFromDb = await tokenService.findToken(token);
if (!userData || !tokenFromDb) {
throw ApiError.UnAuthorizedError();
}
const user = await User.findOne({where: {email: userData.email}});
await tokenService.saveToken(token);
return true;
}
I did google, and i supposed to define jwk key for google auth api? But I can't find real solution. So, hope you guys can help me. I never used before google auth. For now I have this solution by making request to this api https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=token and getting from there my user email

Unable to Authorize users using Implicit / Authorization flow in google actions

I am trying to link to the account :
Here is my google cloud function
var AuthHandler = function() {
this.googleSignIn = googleSignIn;
this.googleSignInCallback = googleSignInCallback;
}
function googleSignIn(req, res, next) {
passport = req._passport.instance;
passport.authenticate('google',{scope: 'https://www.googleapis.com/auth/userinfo.email',
state:"google",response_type:"token"},
function(err, user, info) {
console.log(user);
})(req,res,next);
};
function googleSignInCallback(req, res, next) {
passport = req._passport.instance;
passport.authenticate('google',function(err, user, info) {
if(err) {
return next(err);
}
if(!user) {
return res.redirect('http://localhost:8000');
}
console.log(user._json.token);
// /res.redirect('/');
res.redirect('https://oauth-redirect.googleusercontent.com/r/xxxxxx#access_token=' + user._json.token + '&token_type=bearer&state=google')
})(req,res,next);
};
module.exports = AuthHandler;
In google Action Console :
I have created the implicit flow and gave my authorisation url as follows:
https://[region]-[projectid].cloudfunctions.net/[functionname]/auth/google
Error :
this is the browser Url
https://assistant.google.com/services/auth/handoffs/auth/complete?state=xxxx&code=xxxxxx
on which the following error is displayed
The parameter "state" must be set in the query string.
Update 1
Before starting this implementation , i have followed this Solution to create the Authentication.
Problems in this Approach :
1.As stated in the Documentation it is not redirecting to google.com and i'm unable to access the token using the APIAI SDK in javascript. but still i can see the Access token in emulator . for better understanding adding images
Here is my simulator O/P
{
"response": {
"debug": {
"agentToAssistantDebug": {
"assistantToAgentDebug": {
"assistantToAgentJson": "{"accessToken\":\"xxxxxx\""
}
},
"errors": []
}
Update 2 :
So i have started creating with implicit flow and here is my complete repo
After battling with it i have achieved it , as there is no proper articles about creation of own Oauth Server that implements the Google Action , this might helpful for future users.
Authorization Endpoint
app.get('/authorise', function(req, res) {
req.headers.Authorization = 'Bearer xxxxxxxxxxx';
// with your own mechanism after successful
//login you need to create a access token for the generation of
//authorization code and append it to this header;
var request = new Request(req);
var response = new Response(res);
oauth.authorize(request, response).then(function(success) {
// https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID?
//code=AUTHORIZATION_CODE&state=STATE_STRING
var toredirect = success.redirectUri +"?code="+success.code
+"&state="+request.query.state ;
return res.redirect(toredirect);
}).catch(function(err){
res.status(err.code || 500).json(err)
}) });
Token Endpoint :
app.all('/oauth/token', function(req,res,next){
var request = new Request(req);
var response = new Response(res);
oauth
.token(request,response)
.then(function(token) {
// Todo: remove unnecessary values in response
return res.json(token)
}).catch(function(err){
return res.status(500).json(err)
})
});
After creation of this endpoints publish to the Google Cloud functions . I have used MYSQL as the DB using SEQUELIZE and Oauth-Server , if anyone need those models , will share it through repo .
With this you can able to link account using your own Server which implements
Auth tokens and Access Tokens
I think the problem is that the URL on this line isn't sending the parameters as query parameters, they're sending them as part of the anchor:
res.redirect('https://oauth-redirect.googleusercontent.com/r/xxxxxx#access_token=' + user._json.token + '&token_type=bearer&state=google')
You should replace the # with a ?, as illustrated here:
res.redirect('https://oauth-redirect.googleusercontent.com/r/xxxxxx?access_token=' + user._json.token + '&token_type=bearer&state=google')

Google api revoke token issue

I've created an application using google drive API to list and manage all my drive files.
Everything goes fine, except the log out part. I've searched for two days for a solution without a result.
The following is code related to login and works fine:
function checkAuth() {
gapi.auth.authorize(
{
'client_id': CLIENT_ID,
'scope': SCOPES.join(' '),
'immediate': true,
'authuser': '-1'
}, handleAuthResult);
}
function handleAuthResult(authResult) {
var authorizeDiv = document.getElementById('authorize-div');
if (authResult && !authResult.error) {
// Hide auth UI, then load client library.
authorizeDiv.style.display = 'none';
loadDriveApi();
} else {
authorizeDiv.style.display = 'inline';
}
}
function handleAuthClick(event) {
gapi.auth.authorize(
{client_id: CLIENT_ID, scope: SCOPES, immediate: false},
handleAuthResult);
return false;
}
function loadDriveApi() {
gapi.client.load('drive', 'v2', listFiles);
}
I'm able to login and work with files, but when I try to logout with following I get No 'Access-Control-Allow-Origin' error
$(document).on('click', '.logout', function(){
var token = gapi.auth.getToken();
if (token) {
var accessToken = gapi.auth.getToken().access_token;
if (accessToken) {
var revokeToken = 'https://accounts.google.com/o/oauth2/revoke?token=' + accessToken;
jQuery.getJSON(revokeToken).success(function(data) {
console.log(data);
}).error(function(message) {
console.error('error' + message);
}).complete(function() {
console.log('completed!');
});
}
}
gapi.auth.setToken(null);
gapi.auth.signOut();
});
In Google Developers Console I've regitred my website to Authorized JavaScript origins.
Thanks

handleChallenge() is not getting called after successful execution of isCustomResponse()

I am developing an application using IBM MobileFirst Platform Foundation application 7.0, with AngularJS and Ionic. For the authentication I am using adapter-based authentication.
I have a single realm that protects the application, and all procedures. I've defined a Login Controller and a LoginChallangeHandler Service that handles authentication related activities:
I am basing it on the following: https://medium.com/#papasimons/worklight-authentication-done-right-with-angularjs-768aa933329c
When I login in the app, the authentication works fine by the following steps
Step1:
Calling ch.submitAdapterAuthentication(options, ch.submitLoginCallback);
Step2:
After successful Adapter invocation the following is called
ch.submitLoginCallback = function(response) {
console.log("submitLoginCallback.response ",response);
var isLoginFormResponse = ch.isCustomResponse(response);
console.log("submitLoginCallback.isLoginFormResponse ",isLoginFormResponse);
if (isLoginFormResponse){
console.log("submitLoginCallback.calling ");
ch.handleChallenge(response);
}
};
step3:
ch.isCustomResponse = function(response) is called which returns true or false.
ch.isCustomResponse = function(response){
console.log("isCustomResponse.responseJSON ",response);
//alert("response")
if (!response || !response.responseJSON || response.responseText === null) {
return false;
}
console.log("isCustomResponse.response.responseJSON ",response.responseJSON);
console.log(typeof(response.responseJSON.authRequired) !== 'undefined');
if (typeof(response.responseJSON.authRequired) !== 'undefined'){
//ch.handleChallenge(response);
return true;
} else {
return false;
}
};
Step4:
ch.handleChallenge = function(response) is called, in which we will handle the success or failure of usr authentication.
Problem is, when the authentication fails or server session logout or server session timeout, on server adapter side onAuthRequired method is called which returnsauthRequired=true.
function onAuthRequired(headers, errorMessage){
return {
authRequired: true,
errorMessage: errorMessage
};
}
At the client side, ch.isCustomResponse = function(response) is called, but the ch.handleChallenge = function(response) is not called after that. The execution is terminating at ch.isCustomResponse function and ch.handleChallenge is not called automatically. If I call manually like this
if (typeof(response.responseJSON.authRequired) !== 'undefined'){
//ch.handleChallenge(response);
return true;
} else {
return false;
}
at login time the ch.handleChallenge() is executed twice.
Can anyone please tell me how to solve this problem? How to call ch.handleChallenge() automatically when ch.isCustomResponse() returns either authRequired=true or false.
when the authentication fails or server session logout or server session timeout
First you need to take the user on Login page(where user give credentials and press login) or if you login by code then you need to call this
ch.submitAdapterAuthentication(options, ch.submitLoginCallback);

How can I have a seperate login page using Durandal that has a different layout then the shell?

I've read through Durandal login page redirect pattern wow, lots of code to do what I'd think would be pretty simple.
I've also read through https://groups.google.com/forum/#!topic/durandaljs/RdGpwIm1oOU as I'd like the login page to have a simple logo with a login form, but I'd also like routing for a registration and about page as well. The rest of my site will have a menu, header, etc which I don't want to show until the user is logged in. Also, I'm not sure how this approach would update when the user logs in.
Another code example that almost does what I want to do: https://github.com/Useful-Software-Solutions-Ltd/Durandal451/blob/master/Durandal451v2/App/global/session.js
So, what should I do? Is there an official way to do this? There seems to be a mish mash of things out there that people have tried. I would think this would be a really common occurrence but couldn't find anything on the main docs.
I'm not sure this is the simplest way, but this is what I got
you will need to add some extra function after app.start() is triggered.
main.js
var auth = require('authentication'); // Authentication module
app.start().then(function()
{
// This function will wait for the promise
auth.init().then(function(data)
{
// When successfully authenticate, set the root to shell
app.setRoot('views/shell');
}
});
authentication.js
define(function(require)
{
var app = require('durandal/app');
return {
init: function()
{
// Initialize authentication...
return system.defer(function(dfd)
{
// Check if user is authenticate or if there has stored token
var isAuthenticate = someOtherFunctiontoCheck();
if (isAuthenticate)
{
dfd.resolve(true); // return promise
}
else
{
// When not authenticate, set root to login page
app.setRoot('views/login');
}
}
}
};
});
good luck! :)
UPDATE
login.js
define(function(require)
{
var ko = require('knockout');
var auth = require('authentication');
var username = ko.observable();
var password = ko.observable();
return {
username: username,
password: password,
submitForm: function()
{
// Do a login, if success, auth module will take care of it
// and here will take of the error
auth.login(username(), password()).error(function()
{
// notify user about the error (e.g invalid credentials)
});
}
};
});
Authentication.js
define(function(require)
{
var app = require('durandal/app');
return {
init: function()
{
// Initialize authentication...
return system.defer(function(dfd)
{
// Check if user is authenticate or if there has stored token
var isAuthenticate = someOtherFunctiontoCheck();
if (isAuthenticate)
{
dfd.resolve(true); // return promise
}
else
{
// When not authenticate, set root to login page
app.setRoot('views/login');
}
}
},
login: function(username, password)
{
// do authenticate for login credentials (e.g for retrieve auth token)
return $.ajax({
url : 'api/login',
type : 'POST',
data : {
username: username,
password: password
}
}).then(function(token){
// on success, stored token and set root to shell
functionToStoreToken(token);
// Set root to shell
app.setRoot('views/shell');
});
}
};
});