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
}
Related
I'm trying to access the authorization server that i have in okta, so i can see the users profile (in this case the user first name and favorite color )from the alexa skill but keep getting an error.
i just want to retrieve the user info (claims in okta name/color).i already set up the account linking in alexa, so there is probably an easier approach since the clientID and clientSecret is already configured.
Error message
{
"error": "access_denied",
"error_description": "The requested feature is not enabled in this environment."
}
is this something i have to enable in okta? can i do it in okta developers console with the free tier?
Code
function validateAccessToken(token, callback) {
console.log("token: ", token);
//start
var clientId = '**okta open id connect client id generated earlier**';
var clientSecret = '**okta open id connect client secret generated earlier**';
var auth = "Basic " + new Buffer.from(clientId + ":" + clientSecret).toString("base64");
var https = require('https');
var tokenParam = '?token=' + token;
var tokenHintParam = '&token_type_hint=access_token';
var tokenQuery = tokenParam + tokenHintParam;
var optionspost = {
host: '**your okta org**.oktapreview.com',
port: 443,
path: '/oauth2/**your authorization server id**/v1/introspect' + tokenQuery,
method: 'POST',
headers: {
'Authorization': auth,
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
}
};
console.log(optionspost);
var jsonResponseUser;
var firstName;
var favoriteColor;
console.log("pre Req Post");
var jsonObject;
var reqPost = https.request(optionspost, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('POST result:\n');
process.stdout.write(d);
console.info('\n\nPOST completed');
jsonResponseUser = JSON.parse(d);
firstName = jsonResponseUser['FirstNameClaim'];
favoriteColor = jsonResponseUser['FavoriteColorClaim'];
let responseVoice = firstName + '\'s Favorite Color is ' + favoriteColor;
console.log("responseVoice :" + responseVoice);
callback(responseVoice);
});
});
reqPost.end();
reqPost.on('error', function(e) {
console.error(e);
});
}
const FavoriteColorHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' &&
request.intent.name === 'FavoriteColorIntent';
},
handle(handlerInput) {
let favoriteColor = '';
let request = handlerInput.requestEnvelope.request;
console.log(handlerInput.requestEnvelope.context.System.user.accessToken);
let token = handlerInput.requestEnvelope.context.System.user.accessToken;
return new Promise((resolve) => {
validateAccessToken(token, function(result) {
// setTimeout(1000000000000);
console.log("inside Opp Handler, responseVoice: " + result);
resolve(handlerInput.responseBuilder.speak(result).getResponse());
});
});
},
};
While authenticating with google i m getting this error:
TypeError: crypto.createCredentials is not a function
at exports.OAuth2._request (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\oauth\lib\oauth2.js:33:22)
at exports.OAuth2.getOAuthAccessToken (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\oauth\lib\oauth2.js:130:8)
at loaded (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\passport-oauth2\lib\strategy.js:173:20)
at NullStore.verify (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\passport-oauth2\lib\state\null.js:9:3)
at Strategy.OAuth2Strategy.authenticate (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\passport-oauth2\lib\strategy.js:219:26)
at attempt (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\passport\lib\middleware\authenticate.js:366:16)
at authenticate (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\passport\lib\middleware\authenticate.js:367:7)
at Layer.handle [as handle_request] (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\express\lib\router\layer.js:95:5)
at next (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\express\lib\router\layer.js:95:5)
at D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\express\lib\router\index.js:281:22
at Function.process_params (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\express\lib\router\index.js:335:12)
at next (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\express\lib\router\index.js:275:10)
at Function.handle (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\express\lib\router\index.js:174:3)
at router (D:\WEB_D_CODING_NINJAS\Back-end\6.major\node_modules\express\lib\router\index.js:47:12)
faced this doubt myself, took a lot of effort but finally, I figured it out, this is a problem because of your file in node modules read the error and reach here
node_modules\oauth\lib\oauth2.js:33 , on line 33 you will see that crypto.createCredentails command, I don't know why this file gets installed but change the code inside it
make it this one
var querystring= require('querystring'),
crypto= require('crypto'),
https= require('https'),
http= require('http'),
URL= require('url'),
OAuthUtils= require('./_utils');
exports.OAuth2= function(clientId, clientSecret, baseSite, authorizePath, accessTokenPath, customHeaders) {
this._clientId= clientId;
this._clientSecret= clientSecret;
this._baseSite= baseSite;
this._authorizeUrl= authorizePath || "/oauth/authorize";
this._accessTokenUrl= accessTokenPath || "/oauth/access_token";
this._accessTokenName= "access_token";
this._authMethod= "Bearer";
this._customHeaders = customHeaders || {};
this._useAuthorizationHeaderForGET= false;
//our agent
this._agent = undefined;
};
// Allows you to set an agent to use instead of the default HTTP or
// HTTPS agents. Useful when dealing with your own certificates.
exports.OAuth2.prototype.setAgent = function(agent) {
this._agent = agent;
};
// This 'hack' method is required for sites that don't use
// 'access_token' as the name of the access token (for requests).
// ( http://tools.ietf.org/html/draft-ietf-oauth-v2-16#section-7 )
// it isn't clear what the correct value should be atm, so allowing
// for specific (temporary?) override for now.
exports.OAuth2.prototype.setAccessTokenName= function ( name ) {
this._accessTokenName= name;
}
// Sets the authorization method for Authorization header.
// e.g. Authorization: Bearer <token> # "Bearer" is the authorization method.
exports.OAuth2.prototype.setAuthMethod = function ( authMethod ) {
this._authMethod = authMethod;
};
// If you use the OAuth2 exposed 'get' method (and don't construct your own _request call )
// this will specify whether to use an 'Authorize' header instead of passing the access_token as a query parameter
exports.OAuth2.prototype.useAuthorizationHeaderforGET = function(useIt) {
this._useAuthorizationHeaderForGET= useIt;
}
exports.OAuth2.prototype._getAccessTokenUrl= function() {
return this._baseSite + this._accessTokenUrl; /* + "?" + querystring.stringify(params); */
}
// Build the authorization header. In particular, build the part after the colon.
// e.g. Authorization: Bearer <token> # Build "Bearer <token>"
exports.OAuth2.prototype.buildAuthHeader= function(token) {
return this._authMethod + ' ' + token;
};
exports.OAuth2.prototype._chooseHttpLibrary= function( parsedUrl ) {
var http_library= https;
// As this is OAUth2, we *assume* https unless told explicitly otherwise.
if( parsedUrl.protocol != "https:" ) {
http_library= http;
}
return http_library;
};
exports.OAuth2.prototype._request= function(method, url, headers, post_body, access_token, callback) {
var parsedUrl= URL.parse( url, true );
if( parsedUrl.protocol == "https:" && !parsedUrl.port ) {
parsedUrl.port= 443;
}
var http_library= this._chooseHttpLibrary( parsedUrl );
var realHeaders= {};
for( var key in this._customHeaders ) {
realHeaders[key]= this._customHeaders[key];
}
if( headers ) {
for(var key in headers) {
realHeaders[key] = headers[key];
}
}
realHeaders['Host']= parsedUrl.host;
if (!realHeaders['User-Agent']) {
realHeaders['User-Agent'] = 'Node-oauth';
}
if( post_body ) {
if ( Buffer.isBuffer(post_body) ) {
realHeaders["Content-Length"]= post_body.length;
} else {
realHeaders["Content-Length"]= Buffer.byteLength(post_body);
}
} else {
realHeaders["Content-length"]= 0;
}
if( access_token && !('Authorization' in realHeaders)) {
if( ! parsedUrl.query ) parsedUrl.query= {};
parsedUrl.query[this._accessTokenName]= access_token;
}
var queryStr= querystring.stringify(parsedUrl.query);
if( queryStr ) queryStr= "?" + queryStr;
var options = {
host:parsedUrl.hostname,
port: parsedUrl.port,
path: parsedUrl.pathname + queryStr,
method: method,
headers: realHeaders
};
this._executeRequest( http_library, options, post_body, callback );
}
exports.OAuth2.prototype._executeRequest= function( http_library, options, post_body, callback ) {
// Some hosts *cough* google appear to close the connection early / send no content-length header
// allow this behaviour.
var allowEarlyClose= OAuthUtils.isAnEarlyCloseHost(options.host);
var callbackCalled= false;
function passBackControl( response, result ) {
if(!callbackCalled) {
callbackCalled=true;
if( !(response.statusCode >= 200 && response.statusCode <= 299) && (response.statusCode != 301) && (response.statusCode != 302) ) {
callback({ statusCode: response.statusCode, data: result });
} else {
callback(null, result, response);
}
}
}
var result= "";
//set the agent on the request options
if (this._agent) {
options.agent = this._agent;
}
var request = http_library.request(options);
request.on('response', function (response) {
response.on("data", function (chunk) {
result+= chunk
});
response.on("close", function (err) {
if( allowEarlyClose ) {
passBackControl( response, result );
}
});
response.addListener("end", function () {
passBackControl( response, result );
});
});
request.on('error', function(e) {
callbackCalled= true;
callback(e);
});
if( (options.method == 'POST' || options.method == 'PUT') && post_body ) {
request.write(post_body);
}
request.end();
}
exports.OAuth2.prototype.getAuthorizeUrl= function( params ) {
var params= params || {};
params['client_id'] = this._clientId;
return this._baseSite + this._authorizeUrl + "?" + querystring.stringify(params);
}
exports.OAuth2.prototype.getOAuthAccessToken= function(code, params, callback) {
var params= params || {};
params['client_id'] = this._clientId;
params['client_secret'] = this._clientSecret;
var codeParam = (params.grant_type === 'refresh_token') ? 'refresh_token' : 'code';
params[codeParam]= code;
var post_data= querystring.stringify( params );
var post_headers= {
'Content-Type': 'application/x-www-form-urlencoded'
};
this._request("POST", this._getAccessTokenUrl(), post_headers, post_data, null, function(error, data, response) {
if( error ) callback(error);
else {
var results;
try {
// As of http://tools.ietf.org/html/draft-ietf-oauth-v2-07
// responses should be in JSON
results= JSON.parse( data );
}
catch(e) {
// .... However both Facebook + Github currently use rev05 of the spec
// and neither seem to specify a content-type correctly in their response headers :(
// clients of these services will suffer a *minor* performance cost of the exception
// being thrown
results= querystring.parse( data );
}
var access_token= results["access_token"];
var refresh_token= results["refresh_token"];
delete results["refresh_token"];
callback(null, access_token, refresh_token, results); // callback results =-=
}
});
}
// Deprecated
exports.OAuth2.prototype.getProtectedResource= function(url, access_token, callback) {
this._request("GET", url, {}, "", access_token, callback );
}
exports.OAuth2.prototype.get= function(url, access_token, callback) {
if( this._useAuthorizationHeaderForGET ) {
var headers= {'Authorization': this.buildAuthHeader(access_token) }
access_token= null;
}
else {
headers= {};
}
this._request("GET", url, headers, "", access_token, callback );
}
after changing this file, google OAuth will work just fine
Hi I'm trying to update a Google Doc with NodeJS using the Google Drive API and I'm getting this error:
{
"error": {
"code": 500,
"message": null
}
}
Here's the relevant code :
var j = new google.auth.JWT(
creds.client_email,
null,
creds.private_key,
[
"https://www.googleapis.com/auth/drive"
]
);
async function refreshTokens() {
startedWaiting = true;
return j.authorize((r,t) => {
startedWaiting = false;
timeTillNeedRefresh = t["expiry_date"] - Date.now();
setTimeout(function() {
refreshTokens();
// console.log("doing Q", Q);
}, timeTillNeedRefresh);
tokens = t;
console.log("GOT A TOKEN", tokens);
Q.forEach(x=>x());
Q = [];
});
}
async function start() {
await refreshTokens();
}
start();
function myFetch(opts) {
if(!opts) opts = {};
var cb = opts.cb || empty;
var headers = {
'Accept-Encoding': 'gzip',
'User-Agent': 'google-api-nodejs-client/0.7.2 (gzip)',
Authorization:tokens.token_type +" "+ tokens.access_token,
Accept:"application/json"
};
if(opts.headers) {
for(k in opts.headers) {
headers[k] = opts.headers[k];
}
}
fetch(
opts.url
|| "",
{
method:opts.method || "GET",
headers: headers
})
.then(res => res.text())
.then(body => {
cb(body);
});
}
updateFile({
id: "1vebqOamZ9QB4HqfUaQN-U9Zt4y33eij-I21glMvaPVQ",
content: "hi there"
});
async function allFuncs(tmp) {
if(tokens === null) {
console.log("DOING it later")
Q.push(tmp);
await refreshTokens();
} else if(startedWaiting || timeTillNeedRefresh <= 0) {
console.log("NOT for a while");
Q.push(tmp);
} else {
console.log("THIS is what should happen");
start = Date.now();
tmp();
}
}
async function updateFile(opts) {
var id = opts.id,
content = opts.content || "";
if(id) {
allFuncs(() => {
myFetch({
url:`https://www.googleapis.com/upload/drive/v3/files/${id}?uploadType=media`,
method:"PATCH",
headers: {
body: opts.content,
"Content-Type": "application/vnd.google-apps.document"
},
cb(b) {
console.log(b, "DID I DO IT?!");
}
});
});
}
}
I tried looking up what this error means but I couldn't find anything related to nodejs...
Does anyone know if its a header issue or is there any way to fix it?
I don't know if its possible to do wih a service key, or if you HAVE to verify the user in order to do so??
SEEMINGLY if the service key email has edit permissions for the file, it should just be able to edit it at will.
You want to overwrite the existing Google Document by a text of hi there with Drive API using Service Account.
The Google Document is shared with the Service Account.
You can use googleapis.
I could understand like above. If my understanding is correct, how about this sample script? In this sample script, I used the files.update method of Drive API.
Sample script:
Before you run the script, please set the json file path downloaded when the Service Account is created. And please confirm the file ID of Google Document, again.
const stream = require('stream');
const {google} = require('googleapis');
const creds = require('###'); // Please set the json file path downloaded when the Service Account is created.
const jwtClient = new google.auth.JWT(
creds.client_email,
null,
creds.private_key,
['https://www.googleapis.com/auth/drive'],
null
);
const id = "1vebqOamZ9QB4HqfUaQN-U9Zt4y33eij-I21glMvaPVQ"; // Please set the file ID of Google Document
const content = "hi there"; // Please set the text.
const drive = google.drive({version: 'v3', auth: jwtClient});
const buf = Buffer.from(content, 'binary');
const buffer = Uint8Array.from(buf);
var bufferStream = new stream.PassThrough();
bufferStream.end(buffer);
const media = {
mimeType: 'application/vnd.google-apps.document',
body: bufferStream,
};
drive.files.update({
fileId: id,
media: media,
}, (err, res) => {
if (err) {
console.log(err);
return;
}
console.log(res.data);
});
Note:
When you run the script, the existing Google Document is overwritten. So please be careful this. I recommend to use a sample Document for testing.
If this script didn't work, please confirm the following points.
Drive API is enabled at API console.
The Service Account can be used.
The Google Document is shared with the Service Account.
The version of googleapis is the latest one.
Reference:
Files: update
Edit:
You don't want to use googleapis.
You want to overwrite Google Document with a text value without using googleapis.
From your comments, I understood like above. If my understanding is correct, how about this sample script? When you run this script, please confirm the following points.
About the script,
Please set privateKey and clientEmail from JSON file of Service Account.
Please set the file ID of the existing Google Document you want to overwrite.
Drive API is enabled at API console.
The Service Account can be used.
The Google Document is shared with the Service Account.
The version of googleapis is the latest one.
Sample script:
const cryptor = require('crypto');
const request = require('request');
// Get access token using Service Account
function getAccessToken(serviceAccount) {
const scopes = ["https://www.googleapis.com/auth/drive"];
const url = "https://www.googleapis.com/oauth2/v4/token";
const header = {
alg: "RS256",
typ: "JWT",
};
const now = Math.floor(Date.now() / 1000);
const claim = {
iss: serviceAccount.clientEmail,
scope: scopes.join(" "),
aud: url,
exp: (now + 3600).toString(),
iat: now.toString(),
};
const signature = Buffer.from(JSON.stringify(header)).toString('base64') + "." + Buffer.from(JSON.stringify(claim)).toString('base64');
var sign = cryptor.createSign('RSA-SHA256');
sign.update(signature);
const jwt = signature + "." + sign.sign(serviceAccount.privateKey, 'base64');
return new Promise(function(resolve, reject) {
request({
method: "post",
url: url,
body: JSON.stringify({
assertion: jwt,
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
}),
}, (err, res, body) => {
if (err) {
console.log(err);
return;
}
const obj = JSON.parse(body);
resolve(obj.access_token);
});
});
}
// Overwrite file in Google Drive
function overWriting(object) {
const metadata = {
mimeType: "application/vnd.google-apps.document",
};
const url = "https://www.googleapis.com/upload/drive/v3/files/" + object.googleDocumentFileId + "?uploadType=multipart";
const boundary = "xxxxxxxxxxx";
var data = "--" + boundary + "\r\n";
data += "Content-Disposition: form-data; name=\"metadata\"\r\n";
data += "Content-Type: application/json; charset=UTF-8\r\n\r\n";
data += JSON.stringify(metadata) + "\r\n";
data += "--" + boundary + "\r\n";
data += "Content-Disposition: form-data; name=\"file\"; filename=\"sample.txt\"\r\n";
data += "Content-Type: text/plain" + "\r\n\r\n";
const payload = Buffer.concat([
Buffer.from(data, "utf8"),
new Buffer(object.textData, 'binary'),
Buffer.from("\r\n--" + boundary + "--", "utf8"),
]);
const options = {
method: 'patch',
url: url,
headers: {
"Content-Type": "multipart/related; boundary=" + boundary,
'Authorization': 'Bearer ' + object.accessToken,
},
body: payload,
};
request(options, (error, response, body) => {
console.log(body);
});
}
async function main() {
const serviceAccount = {
privateKey: "###", // private_key of JSON file retrieved by creating Service Account
clientEmail: "###", // client_email of JSON file retrieved by creating Service Account
};
var object = {
googleDocumentFileId: "###", // Set the file ID of the existing Google Document
textData: "hi there",
};
const accessToken = await getAccessToken(serviceAccount);
if (accessToken) {
object.accessToken = accessToken;
overWriting(object);
}
}
main();
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'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.