This question already has answers here:
Force google account chooser
(5 answers)
Closed 1 year ago.
I'm developing a website on which I would like my users to log in with their Google account.
I managed to do it thanks to the Google API and the OAuth protocol. The documentation is very well done for the implementation of the "Connect with Google" button, the problem is that the documentation stops there.
When I click on the "Connect with Google" button, the OAuth authorization page appears, I log in with my account and everything works.
My problem now is this: If I log out (and it works) I am redirected to my login.php page (which is perfectly normal), but when I want to log in again, by pressing the "Login with Google" button, I no longer have the choice of which account I want to log in with, it automatically logs me in with the account I used just before!
This is very convenient but for me it's a huge problem, since if I have several Google accounts, how can I connect with this account and not another one? Normally the OAuth authorization page should ask me with which account I want to log in, right?
Thanks in advance for your help!
Here's my code for login.php page :
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<script src="https://apis.google.com/js/platform.js" async defer></script>
<meta name="google-signin-client_id" content="XXXXXXXXXXXXXXXXXXXXXXXXXXXX">
<link rel="stylesheet" href="../assets/plugins/toastr/toastr.min.css">
<script type="text/javascript" src='../assets/js/jquery.min.js'></script>
<script src="../assets/plugins/toastr/toastr.min.js"></script>
</head>
<body>
<h1>Connexion</h1>
<div class="g-signin2" data-onsuccess="onSignIn" data-onfailure="onFailure"></div>
<script>
function onSignIn(googleUser){
var id_token = googleUser.getAuthResponse().id_token;
verif_token(id_token);
}
function onFailure(){
toastr.error('Error !', '', {positionClass: 'toast-top-left'});
}
function verif_token(id_token){
$.ajax({
url: "connect.php?id_token="+id_token,
method: "GET"
}).done(function(response){
var response = JSON.parse(response);
if(response[0] == 1){
// success
window.location.replace('https://xxxxxxxx.xx/secret.php');
}else{
// error
onFailure();
}
});
}
</script>
</body>
</html>
You can use Disconnecting and revoking scopes to delete the association between your app and a user's account.
Just add this code in onSignIn() function
var auth2 = gapi.auth2.getAuthInstance();
auth2.disconnect();
For more information look to google docs from here
Related
I was able to inject apple sign in to the website by initiating the scopes/client id, redirect URI .. etc
now on successful login, apple redirects the response to the redirect URI using a post response, excuse my ignorance! but how can I handle this callback on my website ? is it something I can use in the Apple library itself ? or something I need to build myself? I was expecting to get the token and pass it to the backend as I am using RESTFul API with the backend
My page is something like this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.signin-button {
width: 210px;
height: 40px;
}
</style>
<meta name="appleid-signin-client-id" content="com.xxx.web">
<meta name="appleid-signin-scope" content="name email">
<meta name="appleid-signin-redirect-uri" content="https://xxx.xxx.com">
<meta name="appleid-signin-state" content="authorized">
</head>
<body>
<html>
<body>
<div id="appleid-signin" data-color="white" data-border="true" data-type="sign in"></div>
<script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
</script>
</body>
</html>
Thanks
redirect uri is mandatory for apple signin and should be a valid endpoint e.g
which accepts post request, Apple will call the endpoint and pass the code and id_token upon successful authentication.
Below is an example of a PHP controller
public function loginAppleAction(Request $request)
{
$code = $request->request->get('code');
$token = $request->request->get('id_token');
// authorize the user in your system.
// id_token is a JWT token that contains scope info like the email of the user. you can decode the JWT token using any JWT lib available.
// make user login into your system.
}
The host specified in appleid-signin-redirect-uri must include a domain name. It can’t be an IP address or localhost.
on the successful response from the redirect URI you can also catch the javascript event if you required to do additional tasks.
document.addEventListener('AppleIDSignInOnSuccess', function(data) {
location.reload();
});
I am trying to recreate the example provided by Tableau here with a dashboard that is hosted in Tableau Online. A separate article from Tableau talks about modifying the URL of the JS API based on where the dashboard is hosted, which I've tried to follow.
Even though the resulting embed should require a login to be displayed, I expect that login to be displayed in that embedded output/iframe on my webpage. Please refer to the included code. Instead, I'm getting a CORS error:
Refused to display 'https://10ay.online.tableau.com/site/jpl/views/JPLDashboard_V05_JUE/Awareness?:iid=2&:size=800,700&:embed=y&:showVizHome=n&:bootstrapWhenNotified=y&:tabs=n&:apiID=host0#navType=1&navSrc=Parse' in a frame because it set 'X-Frame-Options' to 'sameorigin'.
Is the approach I'm taking correct? If embedding Tableau Online dashboards is possible with their JS API, how do I avoid the CORS error?
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>JPL Dashboard</title>
<script type="text/javascript" src="https://online.tableau.com/javascripts/api/tableau-2.min.js"></script>
<script type="text/javascript">
function initViz() {
var containerDiv = document.getElementById("vizContainer"),
//url = "http://public.tableau.com/views/RegionalSampleWorkbook/Storms",
url = "https://10ay.online.tableau.com/site/jpl/views/JPLDashboard_V05_JUE/Awareness?:iid=2",
options = {
hideTabs: true,
onFirstInteractive: function() {
console.log("Run this code when the viz has finished loading.");
}
};
var viz = new tableau.Viz(containerDiv, url, options);
}
</script>
</head>
<body>
<div id="vizContainer" style="width:800px; height:700px;"></div>
<script type="text/javascript">
(function () {
window.onload = function () {
initViz();
};
})();
</script>
</body>
</html>
Ensure that the URL used for embedding the view is from the Share option in Tableau Online:
In Tableau Online, navigate to the view encountering the problem.
Click the Share button.
Copy the URL link within the Link section.
Configure the embed code to use this URL rather than the Tableau Online URL in the browser address bar.
If it is correct, try to add: <meta http-equiv="X-Frame-Options" content="allow"> in the HTML header
I hope it is helpful,
Gigi
I have to implement a "Connect with Paypal" feature in a React SPA application.
The login is implemented by using the Paypal provided code
paypal.use( ["login"], function(login) {
login.render ({
"appid": MYAPPID,
"authend": "sandbox",
"scopes": <SCOPES>,
"containerid": "paypalButton",
"locale": "en-us",
"returnurl": <RETURN_URL>
});
});
This opens a new popup window, which happens completely out of my control. The popup opens the Paypal login form, which after successful login, redirects to the <RETURN_URL>.
All this happens in the popup window. Since this is a SPA, I don't want to refresh the page.
What I need is a way to close the redirected popup, while also preserving the URL params that were passed back to it from Paypal, and have that information (the URL params) transferred to the main app window.
Is this possible and if so how? The Paypal documentation is pretty outdated from what I can tell.
There are a lot of ways to share this data. I am assuming your {RETURN_URL} and SPA are on the same origin. Here are two approaches I came up with to communicate between your SPA and the pop-up.
1) Use the Broadcast Channel API if the API is supported on browsers and versions you require (caniuse). No Safari, and limited Edge! Polyfills also exist.
Here's some sample code you can use to try out the different approaches. Two pages (one's your SPA, the other one's the RETURN_URL you give for PayPal to send you to on completion).
Your SPA index.html:
<html>
<head>
<title>My SPA</title>
</head>
<body>
<script>
const bc = new BroadcastChannel("my_spa_listener");
window.open("./newpage.html?some=true&query=hi¶ms=cat", "_new");
bc.onmessage = function(ev) {
console.log("Got a message from the pop-up: ", ev.data);
};
</script>
</body>
</html>
the pop-up newpage.html:
<html>
<head>
<title>PayPal redirected me here</title>
</head>
<body>
<script>
setTimeout(function() {
const bc = new BroadcastChannel("my_spa_listener");
bc.postMessage(window.location.search);
bc.close();
window.close();
}, 2500);
</script>
</body>
</html>
2) Good old localStorage. You can use it pretty much anywhere!
index.html:
const targetKey = "popup-queryparams";
window.addEventListener("storage", function(ev) {
if (ev.key === targetKey) {
console.log("Got the data: ", ev.newValue);
// clear key in case it conatins sensitive info
localStorage.removeItem(targetKey);
}
});
window.open("./newpage.html?some=true&query=hi¶ms=cat", "_new");
Then in the pop-up, before you close the window, just do:
localStorage.setItem("popup-queryparams", window.location.search);
I am using the Google login client API for JavaScript. The site I am working on has two relevant pages. It has a login page, and it has a user profile page. The login page obviously has a Google login button on it. You should only be able to view your profile page when you are logged in. When a user goes to their profile page without being logged in, it should redirect them to the login page.
Here is an approach I have tried that did not work:
// This does not work because this event is only fired when the user logs in or logs out, but not when the user is already logged out.
gapi.auth2.init().isSignedIn.listen(function(state) {
if(!state) location.href = "/login/";
});
I have also tried detecting the login status of the user when the script loads, but that did not work either. It always redirected to the login page because the Google API can never log the user in by the time the script is done loading.
Additionally, I am trying not to use setInterval or setTimeout in my code, though, if that is my only valid option, please inform me.
By the way, I have heard multiple times that I can just set a variable when the user logs in, and then simply redirect to the login page if the variable is false. When would I check for the value of said variable? This will not work because it requires me to set a specific delay with setTimeout. Google's loading time can vary greatly, so I am not going to use that.
I figured out that you can use this simple expression that returns either true or false depending on whether the user is logged into Google on your website.
gapi.auth2.init().isSignedIn.get()
I'm no expert in the Google login API, however from the what I do know the API is purely for verification purposes, and (as far as I'm aware, I could be wrong) not actual user sessions. Everything else relating to the user account (IE, storing and persisting the login session in your case) are handled by you, the developer. The basic auth supports calling a callback function on a successful login, via data-onsuccess, which calls a JavaScript function on the login with the relevant login information. When a user logins the standard practice is to verify the validity of the user token returned, then you can do what you need with the data. In this case, you'd start some kind of session for the user.
A very basic example is as follows:
home page
<!DOCTYPE html>
<html>
<head>
<title>Test Home</title>
</head>
<body>
Login<br>
Profile
</body>
</html>
This has 2 links, one for the profile and one for the login page.
login/index.php
<!DOCTYPE html>
<html>
<head>
<title>Test Login</title>
<meta name="google-signin-client_id" content="YOUR-CLIENT-ID.apps.googleusercontent.com">
</head>
<body>
<div class="g-signin2" data-onsuccess="onLoginSuccess"></div>
<script type="text/javascript">
function onLoginSuccess(user) {
var user_id_token = user.getAuthResponse().id_token,
request = new XMLHttpRequest();
request.open('POST', 'https://www.googleapis.com/oauth2/v3/tokeninfo');
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.onload = function() {
authUser(request.responseText);
};
request.send('id_token=' + user_id_token);
}
function authUser(userData) {
var request = new XMLHttpRequest();
request.open('POST', '/login/login.php');
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
request.onload = function() {
if (request.responseText == 'true') {
location.href = "/";
}
};
request.send('user_data=' + userData);
}
</script>
<script src="https://apis.google.com/js/platform.js" async defer></script>
</body>
</html>
What this is doing is creating a very basic login button. The button has a callback of onLoginSuccess which is called when the user logs in with Google. It then grabs the users token, via user.getAuthResponse().id_token and makes a post request to https://www.googleapis.com/oauth2/v3/tokeninfo to verify the token (this can be done locally on your backend, Google provides libraries for it. However it's much easier to use the API endpoint). Once it is verified, it sends the response data to authUser, another function, which then passes it to the backend (/login/login.php) to actually start the user session.
login/login.php
<?php
session_start();
$user_data = json_decode($_POST['user_data']);
$_SESSION['user_data'] = $user_data;
echo 'true';
login.php simply starts a session, grabs the posted data, and sets the user session to the data posted. It then echos true so that the JavaScript knows it is done. The JavaScript then sends the user back the home page.
profile/index.php
<?php
session_start();
if (!isset($_SESSION['user_data'])) {
header('Location: /login');
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Test Profile</title>
</head>
<body>
<img src=<?php echo $_SESSION['user_data']->picture; ?>><br>
<b>Welcome! <?php echo $_SESSION['user_data']->name; ?></b><br>
Sign out
</body>
</html>
What this page does is first check if the user_data session is set. IF it is not set (meaning the user has not logged in), it redirects them back to the home page. If it is set (meaning they are logged in) then it displays a picture and the users name, and has a logout button. When this is clicked it simply brings the user to /login/logout.php.
login/logout.php
<?php
session_start();
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), '', time()-3600, '/');
}
session_destroy();
header('Location: /');
All it does is remove all session data for the user, first getting rid of the session cookie and then destroying the actual session. It then leads them back to the home page. Clicking profile will now not allow them to view anything, because they are logged out, and will only display data when they log back in.
That is just a VERY basic and rough way of handling user sessions with the Google API. There are by far better ways (as this example has no real verification on the backend, and sessions are killed when the browser closes, so cookies may be better for you), however this is a general basis for handling user sessions.
I almost copy/pasted this example from the Hello.js website:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="js/vendor/hello/hello.js"></script>
</head>
<body>
<script>
hello.init({
facebook : XXXXXXXXXXX, //Plz note that I replaced a correct ID with the XXXXXXXXXX
},{redirect_uri:'redirect.html'});
hello.on('auth.login', function(auth){
// call user information, for the given network
hello( auth.network ).api( '/me' ).then( function(r){
// Inject it into the container
var label = document.getElementById( "profile_"+ auth.network );
if(!label){
label = document.createElement('div');
label.id = "profile_"+auth.network;
document.getElementById('profile').appendChild(label);
}
label.innerHTML = '<img src="'+ r.thumbnail +'" /> Hey '+r.name;
});
});
</script>
<button onclick="hello('facebook').login()">Facebook</button>
</body>
</html>
But when I click the facebook login button the console always shows me this error:
Uncaught TypeError: Cannot read property 'response_type' of undefined
Am I missing something?
Thanks in advance.
You must first register as a Facebook Developer to get an Facebook Developer ID, then you can replace the facebook : XXXXXXXXXXX with your ID. Also you have to specify the return URL. eg.
hello.init({
facebook : 355555184404909, //eg. Facebook ID
},{redirect_uri:'http://yourDomain/return.html'});
you can also register yourself as a developer on these networks Windows Live or Google+
EDIT: Added how to register your domain to a the Facebook Website Platform
You must register your domain on Facebook Developer Settings to allow the library to redirect to your domain
Just enter your domain http://yourDomain on the "Website URL" field.
You need to create an app as a Facebook Developer (https://developers.facebook.com/apps). You can then retrieve your Facebook App's Client ID.
As shown in hello's official website:
hello.init({
facebook : FACEBOOK_CLIENT_ID,
},{redirect_uri:'redirect.html'});