Google Auth2.0 log out - authentication

I'm currently trying to make a site where the user can log in with his google+ account. Most of it is working. I get them to grant access to my website. They can log in and I get their name and user ID, and I show content specific to their google account on my site.
When however someone else wants to log in and I try to 'log out' of the site, the google log in still remembers that it just logged in and after logging out it instantly runs the code to log in again. If I delete the SSID cookie from google it doesn't do this, so I'm assuming that's where google stores the fact that I just logged in with x.
Is there a way to when I log out make google not instantly log in with the same account, but rather ask for the e-mail and password of a google user?
I feel like I'm missing something obvious here, but I can't figure out how to deal with this.
Code I use to Auth and get data:
<button class ="btn btn-primary" id="authorize-button" style="visibility: hidden">Log in</button>
<script>
var clientId = '';
var apiKey = '';
var scopes = '';
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
}
function checkAuth() {
//alert("authorize");
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true}, handleAuthResult);
}
function handleAuthResult(authResult) {
//alert("authorized");
//alert(authResult.access_token);
var authorizeButton = document.getElementById('authorize-button');
if (authResult && !authResult.error) {
authorizeButton.style.visibility = 'hidden';
makeApiCall();
} else {
authorizeButton.style.visibility = '';
authorizeButton.onclick = handleAuthClick;
}
var token = document.createElement('h4');
token.appendChild(document.createTextNode(authResult.access_token));
document.getElementById('content').appendChild(token);
}
function handleAuthClick(event) {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: false}, handleAuthResult);
return false;
}
var x;
function makeApiCall() {
//return;
gapi.client.load('plus', 'v1', function() {
var request = gapi.client.plus.people.get({
'userId': 'me'
});
request.execute(function(resp) {
x = resp.id;
var heading2 = document.createElement('h4');
var heading3 = document.createElement('h4');
heading3.appendChild(document.createTextNode(resp.displayName));
heading2.appendChild(document.createTextNode(resp.id));
document.getElementById('content2').appendChild(heading2);
document.getElementById('content3').appendChild(heading3);
$.post("token.php", {id: x});
});
});
}

When you make the auth call, set approvalprompt to force. This will force the consent dialog to appear every time. It overrides the default setting of "auto." You can learn more at https://developers.google.com/+/web/signin/#sign-in_button_attributes.
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true, approvalprompt: force}

After the user authorizes your app, they are basically logged in to your app any time that they are also logged in to Google, especially when immediate mode is turned on.
What some sites do is have a logout link or button that displays a page or dialog that says something along the lines of "You're logged in to Google and this site with account blah#blah.com. If you want to switch accounts, go to google.com and log out of your Google session."
You can also track the logged in status of a user using your own cookies and setting and removing them during the appropriate events in your code. You would want to discard any tokens that your app obtained on behalf of the user during a log out event. When the user logged in again, they would not need to re-authorize your application with the popup (or redirect window), but you'd still get a new access token during the callback.

Related

Facebook JS SDK: what does it mean "if the person has used your app within the last 90 days"?

The doc here https://developers.facebook.com/docs/facebook-login/access-tokens/refreshing says "When you use the iOS, Android, or JavaScript SDK, the SDK will automatically refresh tokens if the person has used your app within the last 90 days".
I wonder what kind of "use" I should do to have the token refreshed. I tried to get last name of the user with:
FB.api('/me', {fields: 'last_name'}, function(response) {
console.log(response);
});
but it looks it is not enough to refresh the token (i.e. the call works fine, I get the last name of the user but the access token expiry date doesn't change / update).
I also tried:
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
}
});
but response.authResponse.accessToken has the same expiration date.
The goal is to renew / refresh expiration without asking the user to go through a full login again.

Cognito unable to signup users that have unconfirmed status already

A Cognito User Pool is configured for the users to use their "email address" to sign up and sign in.
If a user signs up with the email of someone else then that email will get stuck in UNCONFIRMED state and the owner will not be able to use it appropriately.
Having said that let me provide an example with the following scenario:
User signs in with an email address the user doesn't own, let's say it is someone#mail.com. In this step (registration form) some more data is sent like organization name, and user full name.
Verification code is sent to the email
Now the user that owns someone#email.com wants to create an account (maybe some days in the future), so he goes and fills the registration form but an error is thrown by cognito {"__type":"UsernameExistsException","message":"An account with the given email already exists."}
Thinks to consider:
* If the email already exists but is in unconfirmed state then provide the user the option to resend the link. This option is not optimal because additional data might be already in the user profile as the 1st step exemplifies.
* A custom lambda can be done to delete the unconfirmed user before signup or as a maintenance process every day, but I am not sure if this is the best approach.
There is also this configuration under Policies in cognito consol: "How quickly should user accounts created by administrators expire if not used?", but as he name implies this setting will only apply to users if they are invited by admins.
Is there a proper solution for this predicament?
Amazon Cognito has provided pre-signup triggers for these functionality and auto signup also.Your thought is the same way as i have implemented that according to the cognito documentations.
Here I am using the amplify/cli which is the toolchain for my development purpose hence the lambda function used in the trigger is as below:
`
"use strict";
console.log("Loading function");
var AWS = require("aws-sdk"),
uuid = require("uuid");
var cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider();
exports.handler = (event, context, callback) => {
const modifiedEvent = event;
// check that we're acting on the right trigger
if (event.triggerSource === "PreSignUp_SignUp") {
var params = {
UserPoolId: event.userPoolId,
Username: event.userName
};
cognitoIdentityServiceProvider.adminGetUser(params, function(err, data) {
if (err) {
console.log(err, err.stack);
} // an error occurred
else {
console.log("cognito service", data);
if (data.UserStatus == "UNCONFIRMED") {
cognitoIdentityServiceProvider.adminDeleteUser(params, function(
err,
data
) {
if (err) console.log(err, err.stack);
// an error occurred
else console.log("Unconfirmed user delete successful ");
// successful response
});
}
// successful response
}
});
return;
}
// Throw an error if invoked from the wrong trigger
callback('Misconfigured Cognito Trigger '+ event.triggerSource);
};
`
this will actually check and delete if the status is UNCONFIRMED using the aws-sdk methods adminGetUser and adminDeleteUser
hope this will help ;)
I got around this by setting ForceAliasCreation=True. This would allow the real email owner to confirm their account. The draw back is that you end up with 2 users. One CONFIRMED user and another UNCONFIRMED user.
To clean this up, I have a lambda function that calls list-users with filter for unconfirmed user and delete the accounts which were created before a certain period. This function is triggered daily by CloudWatch.
change to confirm from unconfirm:
aws cognito-idp admin-confirm-sign-up \
--user-pool-id %aws_user_pools_web_client_id% \
--username %email_address%

firebase log user out ref.unauth() did not work

I used the $authWithPassword() to login User, and it works fine. User can login, add content in the URL (/index.html#/notebook). Then I used the unauth() to log user out, then redirect them to the login page. It does say use is logged out, and redirect the user to the login page (/index.html#/login).
$scope.logOut = function(user) {
logoutObj.unauth();
console.log("User is logged out");
$location.path('/login');
};
However, when I type the URL in browser again (/index.html#/notebook), it shows this user is still logged in, and the content still available for the user.
It seems that the unauth() function does not really log out the user. Am i doing some thing wrong?
It's actually $unauth() and not unauth().
So change your code to this:
$scope.logOut = function(user) {
logoutObj.$unauth();
$location.path('/login');
};

Force google account chooser

Is there is a way I can force the google account chooser to appear even if the user is logged in just with one account.
I have tried by redirecting to this URL:
https://accounts.google.com/AccountChooser?service=lso&continue=[authorizeurl]
and it seems to work, but I don't know if there are any other conditions in which it might fail.
The following parameter is supported in OAuth2 authorization URLs:
prompt
Currently it can have values none, select_account, and consent.
none: Will cause Google to not show any UI, and therefore fail if user needs to login, or select an account in case of multi-login, or consent if first approval. It can be run in an invisible i-frame to obtain a token from previously authorized users before you decide, for instance, to render an authorization button.
consent: Will force the approval page to be displayed even if the user has previously authorized your application. May be useful in a few corner cases, for instance if you lost the refresh_token for the user, as Google only issues refresh_tokens on explicit consent action.
select_account: Will cause the account selector to display, even if there's a single logged-in user, just as you asked.
select_account can be combined with consent, as in:
prompt=select_account consent
Also, you can add "prompt" parameter in HTML tags as data-prompt="select_account":
<div class="g-signin2" data-onsuccess="onSignIn" data-prompt="select_account">
and it will force account chooser every time, even if you are logged in with only one account
Some people may end up here looking for an answer about how to do this in Microsoft.AspNetCore.Authentication.
We were able to accomplish it via the following code in the Startup.ConfigureServices method:
services.AddAuthentication()
.AddGoogle(options =>
{
options.ClientId = configHelper.GoogleOAuthClientID;
options.ClientSecret = configHelper.GoogleOAuthSecret;
options.CallbackPath = "/signin-google";
options.AuthorizationEndpoint = string.Concat(options.AuthorizationEndpoint, "?prompt=select_account");
});
If you are using gapi than just add prompt: 'select_account'
Example:
gapi.load('auth2', function () {
gapi.auth2.init({
client_id: "client_id.apps.googleusercontent.com",
scope: "profile email", // this isn't required
ux_mode: 'redirect',
redirect_uri: 'https://www.example.com',
prompt: 'select_account'
}).then(function (auth2) {
console.log("signed in: " + auth2.isSignedIn.get());
x = auth2.isSignedIn.get();
auth2.isSignedIn.listen(onSignIn);
var button = document.querySelector('#signInButton');
button.addEventListener('click', function () {
auth2.signIn();
});
});
});
For google api php client (https://github.com/google/google-api-php-client) you manage to do that as following:
$client = new Google_Client();
$client->setApprovalPrompt("force");
$client->createAuthUrl();

FB.login returns Invalid OAuth access token

I've been developing an app for the past few weeks and up until now there have been no issues. Just a couple days ago a strange bug has started occurring:
My application uses the PHP SDK and implements the Javascript SDK for user authorization. The user is allowed to roam the application freely, but when they click on a video, FB.login is called to request permissions from the user and get an access token.
jQuery Code
FB.login(function(response) {
if (response.authResponse) {
//Set global vars
fb_uid = response.authResponse.userID;
fb_token = response.authResponse.accessToken;
//If user has already authorized the app
if (response.status === 'connected') {
//Create the user record
$.ajax(site_url + '/facebook/create_fb_user', {
type: 'POST',
dataType: 'json',
data: {fb_uid: fb_uid, token: fb_token},
success: function (data) {
user = data.resp.fb_user;
viewVideo(item);
}
});
};
};
}, {scope: "publish_stream"});
PHP Code
try {
$this->_fb->setAccessToken($this->request->post('token'));
$data = $this->_fb->api("/me");
$model = new Model_Fbuser;
$model->data = array(
'fb_uid' => $data['id'],
'fb_token' => $extended_token
);
$resp = $model->update();
return $this->render_json(array(
'success' => TRUE,
'resp' => $resp
));
} catch (Exception $e) {
return $this->render_json(array(
'success' => FALSE,
'error' => $e->getMessage(),
'token' => $this->request->post('token')
));
}
The first time the user does this, the FB.login call returns a valid access token, the PHP SDK is able to set the token, and everything works as expected.
However, should the user revoke the application's access in their App Settings, and then return to the application, they are presented with the FB.login once more, but this time, the call returns the same access token they were previously given, which has already had its access revoked. Trying to set the access token with the PHP SDK throws the exception: "Invalid OAuth access token."
Yet if I then check the token in the Facebook debugger, is says it is valid.
Edit:
Further investigation reveals that the user is issues the same access token every time in the same session. If the user logs out, then logs back in, then they will receive a new valid token. But if they try to get a new token without logging out first, Facebook reissues them the same invalid one. When trying to use this access token to query information about the user, this is the response:
{"error":{"type":"OAuthException","message":"Error validating access token: The session was invalidated explicitly using an API call."}}
If you get the "Invalid OAuth access token" error in this way, I usually call FB.logout() and then immediately call FB.login() in the callback.
FB.logout(function(response) {
// user is now logged out
FB.login(...)
});
Not ideal, but the best way to fix such a use-case.