how to use Google API in meteor? - meteor

How can i access google api data in meteor. I created a google application with map api, contacts api and google+ api i have the api key, the client id, secret and user access token. I just want to access user's data using meteor Http.call() but it don't work. My error i get is "Unauthenticated Use Exceeded. Continued use requires signup"
Meteor.loginWithGoogle({
requestPermissions: ['email']
}, (err) => {
if (err) {
alert("Đăng nhập thất bại")
} else {
HTTP.call("GET", "googleapis.com/plus/v1/people/109512668573472269428/people/visible?maxResults=100", function(err, result) {
console.log(result);
})
}
}
})

Related

How to get user mail id and user name from Office.js or Office API

I am working on Word , Excel and PowerPoint add-ins . I want to upload document from graphs API .Below are API PUT https://graph.microsoft.com/v1.0/users/**myuser#domain.subdomain.com**/drive/items/root:/filename.docx:/content and it is working fine from Postman .
My concern how I will get USER Mail Id from Word , Excel and PowerPoint add-ins as Any direct API not available .
I follow below article still not success and getting 13006 error .
message: "An unexpected error occurred in the client."
name: "Error occurred in the authentication request from Office."
https://learn.microsoft.com/en-us/office/dev/add-ins/develop/register-sso-add-in-aad-v2
https://learn.microsoft.com/en-us/office/dev/add-ins/develop/sso-in-office-add-ins#register-your-add-in-with-the-microsoft-identity-platform
async getToken() {
var returnObject;
window.Office.context.auth.getAccessTokenAsync({ allowConsentPrompt: true, allowSignInPrompt: true },function (result) {
console.log( result);
if (result.status === "succeeded") {
var token = result.value;
returnObject = token;
console.log(token)
} else {
console.log("Error obtaining token", result);
}
});
return returnObject;
}
You can use the following code:
async function getUserData() {
try {
let userTokenEncoded = await OfficeRuntime.auth.getAccessToken();
let userToken = jwt_decode(userTokenEncoded); // Using the https://www.npmjs.com/package/jwt-decode library.
console.log(userToken.name); // user name
console.log(userToken.preferred_username); // email
console.log(userToken.oid); // user id
}
catch (exception) {
if (exception.code === 13003) {
// SSO is not supported for domain user accounts, only
// Microsoft 365 Education or work account, or a Microsoft account.
} else {
// Handle error
}
}
}
If your add-in is loaded on an older version of Office that does not support SSO, the getAccessToken call will fail. For Excel, Word, and PowerPoint add-ins you will typically want to fall back to using the Microsoft identity platform. For more information, see Authenticate with the Microsoft identity platform.
See Enable single sign-on (SSO) in an Office Add-in for more information.

How to use my firebase authentication to work with external services?

Ok so I am using firebase as authentication for my iOS app. Now I plan on adding video calling to my app using an external service know as connectyCube. This service has their own authentication system and I cannot use their services unless a user is authenticated.
Option 1: I can use their own authentication which means my app would have two authentication systems - not very productive
Option 2: They say I can use an existing authentication to validate users
I understand that this is a common thing in the developers world and I see the word OAuth and JWT being thrown around but I am a rookie developer and I want to understand how I can use firebase and authenticate a user from an external service.
These are the questions they have asked when I opted for the "I have my own authentication" option:
What is your end point URL
Is it GET or POST
Request Headers
Request Params
Response Params
Where do I get all this information from firebase? Any help would be great
As an alternative to #Dharmaraj's answer, you could instead make use of a HTTP Event Cloud Function for this based on the code sample they've provided.
Using this method, you create the endpoint /verifyUserToken to be used by ConnectyCube.
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
admin.initializeApp();
export const verifyUserToken = functions.https.onRequest((req, res) => {
const idToken = req.query.token;
verifyUser(idToken)
.then(
(userData) => {
res.status(200).json(userData)
},
(err) => {
console.log("Token verification failed.", err.code || err.message);
res.status(422).json({error: "User token is invalid"})
}
)
.catch((err) => console.error("Unexpected crash", err));
});
async function verifyUser(token) {
if (!token)
throw new Error("token missing");
// using `true` here to force token to be checked against the Firebase
// Auth API rather than trusting its contents as-is
const { uid, email } = await admin.auth().verifyIdToken(token, true);
// pull the user's username from their user data
// at /users/{userId}/username
const username = (await admin.database().ref("users/" + uid + "/username")).val();
// use user's actual email if available, otherwise fallback
// to a userID based email
const uEmail = email || uid + "#users.noreply.yourapp.com";
// use user's username if available, otherwise fallback to
// the email address above.
const uLogin = username !== null ? username : uEmail;
return {
uid,
login: uLogin,
email: uEmail,
user: {id: uid, login: uLogin, email: uEmail}, // <- this part in particular is used by ConnectyCube
users: [{uid, login: uLogin, email: uEmail}]
};
}
Once deployed, you would use the following settings:
Setting
Value
API URL:
https://us-central1-PROJECT-ID.cloudfunctions.net/verifyUserToken
GET/POST
GET
Request params:
{"token": "#{login}"}
Response params:
{"uid": "#{user.id}", "email": #{user.email}, "login": "#{user.login}"}
It looks like ConnectyCube uses some sort of Session Tokens as mentioned in their documentation with their own username and password.
The most easiest way would be creating a ConnectyCube account whenever a new user signs up in your Firebase app using Firebase Auth Triggers for Cloud functions. Then you can generate username and password on behalf of your user and store them in a Database.
So whenever you need to create a ConnectyCube session, check for the currently logged in user and fetch their ConnectyCube credentials.
async function createCCSession() {
const userId = firebase.auth().currentUser.uid
const ccCrednetials = (await firebase.database().ref(`ccCreds/${userId}`).once('value')).val()
ConnectyCube.createSession(ccCredentials)
.then((session) => {
console.log(session)
return session
}).catch((error) => console.log(error));
}
You can protect the database using security rules so a user can access their credentials only.
{
"rules": {
"ccCreds": {
"$uid": {
".read": "$uid === auth.uid"
}
}
}
}
While I don't normally double-answer a question, in the course of exploring some other authentication related problems, I've managed to eliminate the Cloud Function from my other answer entirely and instead call the Authentication API directly.
Setting
Value
API URL:
https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo?key=FIREBASE_CONFIG_API_KEY
GET/POST
POST
Request params:
{"idToken": "#{login}"}
Response params:
{"uid": "#{users.0.localId}", "email": #{users.0.email}, "full_name": "#{users.0.displayName}"}
On your client, you just call the ConnectyCube Login API with the following data:
POST https://api.connectycube.com/login
login=<Firebase-ID-token>
password=<any-random-value-to-pass-the-validation>

How to send SMS programmatically using Amazon Amplify SDK for my Android app users?

I want to send a welcome message (SMS) to phone number of my app's user when they will sign up using their phone number. I couldn't find official documentation for this particular task.
Amazon lets you do this. Assuming you're using Cognito for sign-up, you'll want to use the post-confirmation Cognito lambda trigger.
Set up your SNS account via the AWS Console, to send SMS messages. Send yourself a test message via the console.
Run amplify auth update
When it gets to the question Do you want to configure Lambda Triggers for Cognito?, answer Yes and choose the Post Confirmation trigger
You need to grant SNS (SMS) permissions to the lambda. Update the PostConfirmation-cloudformation-template.json file to add a new statement under Resources.lambdaexecutionpolicy.Properties.PolicyDocument.Statement:
{
"Resources": {
"lambdaexecutionpolicy": {
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Effect": "Allow",
"Action": "sns:*",
"Resource": "*"
}
]
...
}
...
}
...
}
...
}
...
}
Use this code for the trigger:
var aws = require('aws-sdk');
var sms = new aws.SNS();
exports.handler = (event, context, callback) => {
console.log(event);
if (event.request.userAttributes.phone_number) {
sendSMS(event.request.userAttributes.phone_number, "Congratulations " + event.userName + ", you have been confirmed: ", function (status) {
// Return to Amazon Cognito
callback(null, event);
});
} else {
// Nothing to do, the user's phone number is unknown
callback(null, event);
}
};
function sendSMS(to, message, completedCallback) {
const params = {
Message: message, /* required */
PhoneNumber: to
};
sns.publish(params, function (err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
} else {
console.log(data);
}
completedCallback("SMS Sent");
})
};
Not sure if sending SMS is a service, Amazon Amplify provides.
But you could use a service like Twilio to send SMS (and much more) to phones.
AWS Amplify can help you setting up SMS, Email and Push notifications to your users by integrating with Amazon Pinpoint. Take a look at the documentation here: https://aws-amplify.github.io/docs/js/push-notifications.
Amazon Pinpoint allows you to create user segmentation, message templates, campaigns (with A/B testing and canary as well), Journeys (for email only so far), and so many more other things. You can integrate it and configure it using AWS Amplify, but some of those features I've mentioned are still not supported by AWS Amplify and you will have to either use the AWS Console to configure or use the AWS SDK to integrate with your app. You can leverage the AWS Amplify Auth module in order to get a valid Cognito token which will allow you to interact with Amazon Pinpoint directly.

How to populate client-side Meteor.user.services after OAuth with built-in accounts-ui package in Meteor v1.4+?

I'm using accounts-ui and accounts-google in Meteor v1.4.1. I can't get the user.services object to appear scoped in the client code. In particular, I need google's profile picture.
I've configured the server-side code to authenticate with Google like so:
import { Meteor } from 'meteor/meteor';
import { ServiceConfiguration } from 'meteor/service-configuration';
const services = Meteor.settings.private.oauth;
for (let service of Object.keys(services)) {
ServiceConfiguration.configurations.upsert({
service
}, {
$set: {
clientId: services[service].app_id,
secret: services[service].secret,
loginStyle: "popup"
}
});
}
...and the client side code to configure permissions like so:
Accounts.ui.config({
requestPermissions: {
google: ['email', 'profile']
},
forceApprovalPrompt: {
google: true
},
passwordSignupFields: 'EMAIL_ONLY'
});
When users click the 'Sign-In with Google' button, a pop-up appears and they can authenticate. No prompt appears, however, despite forceApprovalPrompt being set to true for google.
The big issue is that when I execute this,
const user = Meteor.user();
console.log(user.services);
anywhere in client code, I do not see the expected user services information. I check my database and it is definitely there for the taking:
$ mongo localhost:27017
> db.users.find({})
> ... "services" : { "google" : { "accessToken" : ... } } ...
I'm curious what I'm missing? Should I explicitly define a publish function in order for user services data to exist in the client?
The services property is intentionally hidden on the client side for security reasons. There are a couple of approaches here :
Suggestions
My preferred one would be to expose a meteor method to bring you the
public keys and avatars you might need in the few places you'd need
them.
On a successful login, you could record the data you need somewhere in the user object, but outside of the services property.
As you said, you could make a new publication which explicitly specifies which fields to retrieve and which ones to hide. You have to be careful what you publish, though.
Code Examples
Meteor methods:
// server
Meteor.methods({
getProfilePicture() {
const services = Meteor.user().services;
// replace with actual profile picture property
return services.google && services.google.profilePicture;
}
});
// client
Meteor.call('getProfilePicture', (err, profilePicture) => {
console.log('profile picture url', profilePicture);
});
Update on successful user creation (you might want to have a login hook as well to reflect any avatar/picture changes in google):
// Configure what happens with profile data on user creation
Accounts.onCreateUser((options, user) => {
if (!('profile' in options)) { options.profile = {}; }
if (!('providers' in options.profile)) { options.profile.providers = {}; }
// Define additional specific profile options here
if (user.services.google) {
options.profile.providers.google = {
picture: user.services.google.picture
}
}
user.profile = options.profile;
return user;
});
Publish only select data...
// Server
Meteor.publish('userData', function () {
if (this.userId) {
return Meteor.users.find({ _id: this.userId }, {
fields: { other: 1, things: 1 }
});
} else {
this.ready();
}
});
// Client
Meteor.subscribe('userData');

Unknown name "view_id" error when querying google analytics reporting API

I am trying to query the Google Analytics Reporting API from a node.js application.
I think I have set up everything correctly on the google-side of things including a service account, but I must be missing a piece.
My application successfully sends usage-data to Google, I can see it come in in the realtime view. I can also query the data using the interactive API explorer.
In my node.js code I authenticate with the API at server startup like so:
var googleapis_key = require('./config/google-api-key.json');
var googleapis = require('googleapis');
var googleapis_jwtClient = new googleapis.auth.JWT(
googleapis_key.client_email,
null,
googleapis_key.private_key,
["https://www.googleapis.com/auth/analytics.readonly"],
null);
var googleapis_analyticsreporting = googleapis.analyticsreporting('v4');
googleapis_jwtClient.authorize(function(err, tokens) {
if (err) {
lStartup.error(err);
lStartup.error("Could not authenticate with google API. Analytics not available.");
} else {
lStartup.info("Successfully authenticated with google service-account.");
lStartup.debug(googleapis_jwtClient.credentials);
}
});
(where lStartup is a log4js logger). I get a positive response back from Google, err is not set and the credentials logged to the console look convincing.
Then later when the relevant client request comes in my server tries to ask google for the data:
var reportingrequests = {
"reportRequests": [
{
"viewID": "138122972",
"dateRanges": [{"startDate": "7daysAgo", "endDate": "yesterday"}],
"metrics": [{"expression": "ga:users"}]
}
]
};
logger.debug(JSON.stringify(reportingrequests));
googleapis_analyticsreporting.reports.batchGet(
{
"resource": reportingrequests,
"auth": googleapis_jwtClient,
},
function(err, response) {
if (err) {
// Failure. Log and report to the client.
console.error("Could not query the Google Analytics reporting API");
console.error(err);
res.writeHead(500, "Internal server error. (Google analytics:" + err + ")");
res.end(JSON.stringify(err));
} else {
// Success, just serve googles result to the client.
res.end(JSON.stringify(response));
}
}
);
The response is an error
[ { message: 'Invalid JSON payload received. Unknown name "view_id" at \'report_requests[0]\': Cannot find field.',
domain: 'global',
reason: 'badRequest' } ] }
What is it trying to tell me here? I do not have properties named view_id or report_requests in my JSON. Although they look suspiciously like mine de-camelcased.
I hate self-answering, but I love solutions!
"viewID": "138122972",
should be
"viewId": "138122972",
Note the lowercase "d".
Ironically the clue to this is in the camelCase to snake_case-conversion. If the parameter name was "viewID" it would propably have been snake_cased to "view_i_d", which is not what is in the error message.
I feel stupid, but also happy to be able to go on.

Resources