Azure Mobile Services - Getting more user information - javascript

I inherited a Windows 8 application that is written with XAML. So in C# when I make this call
user = await MobileServices.MobileService
.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount);
(This is for Azure Mobile Services)
The user object is ONLY giving me the Token and the MicrosoftAccount:..............
In order to get to authenticate people, I need to be able to see WHO is requesting access...
I looking at articles like below, but I seem to be missing something? Is this javascript in the article something I would have to write in Node.js?
Example article:
http://blogs.msdn.com/b/carlosfigueira/archive/2013/12/12/expanded-login-scopes-in-azure-mobile-services.aspx

Currently to be able to get more information about the logged in user, you need to make a second call to the service to retrieve the user info. You don't really need to ask for additional login scopes (the topic of the post you mentioned) to retrieve the user name, since that is given by default for all the providers.
This post should have the code you need to write in the server side (node.js) to get more information about the logged in user. The TL;DR version is given below:
On the server side: add this custom API (I'll call it "userInfo"; set the permission of GET to "user", and all others to admin):
exports.get = function(request, response) {
var user = request.user;
user.getIdentities({
success: function(identities) {
var accessToken = identities.microsoft.accessToken;
var url = 'https://apis.live.net/v5.0/me/?method=GET&access_token=' + accessToken;
var requestCallback = function (err, resp, body) {
if (err || resp.statusCode !== 200) {
console.error('Error sending data to the provider: ', err);
response.send(statusCodes.INTERNAL_SERVER_ERROR, body);
} else {
try {
var userData = JSON.parse(body);
response.send(200, userData);
} catch (ex) {
console.error('Error parsing response from the provider API: ', ex);
response.send(statusCodes.INTERNAL_SERVER_ERROR, ex);
}
}
}
var req = require('request');
var reqOptions = {
uri: url,
headers: { Accept: "application/json" }
};
req(reqOptions, requestCallback);
}
});
}
On the client side, after a successful login, call that API:
user = await MobileServices.MobileService
.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount);
var userInfo = await MobileServices.MobileService.InvokeApiAsync(
"userInfo", HttpMethod.Get, null);
userInfo will contain a JObject with the user information. There is an open feature request to make this better at http://feedback.azure.com/forums/216254-mobile-services/suggestions/5211616-ability-to-intercept-the-login-response.

Related

Express.js update/put route does not work

I have a website where I want to add, edit and delete student contact data. The data is stored in a SQLite database. My post, get and delete routes (Express API) work but my update route does not.
I load the data of an existing contact into a html form and my plan is to edit the data in the form to send the updated data via a button. But I get the error message "Cannot GET /api/update/contacts/1" although I've implemented a POST method request.
I guess the request doesn't hit the API endpoint but I don't know why, especially since all the other routes are working. Can anyone help?
I already tried MethodOverride, but it also did not work.
The code in my html page with the form and the button:
<form method="POST" id="myForm">
<button
onclick="update()"
id="aktualisierenButton"
type="submit"
>Aktualisieren
</button>
<script>
function update() {
window.open("/api/update/contacts/" + localStorage.getItem("paraID"),
"_blank",
"toolbar=no,scrollbars=no,width=800,height=800");
window.close();
}
I already tried MethodOverride, but it also did not help.
The code in my start.js file where I handle the routes:
app.put("api/update/contacts/:studentID", async (request, response) => {
const studentID = parseInt(request.params.studentID);
const existingContact = await contactsManager.getContact(studentID);
if (existingContact) {
const contact = request.body;
await contactsManager.updateContact(studentID, contact);
response.status(200).send();
} else {
response.status(400).send({
error: "The contact with the specified studentID does not exist.",
});
}
});
The code in my ContactsManager.js file where I handle the database requests:
async updateContact(studentID, contact) {
return new Promise((resolve, reject) => {
db.run(
"UPDATE contacts SET vorname = ?, nachname = ?, mail = ? WHERE studentID = ?",
[contact.vorname, contact.nachname, contact.mail, studentID],
(error, row) => {
if (error) {
reject(error);
} else {
resolve(row);
}
}
);
});
}
You are getting the error because window.open will make a GET request to the resource and load it into a window. Instead of creating a new window then destroying it just to update your data, try using the Fetch API instead.
Using the fetch api with a PUT request would look something like below. You will need to adapt this to your specific data, and process or display the result if that's what you are trying to achieve by opening a new window, but this should give you a starting point.
try {
let fetchUrl = "https://mysite.url/api/update/contacts/" + localStorage.getItem("paraID")
let fetchOptions = {
method: "PUT",
headers: {
"Content-Type": "application/json" // Update with your data type
},
body: JSON.stringify({
data: myData // Update with your JSON data to PUT
})
}
let response = await fetch(fetchUrl, fetchOptions)
if (response.ok) {
// Convert the response to json and process
let data = await response.json()
console.log(data)
}
} catch (error) {
// Handle network errors here
console.error(error)
}
Your endpoint also does not implement a POST request, it uses a PUT request. If you wanted a POST request you should use app.post instead of app.put, although using a PUT request is fine for what you are trying to achieve.

MS graph api get teams using javascript returns no results

i am using graph api javascript example from here https://learn.microsoft.com/en-us/graph/api/user-list-joinedteams?view=graph-rest-beta&tabs=javascript
and my code is like:
async function(req, res) {
if (!req.isAuthenticated()) {
// Redirect unauthenticated requests to home page
res.redirect('/')
} else {
let params = {
active: { calendar: true }
};
// Get the access token
var accessToken;
try {
accessToken = await tokens.getAccessToken(req);
console.log("access token is:", accessToken)
} catch (err) {
req.flash('error_msg', {
message: 'Could not get access token. Try signing out and signing in again.',
debug: JSON.stringify(err)
});
}
if (accessToken && accessToken.length > 0) {
try {
console.log("vik testing stuff12 for teams")
const user = await graph.getTeams(accessToken)
console.log("graph me:::", user)
} catch (err) {
req.flash('error_msg', {
message: 'Could not fetch events',
debug: JSON.stringify(err)
});
}
} else {
req.flash('error_msg', 'Could not get an access token');
}
res.render('calendar', params);
}
}
getTeams is
getTeams: async function(accessToken) {
const client = getAuthenticatedClient(accessToken);
const events = await client
.api('/me/joinedTeams')
.version('beta')
.get();
return events;
}
this prints no results and no error. if I replace 'me/joinedTeams' to just 'me' then it returns logged in user details.
You can got a response successfully, so it seems no error with your code as you said if you call https://graph.microsoft.com/v1.0/me you can get user information.
And I tried to call this API using my account(my account hasn't joined any Teams), and got response like below, so if you got the same response as mine, perhaps you need to check if you have joined any Teams:
On the other hand, following the document, this API needs several permissions. So please obtain your access token when debug and use JWT tool to decrypt it to check if the access token have enough scope.
And I used the same request and got Teams information after adding my account to a team.

How to conditionally render page depending on express/mssql middle ware feedback

I have made a full stack application with a register activity successfully adding to db.
How would I conditionally render the home page dependent on if the login is correct.
In my login route I have an if statement which successfully logs "bad creds" if do not exist or "login: login successful.." if it does.
I added a redirect into the handle submit(this is triggered once the login form button is pressed) which was supposed to be triggered if successful (it technically is but it determines "bad creds successful as well").
I have attempted an if stametn but I am not sure how to use this with express middle ware.
the logic I would want the the portion of handle submit to do is something along the lines of
if (login successful){
window.location.href = "/home";
}
else {
window.location.href = "/login";
(preferably with a alert )
}
Login route
app.post("/login", async (req, response) => {
try {
await sql.connect(config);
var request = new sql.Request();
var Email = req.body.email;
var Password = req.body.password;
console.log({ Email, Password });
request.input("Email", sql.VarChar, Email);
request.input("Password", sql.VarChar, Password);
var queryString =
"SELECT * FROM TestLogin WHERE email = #Email AND password = #Password";
//"SELECT * FROM RegisteredUsers WHERE email = #Email AND Password = HASHBYTES('SHA2_512', #Password + 'skrrt')";
const result = await request.query(queryString);
if (result.recordsets[0].length > 0) {
console.info("/login: login successful..");
console.log(req.body);
req.session.loggedin = true;
req.session.email = Email;
response.send("User logined");
} else {
console.info("/login: bad creds");
response.status(400).send("Incorrect email and/or Password!");
}
} catch (err) {
console.log("Err: ", err);
response.status(500).send("Check api console.log for the error");
}
});
handleSubmit(e) {
e.preventDefault();
if (this.state.email.length < 8 || this.state.password.length < 8) {
alert(`please enter the form correctly `);
} else {
const data = { email: this.state.email, password: this.state.password };
fetch("/login", {
method: "POST", // or 'PUT'
headers: {
Accept: "application/json, text/plain, */*",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
// .then(response => response.json())
.then(data => {
console.log("Success:", data);
// if ( ) {
// console.log("nice");
// } else {
// console.log("not nice");
// }
// window.location.href = "/home";
})
.catch(error => {
console.error("Error:", error);
});
}
}
catch(e) {
console.log(e);
}
You should have explained in the first place that you had a React app in the frontend. Talking at the same time about Express middleware and login route is a bit messy. :)
What you're doing is a login/sign in process through an API. This means your server should return JSON information regarding the login outcome. Then, your frontend should handle that in whatever way you want to. This means that your server should simply treat the login request as any other data request. Return a status code and some optional JSON data.
Authentication is a BIG subject and since you did't provide many details, I can only tell you how normally the overall process should go:
Send the user credentials to the server (like you do in your POST request)
Handle the response received from the server. If login was successful, you should receive some information from the server, like the user id, email, session id, either in the response JSON data or by HTTP headers. You should keep this information in the frontend, normally in localStorage, and use it for every request to the server to provide your identity. You should look up JSON Web Tokens.
In your React app, you want to check when starting the application if the user is already logged in or not (using the piece of information mentioned in step 2, or trying to fetch and endpoint that returns user information like /me). If you don't have that information or the request fails, redirect to Login.
In your React app, in your login page, handle the fetch result and redirect to home if the user is authenticated, or stay there and display whatever info you want.
I assume that since you're using user login some resources should be protected from being accessed by non logged in users or restricted depending on the logged in user. This is done with middleware on your Express server, that should check the user id / token / session id information your React app should be sending with every request.
To redirect using React Router, you don't want to use window.location. You want to use the Router itself to avoid reloading the full page. You can either use the injected history prop on your Login route component or wrap any component that needs it with withRouter HOC.
This article seem to lay out all options using React Router pretty well:
https://serverless-stack.com/chapters/redirect-on-login-and-logout.html
Hope this helps, this is a complex subject that you should split into smaller problems and tackle one at a time. ;)

How to implement json object in Cloud Functions for Firebase?

I want to verify apple in app purchase receipt by sending the original receipt to App store server for validation and get validated receipt back, using Firebase cloud functions.
var jsonObject = {
'receipt-data': receiptData,
password: functions.config().apple.iappassword
};
var jsonData = JSON.stringify(jsonObject);
var firebaseRef = '/' + fbRefHelper.getUserPaymentInfo(currentUser);
let url = "https://sandbox.itunes.apple.com/verifyReceipt";//or production
request.post({
headers: { 'content-type': 'application/x-www-form-urlencoded' },
url: url,
body: jsonData
}, function (error, response, body) {
if (error) {
} else {
var jsonResponse = JSON.parse(body);
if (jsonResponse.status === 0) {
console.log('Recipt Valid!');
} else {
console.log('Recipt Invalid!.');
}
if (jsonResponse.status === 0 && jsonResponse.environment !== 'Sandbox') {
console.log('Response is in Production!');
}
console.log('Done.');
}
});
This is the logic code. How do i input the receipt JSON object (which is sitting in the Firebase database) and how do i integrate this code in an http function? I am using 'request' npm library.
Based on your comment, it sounds as if you don't know how to query the database from within an HTTPS type function. You can use the Firebase Admin SDK for this. There are lots of examples of how to do this. In particular, this uppercase quickstart sample illustrates it. You start like this:
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

Meteor: Handling Facebook Realtime API Requests via Callback-Url with iron-router

I'm trying to use the Facebook Realtime API with a Meteor app. Basically you can subscribe to an object like page or user and get update notifications so that no polling is needed (publish/subscribe pattern).
So I need to setup a callback URL and send a post request with my callbackurl, the object & fields that I want to subscribe and a verify string. A FB server is sending a get request with my verify string and a random string (challenge) and the Meteor server has to respond to this with the challenge string. (If you're interested in details you can read here and here).
I'm getting the following error serverside:
[ec2-11-11-1-123.eu-west-1.compute.amazonaws.com] Exception while invoking method 'createSubscription' Error: error while subscribing to object page - failed [400] {"error":{"message":"(#2200) callback
verification failed: Operation timed out after 6000 milliseconds with
0 bytes received","type":"OAuthException","code":2200}}
at subscription (packages/fbuilder/lib/server/methods.js:20)
at Meteor.methods.createSubscription (packages/fbuilder/lib/server/methods.js:110)
at maybeAuditArgumentChecks (packages/livedata/livedata_server.js:1487)
at packages/livedata/livedata_server.js:643
at _.extend.withValue (packages/meteor/dynamics_nodejs.js:56)
at packages/livedata/livedata_server.js:642
at _.extend.withValue (packages/meteor/dynamics_nodejs.js:56)
at _.extend.protocol_handlers.method (packages/livedata/livedata_server.js:641)
at packages/livedata/livedata_server.js:541
So i guess something is wrong with the router part listening to the given URL...
Router.map(function () {
// Callback URL of the server for verification and receiving data via FB Realtime API
this.route('fbCallbackURL', {
path: Meteor.settings.fbCallbackPath,
where: 'server',
action: function() {
var req = this.request;
var res = this.response;
switch(req.method){
"GET" :
var hub = req.hub;
console.log("got something ...........");
if(hub && hub.verify_token === Meteor.settings.fbVerifyString
&& hub.mode==='subscribe' && hub.challenge){
res.writeHead(200);
res.end({hub: {challenge: hub.challenge}});
}
else{
res.writeHead(404);
res.end("");
}
break;
"POST":
console.log("todo");
/*
The HTTP request will contain an X-Hub-Signature header which contains the SHA1 signature of the request payload,
using the app secret as the key, and prefixed with sha1=. Your callback endpoint can verify this signature
to validate the integrity and origin of the payload.*/
break;
default: res.writeHead(404);
}
}
})
});
Here's the code where I create the subscription:
function subscription(object,fields,active){
if(object){
var url = 'https://graph.facebook.com/'+Meteor.settings.fbAppId+'/subscriptions',
res,
params = {
access_token : Meteor.settings.fbAppId + '|' + Meteor.settings.fbAppSecret,
callback_url : Meteor.settings.fbAppURL+""+Meteor.settings.fbCallbackPath,
object : object,
verify_token : Meteor.settings.fbVerifyString,
fields : fields
};
try {
res = HTTP.post(url , { params: params } );
} catch (err) {
throw _.extend(
new Error("error while subscribing to object " + object + " - " + err.message + " ",{response: err.response}));
}
return res;
}
else
new Error("subscription for invalid object requested!");
};
So I'm calling this function via a method on the server: (just for testing)
Meteor.methods({
createSubscription: function() {
return subscription("page","name",true);
}
});
Any ideas or suggestions? :(
Thanks in advance!

Categories