Retrieve info for specific user's ID - node.js

I do my PHD work dedicated to Social Network Analysis.
As tools was selected Node JS and Facebook API
Now what I can do is retrieve user's ID's with the additional info, but to build graph I need lists of the user's friends.
I have Heroku App but I'm totally disappointed what to do with te APP_ID to get information needed to build data.
Where I should start?

There are some Node.js packages available for this purpose.
Third party SDKs for Facebook
This is very useful, in case you want to write the same code and share between your server (nodejs) and the client (FB JS-SDK)
In order to start, you need to have access_tokens from users, you want information from. (Through FB App)
FB.login(function(response) {
if (response.authResponse) {
var res = response.authResponse;
FB.api('/me', function(response) {
registerUser({ "fb_user_id": res.userID, //register user in your database
"access_token": res.accessToken
}, function() {
//handle here after registration
});
});
} else {
//handle reject in requested fields
}
}, { scope: 'email,friends_about_me'});
//you can set scope field according to your use.
Refer to this for extended profile properties that can be used in scope field.
Once you get access_tokens, you can use them with one of the third party SDK above.
For example with facebook-node-sdk,
This sdk also provides you request access_token api
var FB = require('fb');
var accessToken = FB.getAccessToken();
FB.setAccessToken(accessToken);
FB.api('idHere', { fields: ['id', 'name'] }, function (res) { //you can access fields, access_token has access to
if(!res || res.error) {
console.log(!res ? 'error occurred' : res.error);
return;
}
console.log(res.id);
console.log(res.name);
});
You can also use api function directly with access_token.
FB.api('me', { fields: ['id', 'name'], access_token: 'access_token' }, function (res) {
console.log(res);
}

Related

Oauth2 with Google docs API Node.js (trying to programmatically write a new google doc)

I have a typical web app with a client and a node.js server. When a user selects an option on the client, I want to export (create) a google doc in their drive.
I am half way there following this tutorial https://developers.google.com/identity/protocols/oauth2/web-server
With my current set up, after the user authenticates, the authentication token is sent to a web hook (server side), but I don't have any of the data for creating the google doc there.
If I did, I could create the doc from there. Otherwise, I need to send the token itself back to the client so I can create the doc with the necessary payload from there.
In that case, I don't know how to signal to the client that the user has been authenticated. Should I use a web socket?
Something tells me that my general set up might not be correct, and that I should be doing it a different way in my use case.
This is my client side code that brings the user to the google auth page after getting the auth url (not sure if this really needs to be done server side, but since I have some user credentials I thought it might be better).
export async function exportToGoogleDoc() {
const response = await POST(`${API_URL}export/gdoc`, {
'hello': 'world'
});
if (response.status == 200){
window.location.href = response.authUrl;
}
}
And then the endpoint (just returns the autheticationUrl)
api.post('/export/gdoc', express.raw({ type: 'application/json' }), async (req, res, next) => {
try {
const scopes = [
'https://www.googleapis.com/auth/drive'
];
const oauth2Client = new google.auth.OAuth2(
credentials.web.client_id,
credentials.web.client_secret,
credentials.web.redirect_uris[0]
);
const authorizationUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
include_granted_scopes: true
});
res.json({ 'status': 200, authUrl : authorizationUrl } );
} catch (err){
next(err);
}
});
But then after the user agrees and authenticates with their google account, the auth token is sent to this web hook. At the bottom I am able to write an empty google doc to the authenticated google drive, but I don't have the data I need to create the real doc.
api.get('/auth/google', express.raw({ type: 'application/json' }), async (req, res, next) => {
const q = url.parse(req.url, true).query;
const oauth2Client = new google.auth.OAuth2(
credentials.web.client_id,
credentials.web.client_secret,
credentials.web.redirect_uris[0]
);
if (q.error) {
console.log('Error:' + q.error);
} else {
const { tokens } = await oauth2Client.getToken(q.code.toString());
oauth2Client.setCredentials(tokens);
const drive = google.drive('v3');
const requestBody = {
'name': 'Dabble',
'mimeType': 'application/vnd.google-apps.document',
};
drive.files.create({
requestBody: requestBody,
fields: 'id',
auth: oauth2Client
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log('File Id: ', file);
}
});
}
Somehow I either need to get the data for the google doc inside this web hook, or to listen for this web hook from the client.
OR I need an entirely different set up. I realize I also should be probably storing this token somewhere (local storage on client side?) and only making this call if they do not have a token.
Can anyone help me modify my set up? Thanks!

Node.js Express Spotify API save in session

Question appeared while integrating Spotify API into Nodejs Express web application using spotify-web-api-node. How multiple simultaneous user requests should be handled? After passing the authentication step, user receives access_token, which is different for each user. Each request can have a session, for example using express-session since access_token is unique for each authenticated user. The weird thing is that I can't find an example with proper session usage in the description and samples https://www.npmjs.com/package/spotify-web-api-node where spotify-web-api-node is used. How is that possible to use global variable without session? Would it make full mess among separate user requests or I'm missing something? I guess that the access_token would be always replaced with latest authenticated user. Another usage example is here https://github.com/thelinmichael/spotify-web-api-node, though it also suggests to use one global instance.
the solution is to store the access_token and refresh_token after successful authentication in the session storage, than before calling Spotify API endpoints set both tokens for the current user from the present session:
saving tokens in the session after successful authentication:
app.get('/login', (req,res) => {
var scopes = [ ... ]
var authUrl = spotifyApi.createAuthorizeURL(scopes)
res.redirect(authUrl+"&show_dialog=true")
})
app.get('/callback', async (req, res) => {
const { code } = req.query
try {
var data = await spotifyApi.authorizationCodeGrant(code)
const { access_token, refresh_token } = data.body
spotifyApi.setAccessToken(access_token)
spotifyApi.setRefreshToken(refresh_token)
req.session.spotifyAccount = { access_token, refresh_token }
res.redirect('...')
} catch(err) {
res.send(`error ${err}`)
}
});
app.get('/userinfo', async (req,res) => {
try {
spotifyApi.setAccessToken(req.session.spotifyAccount["access_token"])
spotifyApi.setRefreshToken(req.session.spotifyAccount["refresh_token"])
var result = await spotifyApi.getMe()
console.log(result.body);
res.status(200).send(result.body)
} catch (err) {
res.status(400).send(err)
}
});
since access_token is only identification key which identifies any API request, that ensures that API endpoints are called for the current user. This technique prevents mess and confusion, so that each user can see and manipulate his data only.

Authenticate with Azure AD with Node

I have a Native Client Application setup in my Azure Active Directory environment. I am trying to write a Node app for Utility purposes to interact with the Azure Management APIs. My challenge is just authenticating my app. At this time, I have:
let azure = {
clientId: '[only-for-my-eyes]',
key: '[only-for-my-eyes]',
tenantDomain: 'mydomain.onmicrosoft.com',
tenantId: '[only-for-my-eyes]'
};
let authenticationRequest = {
url: `https://login.microsoftonline.com/${azure.tenantDomain}/oauth2/v2.0/authorize`,
headers: {
'Content-Type':'application/x-www-form-urlencoded'
},
formData: {
response_type: 'code',
response_mode: 'form_post',
grant_type:'client_credentials',
resource: 'https://management.azure.com',
client_id: azure.clientId,
client_secret: azure.key
}
};
request.post(authenticationRequest, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
} else {
console.log(response.statusCode);
console.log(response.statusMessage);
}
});
When the above runs, the 200 status code block is executed. But, it just prints out a bunch of HTML. If I'm looking at it correctly, it looks like the HTML of the login screen. I'm trying to get an access token that I can pass to the management APIs.
What am I missing?
Why not just use ARMClient? All the nasty token business is taken care of.
From https://www.npmjs.com/package/armclient:
Initialization:
// ES5
var ArmClient = require('armclient');
var client = ArmClient({
subscriptionId: '111111-2222-3333333',
auth: ArmClient.clientCredentials({
tenantId: '444444-555555-666666666',
clientId: '777777-888888-999999999',
clientSecret: 'aaaabbbbbccccc' // or servicePrincipalPassword
})
});
Get resources in your subscription:
client.get('https://management.azure.com/subscriptions/111-222-333-444/resourceGroups/lab/providers/Microsoft.Automation/automationAccounts', { 'api-version': '2015-10-31' })
.then((res) => {
console.log(res.body);
console.log(res.headers);
})
.catch((err) => {
console.log(err);
});
I believe that particular endpoint is intended for a GET with those given parameters, not a POST. I suspect what you're seeing is probably just the generic error message:
Sorry, but we’re having trouble signing you in.
We received a bad request.
What you are trying to do is to call the authorization page with a POST request. You don't have to send a POST (or GET) request here, you must redirect your user to that authorization URL.
In addition, you must have a redirect URI (I don't see it in your azure object). This redirect URI is a callback to your application. For the rest of my answer, let say it is stored in azure.redirectUri
let url = 'https://login.microsoftonline.com/${azure.tenantDomain}/oauth2/v2.0/authorize?response_type=code&response_mode=form_post&client_id={azureclient_id}&resource=https%3A%2F%2Fmanagement.azure.com&redirect_uri={azure.redirectUri}'
response.writeHead(302, {
'Location': url
});
response.end();
The user will be redirected to the authorization page and will have to accept (or deny) your application request. Then the user is redirected back to your Node.js application (azure.redirectUri).
As your response_mode is form_post, if the user accepted your application request, you will receive the authorization code in the body parameters.
With that code your application will be able to get an access token by calling the token endpoint.

Loopback - Implementing custom authentication

We are developing a REST service but we already have an infrastructure in place to manage users. But we want to leverage the authentication and authorization mechanism of Loopback. The requirement is to
Add a remote method and receive the user credentials
Manually verify the credentials through stored procedure call
Generate the access token through Loopback
Going forward use Loopback authorization mechanisms such as roles in the application
Should I be implementing a custom login service provider using Loopback's third party login support ? I couldn't find a very good resource on this area. Any pointers would be much appreciated.
Please check some of the following examples to see if it fits your use case:
https://github.com/strongloop/loopback-example-access-control
https://github.com/strongloop/loopback-example-passport
My example is using a bootscript in express but you could easily change it into a remote method.
module.exports = function(app) {
//get User model from the express app
var UserModel = app.models.User;
app.post('/login', function(req, res) {
console.log(req.body);
//parse user credentials from request body
const userCredentials = {
"username": req.body.username,
"password": req.body.password
}
UserModel.findOne({
"where": {
"username": userCredentials.username
}
}, function(err, user) {
// Custom Login - Put the stored procedure call here
if (err) {
//custom logger
console.error(err);
res.status(401).json({
"error": "login failed"
});
return;
}
// Create the accesstoken and return the Token
user.createAccessToken(5000, function(err, token) {
console.log(token)
res.json({
"token": result.id,
"ttl": result.ttl
});
})
})
});
}
Now you can use that Token for Loopbacks authorization mechanism.

Does the Gmail API support JWT?

I want to access the Gmail API using NodeJS.
I'm using a server-to-server approach (see this) but when I execute the code below, I get a backEndError, code 500 from the Google API.
Any ideas?
var authClient = new google.auth.JWT(
'email',
'key.pem',
// Contents of private_key.pem if you want to load the pem file yourself
// (do not use the path parameter above if using this param)
'key',
// Scopes can be specified either as an array or as a single, space-delimited string
['https://www.googleapis.com/auth/gmail.readonly']
);
authClient.authorize(function(err, tokens) {
if (err)
console.log(err);
gmail.users.messages.list({ userId: 'me', auth: authClient }, function(err, resp) {
// handle err and response
if (err) {
console.log(err);
});
Yes, I have the same problem. If I use the scope "https://mail.google.com", I get
403
{
"error" : "access_denied",
"error_description" : "Requested client not authorized."
}
And if I use the scope "https://mail.google.com/" (notice the / at the end), I get
403
'Forbidden'
It seems to be related to using JWT and service account.

Resources