How to make friends Facebook Log in code with Google log in code - google-oauth

I have two snippets of code that are each responsible for logging in from their social networks are Facebook and Google.
//GOOGLE
if(isset($_GET['code'])) {
$token = $google_client->fetchAccessTokenWithAuthCode($_GET["code"]);
//This condition will check there is any error occur during geting authentication token. If there is no any error occur then it will execute if block of code/
if (!isset($token['error'])) {
//Set the access token used for requests
$google_client->setAccessToken($token['access_token']);
//Store "access_token" value in $_SESSION variable for future use.
$_SESSION['access_token'] = $token['access_token'];
//Create Object of Google Service OAuth 2 class
$google_service = new Google_Service_Oauth2($google_client);
//Get user profile data from google
$data = $google_service->userinfo->get();
if (!empty($data['sub'])) {
$_SESSION['user_id'] = $data['sub'];
}
if (!empty($data['given_name'])) {
$_SESSION['user_name'] = $data['given_name'] . " " . $data['family_name'];
}
if (!empty($data['email'])) {
$_SESSION['user_email_address'] = $data['email'];
}
if (!empty($data['picture'])) {
$_SESSION['user_image'] = $data['picture'];
}
}
}
//FACEBOOK
$facebook_helper = $facebook->getRedirectLoginHelper();
if(isset($_GET['code'])) {
if (isset($_SESSION['access_token'])) {
$access_token = $_SESSION['access_token'];
} else {
$access_token = $facebook_helper->getAccessToken();
$_SESSION['access_token'] = $access_token;
$facebook->setDefaultAccessToken($_SESSION['access_token']);
}
$graph_response = $facebook->get("/me?fields=name,email", $access_token);
$facebook_user_info = $graph_response->getGraphUser();
if (!empty($facebook_user_info['id'])) {
$_SESSION['user_image'] = 'http://graph.facebook.com/' . $facebook_user_info['id'] . '/picture';
}
if (!empty($facebook_user_info['id'])) {
$_SESSION['user_id'] = $facebook_user_info['id'];
}
if (!empty($facebook_user_info['name'])) {
$_SESSION['user_name'] = $facebook_user_info['name'];
}
if (!empty($facebook_user_info['email'])) {
$_SESSION['user_email_address'] = $facebook_user_info['email'];
}
} else {
// Get login url
$facebook_permissions = ['email']; // Optional permissions
$facebook_login_url = $facebook_helper->getLoginUrl('https://2goe.com/demo/'.$lang.'/home/', $facebook_permissions);
}
When they are together, then:
When you click Google log in, redirectURL responds with server error 500.
And Facebook does not return user data, which is requested in the code.
But if, for example, you delete the code of one of the social networks, it individually works fine. I myself tried to somehow paint 2 codes into one code, but to no avail. I also split them into different files, but this also did not bring any results.
Can you please help me somehow combine them correctly so that there are no such conflicts between them.

The issue you are having is that you are setting things with the same session names. $_GET['code'] could be facebook or google there is no way for you to know which one it is.
The easiest solution would be to run the google code first. Then alter the if statement for Facebook a little.
If you do something like this the code for facebook will look for a code find a code but it will also look for an error from Google. If google spit back an error then you try the code with facebook. If it did not return an error then you know the code was most likely used by Google.
if(isset($_GET['code'] && isset($token['error'])) {

Related

ETrade API unattended authentication

Background
The ETrade authentication system has me creating a RequestToken, then executing an Authorization URL, which opens an ETrade page.
The user logs in to authorize the activity on their account.
They receive a pin, which they enter in my app.
I call ExchangeRequestTokenForAccessToken with the RequestToken and the Pin.
Then we are off and running.
Question
The problem is I'm creating a service that runs continuously in the background. There won't be any user to log in. Conversely, I won't be making any trades. Just crunching numbers, looking for stocks that meet certain criteria.
I can't figure how to get this to work unattended.
Thanks, Brad.
Previously, I have used a series of WebRequests and manually added headers to simulate the authorization pages. This worked until about a year ago when ETrade complicated their headers with something that appears to be tracking information. I now use http://watin.org/ to log in, and to strip the Auth Code.
Sloppy code looks like this:
using WatiN.Core; // IE Automation
...
// verify current thread in STA.
Settings.Instance.MakeNewIeInstanceVisible = false;
var ieStaticInstanceHelper = new IEStaticInstanceHelper();
Settings.AutoStartDialogWatcher = false;
using (ieStaticInstanceHelper.IE = new IE())
{
string authCode = "";
ieStaticInstanceHelper.IE.GoTo(GetAuthorizationLink());
if (ieStaticInstanceHelper.IE.ContainsText("Scheduled System Maintenance"))
{
throw new ApplicationException("eTrade down for maintenance.");
}
TextField user = ieStaticInstanceHelper.IE.TextField(Find.ByName("USER"));
TextField pass = ieStaticInstanceHelper.IE.TextField(Find.ById("txtPassword"));
TextField pass2 = ieStaticInstanceHelper.IE.TextField(Find.ByName("PASSWORD"));
Button btn = ieStaticInstanceHelper.IE.Button(Find.ByClass("log-on-btn"));
Button btnAccept = ieStaticInstanceHelper.IE.Button(Find.ByValue("Accept"));
TextField authCodeBox = ieStaticInstanceHelper.IE.TextField(Find.First());
if (user != null && pass != null && btn != null &&
user.Exists && pass2.Exists && btn.Exists)
{
user.Value = username;
pass2.Value = password;
btn.Click();
}
btnAccept.WaitUntilExists(30);
btnAccept.Click();
authCodeBox.WaitUntilExists(30);
authCode = authCodeBox.Value;
SavePin(authCode);
}
Current version of Brad Melton's code.
WatiN has changed and no longer contains the IE.AttachToIE function.
So, IEStaticInstanceHelper is now called StaticBrowserInstanceHelper, but that code is hard to find, so I've included it here.
class StaticBrowserInstanceHelper<T> where T : Browser {
private Browser _browser;
private int _browserThread;
private string _browserHwnd;
public Browser Browser {
get {
int currentThreadId = GetCurrentThreadId();
if (currentThreadId != _browserThread) {
_browser = Browser.AttachTo<T>(Find.By("hwnd", _browserHwnd));
_browserThread = currentThreadId;
}
return _browser;
}
set {
_browser = value;
_browserHwnd = _browser.hWnd.ToString();
_browserThread = GetCurrentThreadId();
}
}
private int GetCurrentThreadId() {
return Thread.CurrentThread.GetHashCode();
}
}
ETrade's login pages have changed as well. They have several. All the login pages I checked consistently had a USER field and a PASSWORD field, but the login buttons had various names that look fragile. So if this doesn't work, that's the first thing I'd check.
Second, if I go directly to the auth page, it prompts to log in, but then it frequently doesn't take you to the auth page.
I got more consistent results by going to the home page to log in, then going to the auth page.
static public string GetPin(string username, string password, string logonLink, string authLink) {
// Settings.Instance.MakeNewIeInstanceVisible = false;
var StaticInstanceHelper = new StaticBrowserInstanceHelper<IE>();
Settings.AutoStartDialogWatcher = false;
// This code doesn't always handle it well when IE is already running, but it won't be in my case. You may need to attach to existing, depending on your context.
using (StaticInstanceHelper.Browser = new IE(logonLink)) {
string authCode = "";
// Browser reference was failing because IE hadn't started up yet.
// I'm in the background, so I don't care how long it takes.
// You may want to do a WaitFor to make it snappier.
Thread.Sleep(5000);
if (StaticInstanceHelper.Browser.ContainsText("Scheduled System Maintenance")) {
throw new ApplicationException("eTrade down for maintenance.");
}
TextField user = StaticInstanceHelper.Browser.TextField(Find.ByName("USER"));
TextField pass2 = StaticInstanceHelper.Browser.TextField(Find.ByName("PASSWORD"));
// Class names of the Logon and Logoff buttons vary by page, so I find by text. Seems likely to be more stable.
Button btnLogOn = StaticInstanceHelper.Browser.Button(Find.ByText("Log On"));
Element btnLogOff = StaticInstanceHelper.Browser.Element(Find.ByText("Log Off"));
Button btnAccept = StaticInstanceHelper.Browser.Button(Find.ByValue("Accept"));
TextField authCodeBox = StaticInstanceHelper.Browser.TextField(Find.First());
if (user != null && btnLogOn != null &&
user.Exists && pass2.Exists && btnLogOn.Exists) {
user.Value = username;
pass2.Value = password;
btnLogOn.Click();
}
Thread.Sleep(1000);
if (StaticInstanceHelper.Browser.ContainsText("Scheduled System Maintenance")) {
Element btnContinue = StaticInstanceHelper.Browser.Element(Find.ByName("continueButton"));
if (btnContinue.Exists)
btnContinue.Click();
}
btnLogOff.WaitUntilExists(30);
// Here we go, finally.
StaticInstanceHelper.Browser.GoTo(authLink);
btnAccept.WaitUntilExists(30);
btnAccept.Click();
authCodeBox.WaitUntilExists(30);
authCode = authCodeBox.Value;
StaticInstanceHelper.Browser.Close();
return authCode;
}
}
Being able to automate it like this means that I no longer care about how long the token is valid. Thanks BradM!
This was amazingly helpful. I used your code plus what was posted here to automate this (because tokens expire daily): E*Trade API frequently returns HTTP 401 Unauthorized when fetching an access token but not always
I made two edits:
Changed the authorize URL to what was posted here: https://seansoper.com/blog/connecting_etrade.html
For the log on button, changed it to search by ID: Button btnLogOn = StaticInstanceHelper.Browser.Button(Find.ById("logon_button"));
I ran into issues with Watin and setting up the Apartmentstate. So did this:
static void Main(string[] args)
{
System.Threading.Thread th = new Thread(new ThreadStart(TestAuth));
th.SetApartmentState(ApartmentState.STA);
th.Start();
th.Join();
}
Then put the code in the TestAuth method.

google account login for the first time displays error

I am trying to login the user with google account in my application. I am having a problem when the user is logged in for the first time with google account in my app it shows this error:
Argument 1 passed to Illuminate\Auth\Guard::login() must implement interface Illuminate\Auth\UserInterface, null given
In my controller I have this:
public function loginWithGoogle() {
// get data from input
$code = Input::get('code');
// get google service
$googleService = Artdarek\OAuth\Facade\OAuth::consumer("Google");
if (!empty($code)) {
// This was a callback request from google, get the token
$token = $googleService->requestAccessToken($code);
// Send a request with it
$result = json_decode($googleService->request('https://www.googleapis.com/oauth2/v1/userinfo'), true);
$user = User::whereEmail($result['email'])->first(['id']);
if (empty($user)) {
$data = new User;
$data->Username = $result['name'];
$data->email = $result['email'];
$data->google_id = $result['id'];
$data->first_name = $result['given_name'];
$data->last_name = $result['family_name'];
$data->save();
}
Auth::login($user);
return Redirect::to('/');
}
// if not ask for permission first
else {
// get googleService authorization
$url = $googleService->getAuthorizationUri();
// return to facebook login url
return Redirect::to((string) $url);
}
}
I know the problem is with Auth::login($user); as insert is performed at the same time with Auth::login($user); and it doesn't find data from database for the first time, but I don't know how to avoid this error and instead redirects to the main page even when the user is logged in for the first time. After this error the user is logged in, but how to avoid this?
Without knowing whether the rest of the code works, you definitely have a problem here:
if (empty($user)) {
$data = new User;
(...)
$data->save();
}
Auth::login($user);
When you're done creating your user, the $user variable is still empty. Your user is actually called $data. You should either rename the variable, or do the login with $data instead. Hopefully, that's enough to make the code work. :)

getting user info google plus api

How can I get public info of a user from google plus login button integrated on the site, here is the code which is giving me email, I need more info which is provide by google plus :
<div id="signin-button" class="show">
<div class="g-signin" data-callback="loginFinishedCallback"
data-approvalprompt="force"
data-clientid="9076269517.apps.googleusercontent.com"
data-scope="https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email"
data-height="short"
data-cookiepolicy="single_host_origin">
</div>
java script :
function loginFinishedCallback(authResult) {
if (authResult) {
if (authResult['error'] == undefined){
gapi.auth.setToken(authResult); // Store the returned token.
toggleElement('signin-button'); // Hide the sign-in button after successfully signing in the user.
getEmail(); // Trigger request to get the email address.
} else {
console.log('An error occurred');
}
} else {
console.log('Empty authResult'); // Something went wrong
}
}
function getEmail(){
// Load the oauth2 libraries to enable the userinfo methods.
gapi.client.load('oauth2', 'v2', function() {
var request = gapi.client.oauth2.userinfo.get();
request.execute(getEmailCallback);
});
}
function getEmailCallback(obj){
var el = document.getElementById('email');
var email = '';
if (obj['email']) {
email = 'Email: ' + obj['email'];
}
//console.log(obj); // Uncomment to inspect the full object.
el.innerHTML = email;
toggleElement('email');
}
function toggleElement(id) {
var el = document.getElementById(id);
if (el.getAttribute('class') == 'hide') {
el.setAttribute('class', 'show');
} else {
el.setAttribute('class', 'hide');
}
}
I tried replacing email with name, userId but getting nothing from these variables.
How can I get basic information of a user when he is logged in through google plus.
Similar to how you have loaded the oauth2 v2 client package using gapi.client.load, you will use this again to load the plus v1 client package. This will give you a number of packages and methods under the gapi.client.plus namespace.
The Plus API includes a package to load information about People, including getting them by their User ID or, since they have authenticated with you, you can use the special identifier "me".
Full details and an example are given at https://developers.google.com/+/api/latest/people/get, but here is an (untested) similar function to your getEmail() method that would get their full name:
function getFullName(){
// Load the Plus library to get the People package and methods
gapi.client.load('plus', 'v1', function() {
var request = gapi.client.plus.people.get('me');
request.execute(getFullNameCallback);
});
};
function getFullNameCallback(obj){
var el = document.getElementById('email');
var name = '';
if (obj['displayName']) {
name = 'Name: '+obj.displayName;
}
el.innerHTML = name;
toggleElement('name');
};
The above code snippet no longer seems to work.
Once again we are chasing our tails over something
google now changed......
error "Access Not Configured. Please use Google Developers Console to activate the API for your project."
I assumed it it might be the "Google+ API" so it is switched on in the developer console,
still no working however.
Yet api explorer shows promisingly that some sort of code can work,
however its a dogs breakfast trying to discern what javascript code is working there.
So so useful api explorer...., but how about google show a simple WORKING example in code that we can look at for this same request?

Meteor.http.get issue with Twitter API

I am using Meteor and the Twitter API for a project. I want to get information on a user from Twitter. I wrote a function that for example returns only the location of a user from Twitter. I believe this is the proper way to do a request on Meteor. Here it is :
Meteor.methods({getTwitterLocation: function (username) {
Meteor.http.get("https://api.twitter.com/1/users/show.json?screen_name="+ username +"&include_entities=true", function(error, result) {
if (result.statusCode === 200) {
var respJson = JSON.parse(result.content);
console.log(respJson.location);
console.log("location works");
return (respJson.location)
}else {
return ( "Unknown user ")
}
});
}});
Now this function will log what's in the console on my Git Bash. I get someones Location by doing a Meteor.call. But I want to post what that function returns on a page. In my case, I want to post in on a user's profile. This doesn't work. But the console.log(respJson.location) returns the location in my Git Bash but it won't display anything on the profile page. This is what I did on my profile page:
profile.js :
Template.profile.getLocation= function(){
return Meteor.call("getTwitterLocation","BillGates");
}
profile.html :
<template name="profile">
from {{getLocation}}
</template>
With that I get "Seattle, WA" and " "location works" on my Git Bash but nothing on the profile page. If anyone knows what I can do, that'd be really appreciated. Thanks.
Firstly when data is returned from the server you need to use a synchronous call, as the callback will return the data when the server already thinks the meteor method has completed. (the callback will be fired at a later time, when the data is returned from the server, by which time the meteor client would have already got a response)
var result = Meteor.http.get("https://api.twitter.com/1/users/show.json?screen_name="+ username +"&include_entities=true");
if (result.statusCode === 200) {
var respJson = JSON.parse(result.content);
console.log(respJson.location);
console.log("location works");
return (respJson.location)
}else {
return ( "Unknown user ")
}
The second is you need to use a Session hash to return the data from the template. This is because it will take time to get the response and the getLocation would expect an instant result (without a callback). At the moment client side javascript can't use synchronous api calls like on the server.
Template.profile.getLocation= function(){
return Session.get("twitterlocation");
}
Use the template created event to fire the meteor call:
Template.profile.created = function() {
Meteor.call("getTwitterLocation","BillGates", function(err,result) {
if(result && !err) {
Session.set("twitterlocation", result);
}
else
{
Session.set("twitterlocation", "Error");
}
});
});
Update:
Twitter has since updated its API to 1.1 a few modifications are required:
You now need to swap over to the 1.1 api by using 1.1 instead of 1. In addition you need to OAuth your requests. See https://dev.twitter.com/docs/auth/authorizing-request. Below contains sample data but you need to get proper keys
var authkey = "OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog",
oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg",
oauth_signature="tnnArxj06cWHq44gCs1OSKk%2FjLY%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp=""+(new Date().getTime()/1000).toFixed(0)+"",
oauth_token="370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb",
oauth_version="1.0"";
Be sure to remove the newlines, I've wrapped it to make it easy to read.
var result = Meteor.http.get("https://api.twitter.com/1.1/users/show.json?screen_name="+ username +"&include_entities=true",{headers:{Authorization : authkey});
If you find this a bit troublesome it might be easier to just use a package like https://github.com/Sewdn/meteor-twitter-api via meteorite to OAuth your requests for you.

How do get a new Facebook access token invisibly when my current one expires? (Windows 8 App C#)

Within my app (following various documentations) the user is able to login in to facebook via a dedicated login page. From this, the access token is given and the I save it. The thing is to get the token this way (using await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, loginUri, new Uri(redirectUri));, which seems the automatically show a login screen from facebook, I honestly have no idea how it appears...) means the user has to type their username and password again.
I don't want this to be the case, since I think if the user has logged in once, they shouldn't need to keep typing in their details again and again. However no matter what I've tried I can seem to get a new access token without going through this login screen again.
I've tried methods using the FacebookClient.Get() method, however it just doesn't exist in this version of the SDK. I have no idea what to use in its place, or what I need to send to Facebook to get a response.
So far this is what I have to log in for the first time (pretty much what is on the documentation)
string redirectUrl = "https://www.facebook.com/connect/login_success.html";
try
{
var loginUrl = fb.GetLoginUrl(new
{
client_id = FacebookHandler.FacebookAppId,
redirect_uri = redirectUrl,
scope = FacebookHandler.Permissions,
display = "touch",
response_type = "token"
});
Uri endUri = new Uri(redirectUrl);
WebAuthenticationResult webAuthRes = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, loginUrl, endUri);
if (webAuthRes.ResponseStatus == WebAuthenticationStatus.Success)
{
var callbackUri = new Uri(webAuthRes.ResponseData.ToString());
var facebookOAuthResult = fb.ParseOAuthCallbackUrl(callbackUri);
var accessToken = facebookOAuthResult.AccessToken;
if (String.IsNullOrEmpty(accessToken))
{
// User is not logged in, they may have canceled the login
}
else
{
// User is logged in and token was returned
FacebookHandler.AccessToken = accessToken;
LoginSucceeded();
}
}
else if (webAuthRes.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
{
Debug.WriteLine("Error: " + "HTTP Error returned by AuthenticateAsync() : " + webAuthRes.ResponseErrorDetail.ToString());
}
else
{
Debug.WriteLine("Error: " + "Error returned by AuthenticateAsync() : " + webAuthRes.ResponseStatus.ToString());
}
}
catch (Exception ex)
{
//
// Bad Parameter, SSL/TLS Errors and Network Unavailable errors are to be handled here.
//
Debug.WriteLine(ex);
throw ex;
}
On successive launches of the app, after the user as entered their details for the first time, the saved access token could be used, but it soon expires, which throws a FacebookOAuthException. This is where I have tried to invisibly get a new access token, and where its not working.
try
{
await fb.PostTaskAsync(url, argList);
}
catch (FacebookOAuthException exc)
{
Debug.WriteLine(exc.Message);
ValidateLoginUrl(GetLoginUrl());
//Problem is with the ValidateLoginUrl(), which would get an access token from the login url
}
One of the things I've tried was to use TryParseOAuthCallbackUrl(), on the loginUrl that I can get by using FacebookClient.GetLoginUrl() (which is successful), but when I try to parse it it just comes up with an InvalidOperationException, and otherwise no explanation.
What do I have to do in order to get a new access token without the user having to login in again? I have my app ID and secret, and I could probably save the users ID from the initial login for use later(?). Would any of that help do this?