How to verify Google's auth gapi.auth.signIn response? - javascript

I have a database with users and I want to let user to connect his website account with his google account. I want to be able to let user to log in with his google account too and maybe later to be able to interact with his google+ account etc.
User is logged in on the website and he initiates this process with a click on a button which does following:
// user initiates the process
$('#google-connect').on(function() {
gapi.auth.signIn({
'callback': function(data) {
if(data['status']['signed_in'])
console.log("Signed in", data, gapi.auth.getToken());
// just get some additional user's data
gapi.client.load('oauth2', 'v2', function() {
gapi.client.oauth2.userinfo.get().execute(function(resp) {
console.log("OAuth", resp);
data.userID = resp.id;
// tell server to add google account to user's account
$.post('/add/google', data, function(data) {
console.log("Connected", "data");
});
});
});
},
'clientid': GOOGLE_CLIENT_ID,
'cookiepolicy': 'single_host_origin',
'requestvisibleactions': 'http://schemas.google.com/AddActivity',
'approvalprompt':'force',
'scope': 'https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email'
//'scope': 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.me'
});
return false;
});
// load libs
(function() {
var po = document.createElement('script');
po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/client:plusone.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(po, s);
})();
it basicly works without problem but I am not sure is this secure and how to verify the answers form google server. For example, Facebook login returns "signedRequest" and I am able to run the verification with hash_hmac (php) to verify the response.
Google answers with this on my gapi.auth.signIn() request:
access_token: "ya29.KgDiGDMeEpOEFxoAAAD2dV1eldwT_ZCcr-ODNR_LBKWbam7bOwZ0pplZ33hG3A"
authuser: "0"
client_id: "...."
code: "4/iqLG-akrpp_BGWGGx2b_RAqTSj29.AuyFPmgozMATOl05ti8ZT3bxU6v2jAI"
cookie_policy: "single_host_origin"
expires_at: "1402232030"
expires_in: "3600"
g-oauth-window: Window
g_user_cookie_policy: "single_host_origin"
id_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6IjgxNDBjNWYxYzlkMGM3MzhjMWI2MzI4NTI4ZjdhYjFmNjcyZjViYTAifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTExNTQ2NTQxNjExMzkyOTAzMTYzIiwiYXpwIjoiOTMyNjIxNDU0NTUxLThrNW8yOXY0djEyZmN2cG1tNWFqYXZsbW9ic2x1NzQwLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWwiOiJtaXJ6YS5jd0BnbWFpbC5jb20iLCJhdF9oYXNoIjoiTUNERVJkZjJpaUo0eUZ4ZHU1RUdpUSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJhdWQiOiI5MzI2MjE0NTQ1NTEtOGs1bzI5djR2MTJmY3ZwbW01YWphdmxtb2JzbHU3NDAuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJjX2hhc2giOiJXMXY4UUhkUndLM3FQbGhMZE1XY1Z3IiwiaWF0IjoxNDAyMjI4MTMwLCJleHAiOjE0MDIyMzIwMzB9.Fil-uV6oFdeiRrO_vHFr5oVOnzVIfa2DvneDYaFF_eo3HOdOmD2wElD5UOjXxTLcNHtxyXg-zInyB9wDn1aQaZpYTSgG3Q-PN7oXcmUECyX5UJ7Aga0xgjAH6j57XBTx_BVdeiq1xLTPSMq9J2hZ1jGIkv-1qPedng7bRVGuRgQ"
issued_at: "1402228430"
num_sessions: "1"
prompt: "consent"
response_type: "code token id_token gsession"
scope: "https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.moments.write https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/plus.profile.agerange.read https://www.googleapis.com/auth/plus.profile.language.read https://www.googleapis.com/auth/plus.circles.members.read https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/plus.profile.emails.read"
session_state: "14f90adcf0c130936b1545ec15dbd8fe1515b4dc..0c9b"
state: ""
status: Object
token_type: "Bearer"
I did not find any information how to verify the response. There is no signature or something else except "id_token" which could be some kind of signature.
Is there a way to verify google's answer to be sure that information is correct, that there is no MITM? Or am I just worrying too much?

Yes, there is :
Have you read ID Token verification(PHP lib) ?
I guess, you could do the same in JavaScript using :
$.get("https://www.googleapis.com/oauth2/v1/tokeninfo",{
"id_token" : authResult["id_token"]},function(data){
//Handle data...
});

Related

Facebook Graph API "{video_id}/video-insights" returning an empty "data'' array

I want to the receive statistics such as the views, comments, shares, and reactions from a public video on my Facebook profile using the Facebook graph api.
I am trying to use the endpoint {video_id}/video_insights but this just returns an empty array {data: Array(0)} My scope is read_insights,user_videos
window.fbAsyncInit = function() {
FB.init({
appId: '{app_id}',
autoLogAppEvents: true,
xfbml: true,
version: 'v3.3'
});
FB.login(response => {
if (response.authResponse){
let token = response.authResponse.accessToken;
let scope = response.authResponse.grantedScopes;
FB.api('{video_id}/video_insights', response => {
console.log(token);
console.log(scope);
console.log(response);
})
}
},{scope: 'read_insights,user_videos', return_scopes: true});
}
This is what shows up in the console:
token = {access_token}
scope = 'user_videos,read_insights,public_profile'
response = {data: Array(0)}
There are no insights for user profiles, they are only available for Pages - and videos posted to Pages. You would also need the manage_pages permission in addition, to get a Page Token.
About user videos in general: https://developers.facebook.com/docs/facebook-login/permissions/#reference-user_videos
This permission is restricted to a limited set of partners and usage
requires prior approval by Facebook.
Same for user_photos, as you can read on the same page.

ADAL.js - acquire token for Graph API resources

I'm developing a SPA app in React that needs to integrate with AzureAD and the GraphAPI (implicit flow).
My question is very similar to: ADAL.js - Obtaining Microsoft Graph Access Token with id_token ... but the answer doesn't show me enough code to get me on my way.
So far, using just adal.js (v1.0.14), I can login & get an id_token, but I can't figure out how to use it to get access to make Graph API calls.
UPDATE: I know I'm correctly registered with the Azure portal, because I was able to login and get recent docs without adal.js or any lib ... just using home-made ajax calls.
Here's my code, which does the login/redirect, and then tries to get my recent docs:
// Initial setup
var adalCfg = {
instance : 'https://login.microsoftonline.com/',
tenant : 'common',
clientId : 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
postLogoutRedirectUri : window.location.origin,
extraQueryParameter : 'scope=Mail.ReadWrite+Files.Read+Files.ReadWrite+User.ReadBasic.All' // Is this the proper way to specify what resources I need access to?
};
var authContext = new Adal(adalCfg);
if(!authContext.getCachedUser()) {
authContext.login(); // redirects MS login page successfully
}
// Check For & Handle Redirect From AAD After Login
var isCallback = authContext.isCallback(window.location.hash); // Checks if the URL fragment contains access token, id token or error_description.
if(isCallback) {
authContext.handleWindowCallback(); // extracts the hash, processes the token or error, saves it in the cache and calls the registered callbacks with the result.
}
if (isCallback && !authContext.getLoginError()) {
window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST); // redirects back to /
}
// Try to get my recent docs - FAILS with InvalidAuthenticationToken error
// UDPATED authContext.acquireToken(authContext.config.clientId, function (error, token) {
authContext.acquireToken('https://graph.microsoft.com', function (error, token) {
$.ajax({
url: 'https://graph.microsoft.com/v1.0/me/drive/recent',
headers:{'authorization':'Bearer '+ token},
type:'GET',
dataType:'json'
}).done(function(res) {
console.log(res['value']);
});
});
What have I got wrong?
Update 2: I changed acquireToken per Fei's answer, but now when adal silently gets an access token for my resource, it fails to pass it to my API call.
Updated code:
adalCfg.endpoints.graphApiUri = "https://graph.microsoft.com";
authContext.acquireToken(adalCfg.endpoints.graphApiUri, function (errorDesc, token, error) {
console.log('errorDesc = ' + errorDesc)
console.log('token = ' + token)
console.log('error = ' + error)
$.ajax({
url: adalCfg.endpoints.graphApiUri + '/v1.0/me/drive/recent',
headers:{'authorization':'Bearer '+ token},
type:'GET',
dataType:'json'
}).done(function(res) {
console.log(res['value']);
});
});
And console output:
Token not being captured
The image shows the req for a token, which appears to succeed, because the next GET contains the access_token in the hash. However, acquireToken passes a null token to my Graph API call.
However, if I manually grab the access token out of the hash, I can successfully make the Graph API call.
Why doesn't adal pass the access token to my API call? It came back and is valid.
To call the Microsoft Graph, we need to get the specific token for this resource. Based on the code you were acquire the token using the authContext.config.clientId.
If you register the app on Azure portal, to get the access token for the Microsoft Graph, you need to replace authContext.config.clientId with https://graph.microsoft.com.
And to call the REST sucessfully, we need to make sure having the enough permission. For example, to list recent files, one of the following scopes is required:Files.Read,Files.ReadWrite,Files.Read.All,Files.ReadWrite.All,Sites.Read.All,Sites.ReadWrite.All(refer here).
Update
<html>
<head>
<script src="\node_modules\jquery\dist\jquery.js"></script>
<script src="node_modules\adal-angular\lib\adal.js"></script>
</head>
<body>
<button id="login"> login</button>
<button id="clickMe">click me</button>
<script>
$(function () {
var endpoints = {
"https://graph.microsoft.com": "https://graph.microsoft.com"
};
window.config = {
tenant: 'xxxx.onmicrosoft.com',
clientId: 'xxxxxxxxxxxxxxxxx',
endpoints: endpoints
};
window.authContext = new AuthenticationContext(config);
$("#login").click(function () {
window.authContext.login();
});
$("#clickMe").click(function () {
var user = window.authContext.getCachedUser();
console.log(user);
window.authContext.acquireToken('https://graph.microsoft.com', function (error, token) {
console.log(error);
console.log(token);
$.ajax({
url: 'https://graph.microsoft.com/v1.0/me/',
headers:{'authorization':'Bearer '+ token},
type:'GET',
dataType:'json'
}).done(function(res) {
console.log(res['userPrincipalName']);
});
});
}
);
function init(){
if(window.location.hash!="")
window.authContext.handleWindowCallback(window.location.hash);
}
init();
});
</script>
</body>
</html>

How to send email using MailChimp API

I'm creating an app in nodejs to send an email using MailChimp. I've tried to use https://apidocs.mailchimp.com/sts/1.0/sendemail.func.php but changed it to use 3.0 api because 1.0 seems to no longer work (big surprise). I've setup my app with
var apiKey = '<<apiKey>>',
toEmail = '<<emailAddress>>',
toNames = '<<myName>>',
message = {
'html': 'Yo, this is the <b>html</b> portion',
'text': 'Yo, this is the *text* portion',
'subject': 'This is the subject',
'from_name': 'Me!',
'from_email': '',
'to_email': toEmail,
'to_name': toNames
},
tags = ['HelloWorld'],
params = {
'apikey': apiKey,
'message': message,
'track_opens': true,
'track_clicks': false,
'tags': tags
},
url = 'https://us13.api.mailchimp.com/3.0/SendEmail';
needle.post(url, params, function(err, headers) {
if (err) {
console.error(err);
}
console.log(headers);
}
});
I keep getting a 401 response (not authorized because I'm not sending the API key properly)
I have to use needle due to the constraints on the server.
There is no "SendEmail" endpoint in API v3.0. MailChimp's STS was a pre-cursor to its Mandrill transactional service and may only still work for user accounts that have existing STS campaigns. No new STS campaigns can be created. If you have a monthly, paid MailChimp account, you should look into Mandrill. If not, I've had good luck with Mailgun.
You should use HTTP Basic authentication in MailChimp API 3.0.
needle.get('https://<dc>.api.mailchimp.com/3.0/<endpoint>', { username: 'anystring', password: 'your_apikey' },
function(err, resp) {
// your code here...
});
EDIT
#TooMuchPete is right, the SendMail endpoint is not valid in MailChimp API v3.0. I didn't notice that and I've edited my answer.

google+ api login not returning email

I have implemented javascript based google+ login in my application using the following code:
var isGPInitialzed = false;
function render() {
gapi.signin.render('loginWithGoogle', {
'callback': 'onSignIn',
'clientid': 'the client id',
'cookiepolicy': 'single_host_origin',
'requestvisibleactions': 'http://schema.org/AddAction',
'scope': 'https://www.googleapis.com/auth/plus.login'
});
isGPInitialzed = true;
}
//Google
function onSignIn(authResult) {
if (!isGPInitialzed) {
if (authResult['status']['signed_in']) { //get some user info
gapi.client.load('oauth2', 'v2', function () {
gapi.client.oauth2.userinfo.get().execute(function (response) {
console.log(response.email);
$.ajax({
url: '/Account/GLogin',
type: 'POST',
data: {
email: response.email,
name: response.name,
profilePicture: response.picture
},
dataType: 'json',
success: function (isUserLoggedIn) {
if (isUserLoggedIn) {
window.location.reload();
}
}
});
});
});
}
}
else {
isGPInitialzed = false;
}
};
It was working fine until I created a new application from another account and replaced the client id. On successful authentication, the api is not returning the user email in the response. I have checked in the google+ account settings for the Apps and there is not setting to give acces to the email. What can be the issue?
change the scope with
'scope': 'https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email',
For anyone who still looking for the answer, try to use this:
scope: 'openid profile email'
based on latest update from google developers, please change the scope,
https://www.googleapis.com/auth/plus.profile.emails.read
This scope requests that your app be given access to:
the user's Google account email address, as well as any public, verified email addresses in the user's Google+ profile. You access the email addresses by calling people.get, which returns the emails array.
the name of the Google Apps domain, if any, that the user belongs to.
If you're using Rails, the issue might be that you need to update omniauth-google-oauth2 to (0.6.0)
https://github.com/zquestz/omniauth-google-oauth2/issues/358
Google seems to have changed what gets returned by their API. The first comment in the above issue shows the structure of the hash has changed.

Facebook sdk - share to managed pages

I have the following code to share to a facebook wall, but it doesn't give the option to share to any managed pages the user has admin rights to (i tried testing with my own account) can anyone help me with this? Also i want to post in the future according to a date set in feed if possible.
<script>
window.fbAsyncInit = function() {
FB.init({appId: '475259649152397',
channelUrl : '<?php get_theme_root();?>/inc/facebook-javascript-sdk/channel.php',
status: true,
cookie: true,
xfbml: true
});
};
function Login()
{
FB.login(function(response)
{
if (response.authResponse)
{
getUserInfo();
}
else
{
console.log('User cancelled login or did not fully authorize.');
}
},{scope: 'manage_pages'});
}
(function() {
var e = document.createElement('script'); e.async = true;
e.src = document.location.protocol +
'//connect.facebook.net/en_US/all.js';
document.getElementById('fb-root').appendChild(e);
}());
</script>
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery('#share_button').click(function(e){
e.preventDefault();
FB.ui({
method: 'feed',
name: 'This is the content of the "name" field.',
link: ' http://example.com/',
picture: 'http://myface.gif',
caption: 'insightful thought provoking caption.',
description: 'interresting".',
message: ''
});
});
});
</script>
It works just fine at sharing to the users wall but no option to share to the managed pages
thanks in advance!
option to share to any managed pages the user has admin rights to
Simply, give the PAGE_ID to the to parameter. Just like-
FB.ui({
method: 'feed',
name: 'This is the content of the "name" field.',
link: ' http://example.com/',
picture: 'http://myface.gif',
caption: 'insightful thought provoking caption.',
description: 'interresting".',
message: '',
to: MY_PAGE_ID
});
i want to post in the future
You can use the page access token if you want to post to your page at any later time, the page access token could be extended to never expiring. What are the Steps to getting a Long Lasting Token For Posting To a Facebook Fan Page from a Server
To get the pages managed by you, query for-
/me/accounts?fields=id,name
, you'll get an array of pages you are managing. Live Demo

Categories