I\'m working on using Facebook\'s Javascript SDK for authentication. I\'ve been able to import the SDK properly and put a Like button on my page. But, the facebook login but
I post my solution here, as the answers helped me to implement it, but the accepted answer from ritmatter did not work without the
FB.Event.subscribe('auth.statusChange', function(response)
statement from RubyFanatic's answer. Furthermore the "onlogin" confused me a lot. It is simply not required in my eyes.
I want to share it, as this is a c&p solution, here my full code against fb api v2.8 (react-bootstrap can be kicked of course):
/* global FB*/
import React, { Component } from 'react';
import { Grid, Row, Col } from 'react-bootstrap';
export default class Login extends Component {
constructor(props) {
super(props);
this.checkLoginState = this.checkLoginState.bind(this);
this.handleClick = this.handleClick.bind(this);
this.testAPI = this.testAPI.bind(this);
this.statusChangeCallback = this.statusChangeCallback.bind(this);
}
componentDidMount() {
window.fbAsyncInit = function() {
FB.init({
appId : 'YOURAPIKEYHERE',
cookie : true,
xfbml : true,
version : 'v2.8'
});
FB.AppEvents.logPageView();
FB.Event.subscribe('auth.statusChange', function(response) {
if (response.authResponse) {
this.checkLoginState();
} else {
console.log('---->User cancelled login or did not fully authorize.');
}
}.bind(this));
}.bind(this);
// Load the SDK asynchronously
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = '//connect.facebook.net/en_US/sdk.js';
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
// Here we run a very simple test of the Graph API after login is
// successful. See statusChangeCallback() for when this call is made.
testAPI() {
console.log('Welcome! Fetching your information.... ');
FB.api('/me', function(response) {
console.log('Successful login for: ' + response.name);
document.getElementById('status').innerHTML =
'Thanks for logging in, ' + response.name + '!';
});
}
// This is called with the results from from FB.getLoginStatus().
statusChangeCallback(response) {
if (response.status === 'connected') {
// Logged into your app and Facebook.
this.testAPI();
} else if (response.status === 'not_authorized') {
// The person is logged into Facebook, but not your app.
document.getElementById('status').innerHTML = 'Please log ' +
'into this app.';
} else {
// The person is not logged into Facebook, so we're not sure if
// they are logged into this app or not.
document.getElementById('status').innerHTML = 'Please log ' +
'into Facebook.';
}
}
checkLoginState() {
FB.getLoginStatus(function(response) {
this.statusChangeCallback(response);
}.bind(this));
}
handleClick() {
FB.login(this.checkLoginState());
}
render() {
return (
<main>
<Grid fluid>
<h1>
Facebook Login
</h1>
</Grid>
<Grid>
<Row>
<Col xs={12}>
<a href="#" onClick={this.handleClick} onlogin={this.checkLoginState}>Login</a>
<div id="status"></div>
</Col>
</Row>
</Grid>
</main>
);
}
}
I have figured out how to modify the Facebook tutorial for the Login API with ReactJS. I hope this helps anyone else struggling with this.
Firstly, in the react component where you want the Login link, include this code:
componentDidMount: function() {
window.fbAsyncInit = function() {
FB.init({
appId : '<YOUR_APP_ID>',
cookie : true, // enable cookies to allow the server to access
// the session
xfbml : true, // parse social plugins on this page
version : 'v2.1' // use version 2.1
});
// Now that we've initialized the JavaScript SDK, we call
// FB.getLoginStatus(). This function gets the state of the
// person visiting this page and can return one of three states to
// the callback you provide. They can be:
//
// 1. Logged into your app ('connected')
// 2. Logged into Facebook, but not your app ('not_authorized')
// 3. Not logged into Facebook and can't tell if they are logged into
// your app or not.
//
// These three cases are handled in the callback function.
FB.getLoginStatus(function(response) {
this.statusChangeCallback(response);
}.bind(this));
}.bind(this);
// Load the SDK asynchronously
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
},
// Here we run a very simple test of the Graph API after login is
// successful. See statusChangeCallback() for when this call is made.
testAPI: function() {
console.log('Welcome! Fetching your information.... ');
FB.api('/me', function(response) {
console.log('Successful login for: ' + response.name);
document.getElementById('status').innerHTML =
'Thanks for logging in, ' + response.name + '!';
});
},
// This is called with the results from from FB.getLoginStatus().
statusChangeCallback: function(response) {
console.log('statusChangeCallback');
console.log(response);
// The response object is returned with a status field that lets the
// app know the current login status of the person.
// Full docs on the response object can be found in the documentation
// for FB.getLoginStatus().
if (response.status === 'connected') {
// Logged into your app and Facebook.
this.testAPI();
} else if (response.status === 'not_authorized') {
// The person is logged into Facebook, but not your app.
document.getElementById('status').innerHTML = 'Please log ' +
'into this app.';
} else {
// The person is not logged into Facebook, so we're not sure if
// they are logged into this app or not.
document.getElementById('status').innerHTML = 'Please log ' +
'into Facebook.';
}
},
// This function is called when someone finishes with the Login
// Button. See the onlogin handler attached to it in the sample
// code below.
checkLoginState: function() {
FB.getLoginStatus(function(response) {
this.statusChangeCallback(response);
}.bind(this));
},
handleClick: function() {
FB.login(this.checkLoginState());
},
Then, in your render method, make sure you have some HTML that will call that handleClick:
<a href="#" onClick={this.handleClick}>Login</a>
Note, this is the same code from the tutorial, but placed in a ReactJS component. The only difference is that you have to bind this strategically to make the Facebook API functions part of your react component. This login will finish with a response message parsed from the response given by FB.getLoginStatus(). You can also take the token out of that response object and send it to your backend for authentication with something like passport-facebook-token.
This is the solution I used to get login callback. You can add this code for your Facebook login button in your render method:
<div className="fb-login-button" data-max-row="5"
data-size="large"
data-show-faces="false"
data-auto-logout-link="false"
href="javascript:void(0)">Login</div>
In your code, add these lines:
componentDidMount: function() {
// facebook signin button render
window.fbAsyncInit = function() {
FB.init({
appId : 'replace with your app id here',
cookie : true, // enable cookies to allow the server to access
// the session
xfbml : true, // parse social plugins on this page
version : 'v2.1' // use version 2.1
});
// login callback implementation goes inside the function() { ... } block
FB.Event.subscribe('auth.statusChange', function(response) {
// example implementation
if (response.authResponse) {
console.log('Welcome! Fetching your information.... ');
FB.api('/me', function(response) {
console.log('Good to see you, ' + response.name + '.');
});
} else {
console.log('User cancelled login or did not fully authorize.');
}
});
}.bind(this);
// Load the SDK asynchronously
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
}
Calling FB.Event.subscribe('auth.statusChange', callback_function) during component initialization is important because that's basically your login callback. Checkout here for FB.Event documentation.
I wrote a mixin class to address this.
https://github.com/genxstylez/react-oauth-mixin
Find simplest code below:
import React, { Component } from 'react';
import './App.css';
import FacebookLogin from 'react-facebook-login';
import GoogleLogin from 'react-google-login';
class App extends Component {
render() {
const responseFacebook = (response) => {
console.log(response);
}
const responseGoogle = (response) => {
console.log(response);
}
return (
<div className="App">
<h1>LOGIN WITH FACEBOOK AND GOOGLE</h1>
<FacebookLogin
appId="" //APP ID NOT CREATED YET
fields="name,email,picture"
callback={responseFacebook}
/>
<br />
<br />
<GoogleLogin
clientId="" //CLIENTID NOT CREATED YET
buttonText="LOGIN WITH GOOGLE"
onSuccess={responseGoogle}
onFailure={responseGoogle}
/>
</div>
);
}
}
export default App;
I used Promises for Facebook Auth flow
mixins/facebook.js
const promises = {
init: () => {
return new Promise((resolve, reject) => {
if (typeof FB !== 'undefined') {
resolve();
} else {
window.fbAsyncInit = () => {
FB.init({
appId : '<app_id>',
cookie : true,
xfbml : true,
version : 'v2.5'
});
resolve();
};
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
});
},
checkLoginState: () => {
return new Promise((resolve, reject) => {
FB.getLoginStatus((response) => {
response.status === 'connected' ? resolve(response) : reject(response);
});
});
},
login: () => {
return new Promise((resolve, reject) => {
FB.login((response) => {
response.status === 'connected' ? resolve(response) : reject(response);
});
});
},
logout: () => {
return new Promise((resolve, reject) => {
FB.logout((response) => {
response.authResponse ? resolve(response) : reject(response);
});
});
},
fetch: () => {
return new Promise((resolve, reject) => {
FB.api(
'/me',
{fields: 'first_name, last_name, gender'},
response => response.error ? reject(response) : resolve(response)
);
});
}
}
export const Facebook = {
doLogin() {
this.setState({
loading: true
}, () => {
promises.init()
.then(
promises.checkLoginState,
error => { throw error; }
)
.then(
response => { this.setState({status: response.status}); },
promises.login
)
.then(
promises.fetch,
error => { throw error; }
)
.then(
response => { this.setState({loading: false, data: response, status: 'connected'}); },
error => { throw error; }
)
.catch((error) => {
this.setState({loading: false, data: {}, status: 'unknown'});
console.warn(error);
});
});
},
doLogout() {
this.setState({
loading: true
}, () => {
promises.init()
.then(
promises.checkLoginState,
error => { throw error; }
)
.then(
promises.logout,
error => { this.setState({data: {}, status: 'unknown'}); }
)
.then(
response => { this.setState({loading: false, data: {}, status: 'unknown'}); },
error => { throw error; }
)
.catch(error => {
this.setState({loading: false, data: {}, status: 'unknown'});
console.warn(error);
});
});
},
checkStatus() {
this.setState({
loading: true
}, () => {
promises.init()
.then(
promises.checkLoginState,
error => { throw error; }
)
.then(
response => { this.setState({status: response.status}); },
error => { throw error; }
)
.then(
promises.fetchUser,
error => { throw error; }
)
.then(
response => { this.setState({loading: false, data: response, status: 'connected'}); },
error => { throw error; }
)
.catch((error) => {
this.setState({loading: false, data: {}, status: 'unknown'});
console.warn(error);
});
});
}
};
Profile.jsx
import {Facebook} from './mixins/Facebook.js';
import {Button} from 'react-bootstrap';
const ProfileHandler = React.createClass({
mixins: [Facebook],
componentDidMount() {
this.checkStatus();
},
getInitialState() {
return {
status: 'unknown',
loading: false,
data: {}
};
},
render() {
const loading = this.state.loading ? <p>Please wait, profile is loading ...</p> : null;
const message = this.state.status === 'connected'
? (<div>
Hi {data.name}!
<Button onClick={this.doLogout}>Logout</Button>
</div>)
: (<Button onClick={this.doLogin}>Login</Button>);
return (
<div>
{message}
{loading}
</div>
);
}
});