I'm currently looking to automate a few tasks by creating a custom application that allows me to easily post status updates on my Facebook page(not my personal timeline). My backend is running on NodeJS.
My client-side code has the following:
window.fbAsyncInit = function() {
FB.init({
appId : 'xxxxxxxxxxxxx', // App ID
channelUrl : '//xxxxxxxxxxx, // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// Additional init code here
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
console.log("You are signed into FB");
var access_token = FB.getAuthResponse()['accessToken'];
console.log('Access Token = ' + access_token);
FB.api('/me/accounts', function(response) {
for(var i=0;i <response.data.length;i++){;
var page = response.data[i];
if(page.id==my_id){
var page_token = page.access_token;
console.log(page_token);
var param = 'callback=?&username=' + GetURLParameter('username')+'&session='+ GetURLParameter('session')+'&access_token='+ page_token;
$.post(saveTokenEndpoint, param, function(data) {
console.log(data);
});
}
}
});
FB.api('/me', function(response) {
username = response.name;
userid = response.id;
$('#username').text('~Hi '+username+'!');
$(document).trigger('fbInit');
});
// connected
} else if (response.status === 'not_authorized') {
// not_authorized
login();
} else {
login();
// not_logged_in
}
});
};
// Load the SDK Asynchronously
( function(d) {
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {
return;
}
js = d.createElement('script');
js.id = id;
js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
function login() {
FB.login(function(response) {
if (response.authResponse) {
console.log("You are signed into FB");
var access_token = FB.getAuthResponse()['accessToken'];
FB.api('/me', function(response) {
username = response.name;
userid = response.id;
$('#username').text('~Hi '+username+'!');
$(document).trigger('fbInit');
});
FB.api('/me/accounts', function(response) {
// handle response
for(page in response.data){
if(page.id==my_id){
var page_token = page.access_token;
console.log(page_token);
var param = 'callback=?&username=' + GetURLParameter('username')+'&session='+ GetURLParameter('session')+'&access_token='+ page_token;
$.post(saveTokenEndpoint, param, function(data) {
console.log(data);
});
}
}
});
} else {
// cancelled
}
}, {scope: 'publish_stream, manage_pages, offline_access'});
}
My server-side code:
// saves the token received for future use in posting
app.post('/api/saveToken',function(req,res){
var username = req.body.username;
var access_token = req.body.access_token;
var session = req.body.session;
user.findOne({
username: username,
session: session
},function(err, userObj){
if(userObj!=null){
userObj.token = access_token;
console.log(access_token);
userObj.save();
res.jsonp({status:'true'});
}else{
res.jsonp({status:'false'});
}
});
});
I'm using this method to post my posts on my page:
var data = querystring.stringify({
access_token: token,
message: message
});
var options = {
host: 'graph.facebook.com',
port: 443,
path: '/app_name/feed',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': data.length
}
};
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log("body: " + chunk);
});
res.on('end', function(){ // see http nodejs documentation to see end
console.log("\nfinished posting message");
conObj.approval = 'published';
conObj.save();
});
});
req.on('error', function(e) {
console.error(e);
});
req.write(data);
req.end();
Current situation:
My code is working and i can actually see the posts on the wall of my page.
BUT
It does not appear to anyone else except myself.
HOW I GOT IT TO APPEAR PROPERLY TEMPORARILY:
When i copy the token directly from the Graph API Explorer(/me/accounts), I got it to work.
https://developers.facebook.com/tools/explorer?method=GET&path=me%2Faccounts
Ultimately, all i want to do is find a way to post a post on my page
I monitored the differences that was made through both tokens and have found no differences. Their scope was to the 'public' and 'everyone'.
Experts do advice! I find this all very puzzling.
I'm intending to try NodeJS facebook such as facebook-node-sdk and nodejs-facebook-sdk libraries if all else fails.
Thanks for the replies in advance!
You should do OAUTH server side, not client side.
Here is a working example of posting a post through the Facebook Graph API using node.js here: http://code.runnable.com/facebook/UTlPM1-f2W1TAABY
The only dependency you're not already using is request, which you should be using.
Related
I'm adding recaptcha to a form and would like to know if there are any foreseeable problems with the following code:
router.post("/recaptcha", function(req, res) {
const secret = process.env.SECRET_KEY;
const userResponse = req.body["g-recaptcha-response"];
const url = "https://www.google.com/recaptcha/api/siteverify?secret=" + secret + "&response=" + userResponse;
https.get(url, function(response) {
response.on("data", function(data) {
const success = JSON.parse(data).success;
if (success === true) {
// do something
} else {
// do something else
}
});
});
});
Any suggestions would be great.
I'm able to get access oauth2 token from google api by using below code:
<html><head></head><body>
<script>
var YOUR_CLIENT_ID =
'568020407566-s1tdctjbjeocf5nt20l64midfo1atu4h.apps.googleusercontent.com';
var YOUR_REDIRECT_URI =
'https://us-central1-hyperledger-poc.cloudfunctions.net/oauthjax';
var fragmentString = location.hash.substring(1);
// Parse query string to see if page request is coming from OAuth 2.0 server.
var params = {};
var regex = /([^&=]+)=([^&]*)/g, m;
while (m = regex.exec(fragmentString)) {
params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
}
if (Object.keys(params).length > 0) {
localStorage.setItem('oauth2-test-params', JSON.stringify(params) );
if (params['state'] && params['state'] == 'try_sample_request') {
trySampleRequest();
}
}
// If there's an access token, try an API request.
// Otherwise, start OAuth 2.0 flow.
function trySampleRequest() {
var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
if (params && params['access_token']) {
var xhr = new XMLHttpRequest();
xhr.open('GET',
'https://www.googleapis.com' +
'access_token=' + params['access_token']);
xhr.onreadystatechange = function (e) {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.response);
} else if (xhr.readyState === 4 && xhr.status === 401) {
// Token invalid, so prompt for user permission.
oauth2SignIn();
}
};
xhr.send(null);
} else {
oauth2SignIn();
}
}
/*
* Create form to request access token from Google's OAuth 2.0 server.
*/
function oauth2SignIn() {
// Google's OAuth 2.0 endpoint for requesting an access token
var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
// Create element to open OAuth 2.0 endpoint in new window.
var form = document.createElement('form');
form.setAttribute('method', 'GET'); // Send as a GET request.
form.setAttribute('action', oauth2Endpoint);
// Parameters to pass to OAuth 2.0 endpoint.
var params = {'client_id': YOUR_CLIENT_ID,
'redirect_uri': YOUR_REDIRECT_URI,
'scope': 'https://www.googleapis.com/auth/userinfo.email',
'state': 'try_sample_request',
'include_granted_scopes': 'true',
'response_type': 'token'};
// Add form parameters as hidden input values.
for (var p in params) {
var input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', p);
input.setAttribute('value', params[p]);
form.appendChild(input);
}
// Add form to page and submit it to open the OAuth 2.0 endpoint.
document.body.appendChild(form);
form.submit();
}
</script>
<button onclick="trySampleRequest();">Try sample request</button>
</body></html>
I'm trying to get the token information using https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123 mentioned in below google document
https://developers.google.com/identity/protocols/oauth2/openid-connect#validatinganidtoken
I'm getting below error as response:
{
"error_description": "Invalid Value"
}
But if i use the same token to get user info, it was working fine by using below code and the response as well
code which i tried:
const token = req.body.access_token;
var options = {
host: 'www.googleapis.com',
port: 443,
//path: '/oauth2/v3/userinfo',
path: '/oauth2/v3/tokeninfo?id_token='+token,
method: 'GET',
headers: {'Authorization': 'Bearer '+ token}
}
// making the https get call
let data;
var getReq = await https.request(options, function(response) {
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', function() {
// Data reception is done, do whatever with it!
console.log("line 52");
// var parsed = JSON.parse(data);
console.log("line 54"+data);
res.send(data);
// console.log('data', parsed);
// console.log('endSTATUS: ' + parsed);
});
});
// console.log("response",recievedJSON);
/*getReq.on('end',function(){
res.send(valid);
});*/
getReq.end();
getReq.on('error', function(err) {
console.log('Error: ', err);
});
Response:
{
"sub": "1070944556782450037456",
"picture": "https://lh6.googleusercontent.com/-b32hSj9vONg/AAAAAAAAAAI/AAAAAAAAAAA/tasdfsadfBfIQ/photo.jpg",
"email": "xxxxxxxxx#gmail.com",
"email_verified": true
}
PouchDB and Cloud-Cloudant setup.
Development environment: Ionic hybrid App (AngularJS).
Would like to create database and set up permission from code.
Tried
put _security but received error code 400. Only reserved document ids may start with underscore.
Refer to Cloudant API regarding modifying permission. But failed to implement. Anyone could eliminate about how to perform this?
https://docs.cloudant.com/authorization.html#modifying-permissions
Example of my code.
var attendanceSecurity = {
"_id": "_security",
"cloudant": {
"nobody": []
}
};
attendanceSecurity['cloudant'][user.id] = ["_reader","_writer","_replicator"];
var user2 = {
name: username,
password: password
};
var pouchOpts = {
skipSetup: false
};
var ajaxOpts = {
ajax: {
headers: {
Authorization: 'Basic ' + window.btoa(user2.name + ':' + user2.password)
}
}
};
var url = 'https://' + attendanceUsername + '.cloudant.com/' + user.id;
var db = new PouchDB(url, pouchOpts);
db.login(user2.name, user2.password, ajaxOpts).then(function() {
return db.allDocs();
}).then(function(docs) {
db.put(attendanceSecurity).then(function (response) {
// handle response
console.log(response);
}).catch(function (err) {
console.log(err);
});
console.log(docs);
}).catch(function(error) {
console.error(error);
});
I am using digits web. I am using the cannonball example. I am running the below code on my local comptuter.
Heres my code of client side
<script>document.getElementById('digits-sdk').onload = function() {
Digits.init({ consumerKey: 'my consumer key' });
Digits.embed({
container: '#my-digits-container',
theme: {
/* Input fields borders */
},
phoneNumber: '+91',
})
.done(onLogin) /*handle the response*/
.fail(onLoginFailure);
};
function onLoginFailure(loginResponse) {
console.log('Digits login failed.');
//setDigitsButton('Verify again');
}
/* Validate and log use in. */
function onLogin(loginResponse){
// Send headers to your server and validate user by calling Digits’ API
//var oAuthHeaders = loginResponse.oauth_echo_headers;
var oAuthHeaders = parseOAuthHeaders(loginResponse.oauth_echo_headers);
$.ajax({
type: 'POST',
url: '/digits',
data: oAuthHeaders,
success: onDigitsSuccess
});
// setDigitsButton('Step 2.....');
}
function parseOAuthHeaders(oAuthEchoHeaders) {
var credentials = oAuthEchoHeaders['X-Verify-Credentials-Authorization'];
var apiUrl = oAuthEchoHeaders['X-Auth-Service-Provider'];
console.log(apiUrl);
return {
apiUrl: apiUrl,
credentials: credentials
};
}
function onDigitsSuccess(response) {
console.log(response.phoneNumber);
setDigitsNumber(response.phoneNumber);
}
function setDigitsNumber(phoneNumber) {
document.getElementById('notr').value = phoneNumber;
console.log('Digits phone number retrieved.');
}
</script>
In the above code I have changed the consumer key only. So ignore that.
And heres my server code
var express = require("express");
var app = express();
var router = express.Router();
var path = __dirname + '/static/';
app.use(express.static(__dirname + '/static'));
router.use(function (req,res,next) {
console.log("/" + req.method);
next();
});
router.get("/",function(req,res){
res.sendFile(path + "homepage9.html");
});
router.get("/about",function(req,res){
res.sendFile(path + "about.html");
});
router.get("/contact",function(req,res){
res.sendFile(path + "contact.html");
});
app.use("/",router);
app.use("*",function(req,res){
res.sendFile(path + "404.html");
});
app.listen(3000,function(){
console.log("Live at Port 3000");
});
var fs = require('fs');
var nconf = require('nconf');
var url = require('url');
var request = require('request');
router.post('/digits', function (req, res) {
console.log("digits entered")
var apiUrl = req.body['apiUrl']
var credentials = req.body['credentials']
var verified = true;
var messages = [];
if (credentials.indexOf('oauth_consumer_key="' + 'my consumer key' + '"') == -1) {
verified = false;
messages.push('The Digits API key does not match.');
}
var hostname = url.parse(req.body.apiUrl).hostname;
if (hostname != 'api.digits.com' && hostname != 'api.twitter.com') {
verified = false;
messages.push('Invalid API hostname.');
}
// Do not perform the request if the API key or hostname are not verified.
if (!verified) {
return res.send({
phoneNumber: "",
userID: "",
error: messages.join(' ')
});
}
// Prepare the request to the Digits API.
var options = {
url: apiUrl,
headers: {
'Authorization': credentials
}
};
// Perform the request to the Digits API.
request.get(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Send the verified phone number and Digits user ID.
var digits = JSON.parse(body)
return res.send({
phoneNumber: digits.phone_number,
userID: digits.id_str,
error: ''
});
} else {
// Send the error.
return res.send({
phoneNumber: '',
userID: '',
error: error.message
});
}
});
});
But on the node console i am getting
cannot read property 'apiUrl' of undefined.
on google chrome console i am getting
Failed to load resource: the server responded with a status of 500 (Internal Server Error)
Can any one help of what I am doing wrong.
Also in the cannon ball example i found that it nowhere uses the consumer secret key. Why is that?
I am trying to build simple social network and I am following this book(Building Node Applications with MongoDB and Backbone)(https://github.com/Swiftam/book-node-mongodb-backbone/tree/master/ch10). However, I just realized that the node.js version has been updated.
I tied to solve some the issue however I got problem in chat.js that states this is the error:
ch10/routes/chat.js:27
data.sessionStore.load(data.sessionID, function(err, session) {
TypeError: Cannot read property 'load' of undefined
module.exports = function(app, models) {
var io = require('socket.io');
var utils = require('connect').utils;
var cookie = require('cookie');
this.io = io;
//var Session = require('connect').middleware.session.Session;
var sio = io.listen(app.server);
sio.configure(function() {
// Utility methods to see if the account is online
app.isAccountOnline = function(accountId) {
var clients = sio.sockets.clients(accountId);
return (clients.length > 0);
};
sio.set('authorization', function(data, accept) {
var signedCookies = cookie.parse(data.headers.cookie);
// var cookies = utils.parseSignedCookies(signedCookies, app.sessionSecret);
// data.sessionID = cookies['express.sid'];
data.sessionStore = app.sessionStore;
data.sessionStore.load(data.sessionID, function(err, session) {
if (err || !session) {
accept("Error", false);
} else {
data.session = session;
accept(null, true);
}
});
});
sio.sockets.on('connection', function(socket) {
var session = socket.handshake.session;
var accountId = session.accountId;
var sAccount = null;
socket.join(accountId);
io.use(function (socket, next) { next(); });
// Immediately trigger the login event
// of this account
app.triggerEvent('event:' + accountId, {
from: accountId,
action: 'login'
});
var handleContactEvent = function(eventMessage) {
socket.emit('contactEvent', eventMessage);
};
var subscribeToAccount = function(accountId) {
var eventName = 'event:' + accountId;
app.addEventListener(eventName, handleContactEvent);
console.log('Subscribing to ' + eventName);
};
// Find the account contacts and subscribe
models.Account.findById(accountId, function subscribeToFriendFeed(account) {
var subscribedAccounts = {};
sAccount = account;
account.contacts.forEach(function(contact) {
if (!subscribedAccounts[contact.accountId]) {
subscribeToAccount(contact.accountId);
subscribedAccounts[contact.accountId] = true;
}
});
// Subscribed to my feed as well
if (!subscribedAccounts[accountId]) {
subscribeToAccount(accountId);
}
});
// Remove listeners if socket disconnects
socket.on('disconnect', function() {
sAccount.contacts.forEach(function(contact) {
var eventName = 'event:' + contact.accountId;
app.removeEventListener(eventName, handleContactEvent);
console.log('Unsubscribing from ' + eventName);
});
app.triggerEvent('event:' + accountId, {
from: accountId,
action: 'logout'
});
});
var cookieParser = require('cookie-parser')(SESSION_SECRET);
// ### Cookie parser
// Wrapper arround Express cookie parser, so we can use the same cookie parser for socket.io.
// Parse Cookie header and populate `socket.request.cookies` with an object keyed by the cookie names.
// Uses signed cookies by passing a secret string, which assigns `socket.request.secret` so it may be used by other middleware.
function cookieParserWrapper (socket, next) {
// request, response and callback
cookieParser(socket.request, {}, next);
}
// Handle incoming chats from client
socket.on('chatclient', function(data) {
sio.sockets.in(data.to).emit('chatserver', {
from: accountId,
text: data.text
});
});
});
});
}
Without testing the code myself or anything.
"TypeError: Cannot read property 'load' of undefined"
That particular error means that data.sessionStore is undefined and that "load" does not exists as a property, since there is literally nothing defined in data.sessionStore.
So the problem in my opinion is that your session system is not working properly. Hope that helps a bit!