I am trying to create a custom API for Azure Mobile Services that does a Transact-SQL command on the table. According to the docs I should be able to use an object called 'mssql' to do this (http://msdn.microsoft.com/en-us/library/jj554212.aspx). However, the object does not seem to exist and my backend script always fails with error 500 (internal server error). Does this object not exist in custom API backend scripts?
To use that object in a custom API, you should access it via the request object passed to the API:
exports.get = function(request, response) {
var mssql = request.services.mssql;
mssql.query('select GETDATE() from myTable', {
success: function(results) {
response.send(200, { serverTime: results[0] });
}
});
}
Related
I am trying to connect my javascript app AWS WebRTC with a Cognito user to get its credentials dynamically but faced the following error code:
json.js:52 Uncaught (in promise) CredentialsError: Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1
I have done hard coding my credentials into the configuration and it has work successfully, however that's a bad practice hence I am trying to get AWS Web RTC credentials via my Cognito user. I have setup user pool and link in to my federal identities already. The credentials are now managed by AWS Amplify which loads AWS user profile from config file (./aws/credentials).
Following this two guides:
https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-integrating-user-pools-with-identity-pools.html
https://docs.aws.amazon.com/cognito/latest/developerguide/getting-credentials.html
I've written the following snippet to get my credentials but now faced the error.
AWS.config.region = '<REGION>';
AWS.config.update({
credentials: new AWS.CognitoIdentityCredentials({
IdentityPoolId: '<Region>:<IdentitiyPoolID>',
Logins: {
'cognito-idp.<Region>.amazonaws.com/<UserPoolID> ': <id token from cognito>,
},
}),
});
var accessKeyId;
var secretAccessKey;
AWS.config.credentials.get(function () {
accessKeyId = AWS.config.credentials.accessKeyId;
secretAccessKey = AWS.config.credentials.secretAccessKey;
});
const state = {
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey,
region: 'region',
}
async function startPlayerForViewer();
Any helps is much appreciated ! Cant find much updated resources/examples online.
credentials.get() is an async operation that receives the keys in a callback, while the state definition happens before that callback is received. Hence, the keys are not set. You need to ensure that you define the state after the callback and ensure that the connection happens afterwards.
I have created a simple REACT application that is ONLY run on a local PC attached to a large screen on our network. Internal use only! It is like a billboard or dashboard. There is ZERO user interaction. The screen is NOT a touch screen and there is no keyboard and mouse attached. Therefore NO users to login.
The REACT application is build and then deployed to a folder on the PC. All automated. The initial deployment includes all current data. Then at windows startup a command something like this is executed:
"python -m http.server 3000" (just example...)
The application has initial data that was deployed with the application, however, I would like it to also be able to call a secure Azure WebAPI service to get updated statistics every few minutes. Very small data. Mostly integer values. I just want to provide some real time updates.
I have the REACT app fully working (if the WEBAPI is not secure) or the individual calls allow anonymous. However, we have business rules that require all endpoints to be secure.
This app runs locally, but the API is an Azure App Service.
I have setup the REACT application in Azure AD as a registered application and configured it to have permissions to call the WEBAPI service.
I have many console applications that are setup and work basically the same way as this REACT application. With the C# daemon applications, there is a MSAL package that makes it easy.
I am trying to learn REACT, and instead of building this as another WPF or UWP application, I wanted to try using REACT.
So, I know I need an access token somehow. I was thinking with a client ID and Secret just like I do in my C# daemon clients that are written in C#.
I cannot find any REACT nor Angular examples that do this without a user login first. Remember, the PC does not have input devices. Display ONLY. Again, my app does not have users. It calls a secure API to get data. That's it.
Thanks for your help.
Using Joy Wang's comments and this page from documentation:
Service-to-Service Access Token Request
This is my new code:
const adalConfig = {
tenant: '...',
clientId: '...',
clientSecret: '...',
authority: 'https://login.microsoftonline.com/{tenant}/oauth2/token',
endpoints: {
apiResourceId: 'api://bbbbbb-...',
},
};
function getAccessToken() {
var requestParams = {
grant_type: 'client_credentials',
client_id: adalConfig.clientId,
client_secret: adalConfig.clientSecret,
resource: adalConfig.endpoints.apiResourceId
};
// Make a request to the token issuing endpoint.
fetch(adalConfig.authority,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify( requestParams )
}).then(response => {
if (response.status >= 200 && response.status < 300) {
console.log(response);
console.log(response.json());
} else {
console.log('Somthing happened wrong');
console.log(response);
}
}).catch(err => err);
}
When I call the function above, I get the following response:
Response {type: "cors", url: "https://login.microsoftonline.com/.../oauth2/token", redirected: false, status: 400, ok: false, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 400
statusText: "Bad Request"
type: "cors"
url: "https://login.microsoftonline.com/.../oauth2/token"
proto: Response
Maybe there is another way to start the REACT application so that CORS is not checked? Any ideas?
Thanks again.
So, currently there is not a secure way to do what I want. The basic issue is that you cannot use the client credential grant type from JavaScript in a browser.
However, I think I have a good work around that may help others. I am sure it is NOT for most application. And I believe OAUTH is working on a solution so this may not be needed in the near future. If a better solution is add, I will gladly mark it as the correct answer. Thanks for your help.
My app is basically an automated dashboard/billboard with ZERO user input. It pulls secure data and displays it. The REACT application is ONLY on a LOCAL PC on a wall with NO inputs. A script runs when the PC is turned on.
The script starts the built REACT application using an http server like python.
Ex: "python -m http.server 8000"
The script then opens the browser in kiosk mode so the only thing you see on the screen is the application.
So far, this is exactly as I had it before.
WORK AROUND:
I created a command line utility called GetToken. Before the REACT application is started by the script, it calls this utility like so: "gettoken --client Dashboard --file token.json"
This utility makes the Client Credential Grant Type call to get a token.
It then saved that token to a local json file with the other built REACT files. Ex: \public\data\token.json
In my REACT application, it just loads the token and uses it.
const t = await fetch('./data/token.json').then(r => r.json());
this.setState({ token: t.token });
Then I just add this to my api calls like so:
const fetchOptions = {
method: 'GET',
headers: {
"Authorization": `Bearer ${this.state.token}`,
"Content-Type": "application/json"
}
};
const newSlides = await fetch(this.state.baseUrl + '/api/Dashboard/GetSlides', fetchOptions).then(response => response.json());
IMPORTANT: This only works if you also have the ability to update the API. If you cannot, then you will still get CORS errors. You will have to allow calls from the localhost and port you use to start you application. You should pick something other than 3000, 4200, or 8000.
I added the following to my API startup.cs:
public void ConfigureServices(IServiceCollection services) {
...
var origins = Configuration.GetSection("AppSettings:AllowedOrigins").Value.Split(",");
services.AddCors(o => o.AddPolicy(specificOriginsPolicy, builder => {
builder.WithOrigins(origins)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.SetIsOriginAllowed((host) => true);
}));
...
}
public void Configure(IApplicationBuilder app) {
...
app.UseCors(specificOriginsPolicy);
...
}
I am still refining this solution, but it works well so far. I may turn the utility into a background service that is updating the token on an interval. Or I may turn the utility into a Shell, and then use it instead of the script. Either way, you get the idea.
LESSON:
I know I could have done this as a UWP or WPF application and avoided all these issues, but the main goal was to learn REACT. I learned a lot. I would do it again. It is shocking just how little code there is to my REACT application now that it is done. I believe REACT could be used for many similar scenarios.
You could refer to this sample, it uses client credential flow(i.e. client id and secret you want) to get the access token, just change the resource to the one you want to get token for, the sample gets the token for Microsoft Graph.
auth.getAccessToken = function () {
var deferred = Q.defer();
// These are the parameters necessary for the OAuth 2.0 Client Credentials Grant Flow.
// For more information, see Service to Service Calls Using Client Credentials (https://msdn.microsoft.com/library/azure/dn645543.aspx).
var requestParams = {
grant_type: 'client_credentials',
client_id: config.clientId,
client_secret: config.clientSecret,
resource: 'https://graph.microsoft.com'
};
// Make a request to the token issuing endpoint.
request.post({ url: config.tokenEndpoint, form: requestParams }, function (err, response, body) {
var parsedBody = JSON.parse(body);
console.log(parsedBody);
if (err) {
deferred.reject(err);
} else if (parsedBody.error) {
deferred.reject(parsedBody.error_description);
} else {
// If successful, return the access token.
deferred.resolve(parsedBody.access_token);
}
});
return deferred.promise;
};
I followed the following tutorial to create a RESTApi for my node server...https://scotch.io/tutorials/build-a-restful-api-using-node-and-express-4
My server file now has routes that allow it to to make GET and POST requests which I've tested on Postman and they work. My server file is pretty long but here is an excerpt to get an idea of how it works...
router.route('/bears')
// create a bear (accessed at POST http://localhost:8080/api/bears)
.post(function(req, res) {
var bear = new Bear(); // create a new instance of the Bear model
bear.name = req.body.name; // set the bears name (comes from the request)
// save the bear and check for errors
bear.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Bear created!' });
});
})
.get(function(req, res) {
Bear.find(function(err, bears) {
if (err)
res.send(err);
res.json(bears);
});
});
router.route('/bears/:bear_id')
// get the bear with that id (accessed at GET http://localhost:8080/api/bears/:bear_id)
.get(function(req, res) {
Bear.findById(req.params.bear_id, function(err, bear) {
if (err)
res.send(err);
res.json(bear);
});
});
...etc,etc
Now, since I am using an ionic framework I need to configure it to use this server as a backend.
My problem is, how do I connect to it using angular?
All my routes are prefixed using /api
app.use('/api', router);
So I tried the following...
app.factory('Bear', function ($resource) {
return $resource('http://XXX.XXX.X.XX:3000/api/bears/:bearId');
});
But I'm not sure this is working. I want to make one Post request so that I can test that the backend is working but I do not know what code to add to do so.
For example, if I have a form on my index.html and I send this info to my angular controller, how can my controller take this info and make a post request to my server? I've been trying to figure this out for days.
If you just want to test that your backend is working, check out postman.
Here's how you can refactor your code. First, note that as it is currently, how you're using $resource isn't actually make any calls to the API. You should inject your Bear service in a controller or another service somewhere in your app, depending on how you're going to use the bears. Then, in this other service or controller, you would do
var result = Bear.get({ bearId: <value> }) or var result = Bear.post({ bearId: <value> })
or whatever other http method you want to use. The resource object will then automatically hit the URL endpoint with the specified HTTP action and the parameter you have provided and then return you back the result.
Check out the $resource documentation for more detail. Also, the fact that you're using ionic has no bearing on connecting to the API.
I'm using AngularJS Sdk from Strongloop to develop the mobile application with ionicframework.
In between the development progress, i failed to use the mongodb function from angular. I always get the unexpected result without any error message. Hope can get some help. Thanks.
var feed$ = Feed.find({
filter : {
$or : [{ accountId : "569a9fc898e6f58b0329eefc" }, { accountId : "569a9fa098e6f58b0329eefb" }]
}
});
Loopback AngularJS SDK provides client-side representation of the models and remote methods in the LoopBack server application. What you actually use is not MongoDB query (at least not directly). You are calling angular service which is calling remote method from persisted model on server. Loopback then translates your request to query using database connector. In your case this is MongoDB connector.
That being said correct way to use find method in loopback angularjs sdk is:
Feed.find({
filter: {
where: {
or: [{accountId: "569a9fc898e6f58b0329eefc"}, {accountId: "569a9fa098e6f58b0329eefb"}]
}
}
},
function (feeds) {
console.log(feeds); //query result is available in callback function
});
I'm trying to access Dynamics CRM OData using AngularJS but I'm not sure where to set my credentials. I'm getting a 401 (Unauthorized) error with this code:
angularDynamicsCRM.factory('DynamicsCRMService', function ($resource)
{
var oDataUrl = Xrm.Page.context.getClientUrl() + '/XRMServices/2011/OrganizationData.svc/';
var defaultParams = {};
/// describe our API actions
var actions = {
lookup: {
method: 'GET',
url: oDataUrl + ':entitySet?$filter=startswith(:field, \':search\')',
withCredentials: true
}
};
/// create the service
return $resource(oDataUrl, defaultParams, actions); });
How can I set my CRM credentials when accessing the OData using this code?
As per Microsoft definition "Dynamics CRM does not permit authentication from external applications."
However, a Web resource such as a Silverlight XAP file or a JavaScript file that is hosted in a Dynamics CRM solution can use the OData service as a data source
There is already a question in SO here. See the accepted answer.