I've been getting this error:
Expected OAuth 2 access token, login cookie or other valid authentication credential
whenever I run my program. Here is my code.
const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');
const promise = require('promise');
const slides = google.slides({
version: 'v1',
auth: 'CLIENT_SECRET'
});
const SCOPES = ['https://www.googleapis.com/auth/presentations', 'https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/drive.file', 'https://www.googleapis.com/auth/drive.appdata', 'https://www.googleapis.com/auth/plus.me', 'https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email'];
const TOKEN_PATH = 'token.json';
fs.readFile('credentials.json', (err, content) => {
if (err) return console.log('Error loading client secret file:', err);
authorize(JSON.parse(content), createSlide);
});
function authorize(credentials, callback) {
const {client_secret, client_id, redirect_uris} = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]
);
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getNewToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}
function getNewToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES,
});
console.log('Authorize this app by visiting this url:', authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.question('Enter the code from that page here: ', (code) => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return console.error('Error retrieving access token', err);
oAuth2Client.setCredentials(token);
fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
if (err) console.error(err);
console.log('Token stored to', TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
function createSlide(presentationId, pageId, auth) {
return new Promise((resolve, reject) => {
let requests = [{
createSlide: {
objectId: pageId,
insertionIndex: '1',
slideLayoutReference: {
predefinedLayout: 'TITLE_AND_TWO_COLUMNS',
},
},
}];
//ELEMENTS
slides.presentations.batchUpdate({
presentationId,
resource: {
requests,
},
}, (err, res) => {
if (err) return console.log("Error: " + err);
console.log(`Created slide with ID: ${res.replies[0].createSlide.objectId}`);
resolve(res);
});
});
}
The code is from the node.js quickstart (https://developers.google.com/slides/quickstart/nodejs).
The function createSlide() is from the Github Node.Js snippets (https://github.com/gsuitedevs/node-samples/blob/master/slides/snippets/snippets.js#L78)
I have tried the code on the Github for the Google APIs Node.js Client (https://github.com/googleapis/google-api-nodejs-client)
I am fairly new to the Google API and Node.Js, so I'm still learning about async and promise. Can someone tell me what I am doing wrong, and perhaps provide a full working example (not snippets)? Thanks in advance!
Related
`//Dbconnect.js File
async function connect() {
const credential = new DefaultAzureCredential();
const keyVaultName = "dbconnection";
const url = "https://" + keyVaultName + ".vault.azure.net";
const client = new SecretClient(url, credential);
const connection = await mysql.createConnection({
host: (await client.getSecret('host')).value,
user: (await client.getSecret('user')).value,
password: '',
database:(await client.getSecret('database')).value,
});
connection.connect((err) => {
if(err){
console.log('Error connecting to Db');
return;
}
console.log('Connection established successfully');
});
return connection;
}
connect().catch((error) => {
console.error("An error occurred:", error);
process.exit(1);
});
module.exports.connect = connect;
//APi.js File
const mysql = require('../DbConnect').connect;
exports.customerInformation = async (req, res) => {
let qry = "select * from customerinformation";
mysql query(qry, (err, results) => {
if (err){
res.status(500).json({response:"500",status:'Failed',message:"Internal Server Error"});
}
else {
if (results.length > 0) {
res.status(200).json({response:"200",status:'success',data:results});
}else{
res.status(404).json({response:"404",status:'Failed',message:"Invalid Credential"});
}
}
})
};
`
Keyvault secrets are fectched and Connection Is getting established successfully. But when I am Trying to call the API It is SHowing query is not defined as the error
I'm trying to get result from node.js api however, whenever i deploy my website, it gets html result like below.
but it works when it's on local. but not on the deployed website.
so i tried to use axios post then it gets 404 error.
and another api is work but when i write new api then it gets error.
this is my node.js
//this post work just fine .
app.post("/insertCodeVisual", async (req, res) => {
const { data } = await req.body;
const visualData = new CodeVisualData({
data: data,
});
try {
visualData.save((err, info) => {
res.send(info._id);
});
console.log("success");
} catch (error) {
console.log(error);
}
});
//but this post is not working
app.post("/api/database", async (req, res) => {
const { host, user, password, port, table, database } = await req.body;
var connection = mysql.createConnection({
host: host,
user: user,
password: password,
port: port,
database: database,
});
try {
connection.connect();
} catch (error) {
res.send([["ERROR_CODE"], [error.code]]);
}
const sql = `SELECT * FROM ${table}`;
connection.query(sql, function (err, results) {
if (err) {
return res.send([
["ERROR"],
[`code : ${err.code}`],
[`errno : ${err.errno}`],
[`sqlMessage : ${err.sqlMessage}`],
]);
} else {
const parse = papa.unparse(results, {
quotes: false, //or array of booleans
quoteChar: '"',
escapeChar: '"',
delimiter: ",",
header: true,
newline: "\r\n",
skipEmptyLines: false, //other option is 'greedy', meaning skip delimiters, quotes, and whitespace.
columns: null, //or array of strings
});
const unparse = papa.parse(parse);
res.send(unparse.data);
}
});
});
const __dirname = path.resolve();
app.use(express.static(path.join(__dirname, "dist")));
app.get("/*", (req, res) => {
res.sendFile(path.join(__dirname, "dist", "index.html"));
});
React.js
this one is working absolutely
const insertData = async () => {
try {
if (confirm("are u sure? ")) {
axios
.post(`${backend}/insertCodeVisual`, {
data: {
client: client,
header: header,
},
})
.then(res => {
setJustSavedDataId(res.data);
});
} else {
return;
}
} catch (error) {
console.log(error);
}
};
this below is not working when i deployed .
const getDatabase = async () => {
const url = `${backend}/api/database`;
const api = await axios.post(url, db[id]);
const data = api.data;
try {
setInfo({ ...info, [id]: data });
} catch (error) {
console.log(error);
}
};
So i wonder what cases make this kind of issue.
This below is my auth.js route code to login via oAuth2 and it was working till this afternoon, now tonight started to throw error UnhandledPromiseRejectionWarning: Error: No refresh token is set.
const express = require("express");
const google = require('googleapis').google;
const jwt = require('jsonwebtoken');
const CONFIG = require("../config/passport-google");
const nf = require('node-fetch');
const gUser = require('../models/User-g');
const router = express.Router();
// Google's OAuth2 client
const OAuth2 = google.auth.OAuth2;
router.get("/youtube", function(req, res) {
// Create an OAuth2 client object from the credentials in our config file
const oauth2Client = new OAuth2(
CONFIG.oauth2Credentials.client_id,
CONFIG.oauth2Credentials.client_secret,
CONFIG.oauth2Credentials.redirect_uris[0]
);
// Obtain the google login link to which we'll send our users to give us access
const loginLink = oauth2Client.generateAuthUrl({
access_type: "offline", // Indicates that we need to be able to access data continously without the user constantly giving us consent
scope: CONFIG.oauth2Credentials.scopes // Using the access scopes from our config file
});
return res.render("./home/g-login", { loginLink: loginLink });
});
router.get("/youtube/callback", function(req, res) {
// Create an OAuth2 client object from the credentials in our config file
const oauth2Client = new OAuth2(
CONFIG.oauth2Credentials.client_id,
CONFIG.oauth2Credentials.client_secret,
CONFIG.oauth2Credentials.redirect_uris[0]
);
if (req.query.error) {
// The user did not give us permission.
return res.redirect("/");
} else {
oauth2Client.getToken(req.query.code, function(err, token) {
if (err) return res.redirect("/");
// Store the credentials given by google into a jsonwebtoken in a cookie called 'jwt'
res.cookie("jwt", jwt.sign(token, CONFIG.JWTsecret));
// return res.redirect("/get_some_data");
if (!req.cookies.jwt) {
// We haven't logged in
return res.redirect("/");
}
// Add this specific user's credentials to our OAuth2 client
oauth2Client.credentials = jwt.verify(req.cookies.jwt, CONFIG.JWTsecret);
// Get the youtube service
const service = google.youtube("v3");
const url = `https://www.googleapis.com/oauth2/v1/userinfo?access_token=${token[Object.keys(token)[0]]}`;
const get_data = async () => {
try {
const response = await nf(url);
const json = await response.json();
// save user to db
async (json, done) => {
const newUser = {
channelId: json.id,
channelEmail: json.email,
image: json.picture,
createdAt: Date.now()
}
try {
let user = await gUser.findOne({ channelId: json.id });
if(user){
done(null, user);
} else {
user = await gUser.create(newUser);
done(null, user);
}
} catch (err) {
console.log(err);
return res.redirect("../../500");
}
}
return json;
} catch (err) {
console.log(err);
return res.redirect("../../500");
}
};
// Get 50 of the user's subscriptions (the channels they're subscribed to)
service.subscriptions
.list({
auth: oauth2Client,
mine: true,
part: "snippet,contentDetails",
maxResults: 50
})
.then(async (response) => {
//.then(response => {
const diomerda = await get_data();
// Render the profile view, passing the subscriptions to it
return res.render("./user/dashboard", { subscriptions: response.data.items, diomerda: diomerda });
});
});
}
});
// Logout from Google
router.get('/logout', (req, res) => {
req.logout();
res.redirect('/');
})
module.exports = router;
I tried to delete the app from the authorized apps inside my google account im using to test, and when i test the login again it now goes through all the steps of the login, it asks for permit, i accept twice and then it throws that error and the page looks like frozen in a loop
I am changing my backend (switching over from Mongo to MySql). I know the error is getting thrown because a return statement is being executed before my SQL query has finished and then when my sql query finishes, it tires to send another res.send, hence why I am trying to use mysql2 with Promise wrappers to use await on queries in my async function.
I have a separate file that creates the DB connection so I can access the connection throughout my Nodejs backend:
const mysql = require('mysql2');
async function pool(){
const pool = await mysql.createPool({
host: "ip",
user: "username",
password: "password",
database: "db"
});
return pool
}
exports.getConnection = async function(callback) {
const currentPool = await pool();
currentPool.getConnection(function(err, conn) {
if(err) return callback(err);
callback(err,conn)
});
};
Then, to create a query that follows async/await:
sql.getConnection(async function(err, client){
client.query(`select email from users where email = "${email}"`, function (error, result){
if(error) return res.status(500).send('an internal db error occurred');
// carry on with code ...
});
});
I've tried using await on the query too:
await sql.getConnection(async function(err, client){
client.query(`select email from users where email = "${email}"`, function (error, result){
if(error) return res.status(500).send('an internal db error occurred');
// carry on with code ...
});
});
What am I missing? I haven't tired to use the normal mysql NPM library and make my own promise wrapper yet...
NEW CODE:
I've updated my function:
const mysql = require('mysql2');
const pool = mysql.createPool({
host: "ip",
user: "user",
password: "pass",
database: "db"
});
exports.db = (sql) => {
new Promise((resolve, reject) => {
pool.getConnection((err, conn) => {
if(err) return reject(err);
conn.query(sql, (err, results, fields) => {
conn.release()
if(err) return reject(err)
console.log(results)
resolve(results);
});
});
});
}
Then I call it via:
try{
const emailExisit = await sql.db(`SELECT email FROM users WHERE email = "${email}"`);
console.log(emailExisit);
if(emailExisit.length > 0) return res.status(422).send({"data": "", "code": "105", "message": "An account with given email already exists"});
}catch (err) {
console.log(err)
return res.status(500).send({"data": "", "code": "108", "message": `There seems to be an error contacting the database. Try again later <br> ${err}`});
}
However, my code still continues, leaving my emailExists variable undefined (yes, it is inside an async function)
This is my configuration to use MySQL with Node.js. I hope it works with you.
/config/mysql.js
const mysql = require('mysql2');
const pool = mysql.createPool({
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
port: process.env.MYSQL_PORT,
database: process.env.MYSQL_DB_NAME,
});
const query = (query, args = []) =>
new Promise((resolve, reject) => {
pool.getConnection((err, connection) => {
if (err) {
return reject(err);
}
connection.query(query, args, (err, results) => {
connection.release();
if (err) {
return reject(err);
}
resolve(results);
});
});
});
module.exports = { query };
/index.js
const { query } = require('./mysql');
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.get('/api/v1/sum', (req, res) => {
query('SELECT 1 + 1 as sum')
.then(results => {
res.json({ sum: results[0].sum });
})
.catch(err => {
console.error(err);
res.status(500).json({ error: 'error msg' });
});
});
// anther example with async
app.get('/api/v1/sum', async (req, res) => {
try {
const results = await query('SELECT 1 + 1 as sum');
res.json({ sum: results[0].sum });
} catch (err) {
console.error(err);
res.status(500).json({ error: 'error msg' });
}
});
app.listen(3000);
const express = require('express'),
bodyParser = require('body-parser'),
Sequelize = require('sequelize')
const app=express()
app.use(bodyParser.json())
var google = require('googleapis');
var contacts = google.people('v1');
const nconf = require('nconf');
const readline = require('readline');
const plus = google.plus('v1');
const path = require('path');
const OAuth2Client = google.auth.OAuth2;
nconf.argv().env().file(path.join(__dirname, '/oauth2.keys.json'));
const keys = nconf.get('web');
const CLIENT_ID = '1058912681476-uat19si2uli37vlehs2avqfue2l0b6ku.apps.googleusercontent.com';
const CLIENT_SECRET = 'PbY8AVICTQsywb4qiqCJ8gMB';
const REDIRECT_URL = 'urn:ietf:wg:oauth:2.0:oob';
const oauth2Client = new OAuth2Client(CLIENT_ID, CLIENT_SECRET, REDIRECT_URL);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function getAccessToken (oauth2Client, callback) {
// generate consent page url
const url = oauth2Client.generateAuthUrl({
access_type: 'offline', // will return a refresh token
scope: 'https://www.googleapis.com/auth/plus.me' // can be a space-delimited string or an array of scopes
});
console.log('Visit the url: ', url);
rl.question('Enter the code here:', code => {
// request access token
oauth2Client.getToken(code, (err, tokens) => {
if (err) {
return callback(err);
}
// set tokens to the client
// TODO: tokens should be set by OAuth2 client.
oauth2Client.credentials=tokens;
callback();
});
});
}
// retrieve an access token
getAccessToken(oauth2Client, () => {
// retrieve user profile
plus.people.get({ userId: 'me', auth: oauth2Client }, (err, profile) => {
if (err) {
throw err;
}
console.log(profile.displayName, ':', profile.tagline);
});
});
//here-not working
contacts.people.connections.list({
auth: oauth2Client //authetication object generated in step-3
}, function (err, response) {
// handle err and response
if(err){
throw err;
}
console.log(response.names);
});
app.listen(8080)
I'm trying to get the contacts of an user from the google people api(https://developers.google.com/people/api/rest/v1/people.connections/list) but when I try to call contacts.people.connection.list() I get Error:
Missing required parameters: resourceName
at Object.createAPIRequest (/home/ubuntu/workspace/contactmanager/backend/node_modules/googleapis/build/src/lib/apirequest.js:94:18);
The error says it all. The resourceName is a required parameter. If you look in the people.connections.list you must provide a 'people/me' value as parameter. Other values are invalid.
GET https://people.googleapis.com/v1/{resourceName=people/me}/connections
#noogui already answered the reason . Here is the more elaborative code for the use case:
function listConnectionNames(auth) {
const service = google.people({
version: "v1",
auth
});
service.people.connections.list({
resourceName: "people/me",
pageSize: 10,
personFields: "names,emailAddresses"
},
(err, res) => {
if (err) return console.error("The API returned an error: " + err);
const connections = res.data.connections;
if (connections) {
console.log("Connections:");
connections.forEach(person => {
if (person.names && person.names.length > 0) {
console.log(person.names[0].displayName);
} else {
console.log("No display name found for connection.");
}
});
} else {
console.log("No connections found.");
}
}
);
}