Application settings in Azure Mobile Services
This little feature was released over a month ago with little fanfare, and since I haven’t seen it covered anywhere I decided to write about it now. The idea of application settings is a set of key-value pairs which can be set for the mobile service (either via the portal or via the command-line interface), and those values could be then read in the service runtime. There are quite a few scenarios where this can be useful: defining a debug flag which can be easily toggled, storing secrets which shouldn’t be stored in code, or even enabling some preview features (as mentioned in this blog post). Let’s look at those scenarios:
Storing secrets
I have an account in the Twilio service which I use in some (personal) projects to send SMS messages. In one of those projects I work together with a colleague, and we develop the back-end together. To be able to access my Twilio account, I need to pass my credentials (account SID and auth token) to the Twilio SDK (in this case, the twilio npm package), as can be shown in this tutorial for accessing Twilio from an Azure Mobile Service. But I don’t want my colleague to see my credentials (in my case I wouldn’t mind, but you can imagine that the development is being done by some people who you don’t have that high of a trust relationship). So I’ll store the secrets in my app settings, and we only share the code.
Adding application settings is simple: go to the ‘configure’ tab in the Azure Mobile Services portal, and enter the key value pairs with the secrets I want to store:
Now, on the server side I can access those via the ‘process.env’ variable:
- function insert(item, user, request) {
- request.execute({
- success: function () {
- request.respond(); // send the response to the client
- // then send a SMS about the new item
- var twilio = require('twilio');
- var accountSid = process.env.TwilioAccountSid;
- var authToken = process.env.TwilioAuthToken;
- var myTwilioNumber = '+14045551234';
- var myPhoneNumber = '+12065555678';
- var client = new twilio.RestClient(accountSid, authToken);
- client.sendSms({
- to: myPhoneNumber,
- from: myTwilioNumber,
- body: 'Item inserted, with id = ' + item.id
- }, function (err, msg) {
- if (err) {
- console.warn('Error sending SMS: ', err);
- } else {
- console.log('SMS sent successfully: ', msg);
- }
- });
- }
- });
- }
Now that code can be shared with my collaborators and my credentials will remain secure…
Conditional code execution
In one of my services I was tracking down an issue that happened in my API script which was returning a 500 (Internal Server Error) for some unknown reason. I started then adding tracing to the script. Once I found the issue I could have simply deleted all the tracing, but since they were helpful for me to debug that problem I decided to leave them there, but disabled until I needed to. So this is a (very simplified) version of my script:
- exports.get = function (request, response) {
- var config = request.service.config;
- var isDebug = config.appSettings.isDebug === 'true';
- if (isDebug) {
- console.log('request url: ', request.url);
- console.log('request headers: ', request.headers);
- console.log('request query: ', request.query);
- }
- var result = process(request);
- response.send(200, result);
- if (isDebug) {
- console.log('API execution reached the end');
- }
- }
And if I wanted to enable that debugging again, all I need is to add the app setting ‘isDebug’ with the value ‘true’. Notice that I’m accessing the app setting via a config object this time instead of directly via the process environment. More on that later on this post…
Enabling preview features
Starting a couple of weeks back, the mobile services team started releasing some runtime features in a preview mode, and they can be enabled via app settings. The idea is that if enough people start using them, they will get the first-class treatment of other features in the Azure Mobile Services portal. As I mentioned in this blog post, during login you can now request additional scopes from some of the authentication providers (Facebook, Google, Microsoft) via an app setting. This gives more information to the user object which is passed to table and API scripts. For example, before this feature the only information you could get from the Facebook Graph API about the logged in user was some basic information. But if you wanted the user’s e-mail and the list of their friends, you were out of luck with the simple authentication, having to use a native Facebook SDK instead. Let’s see how this can be done with this new preview feature (authentication scopes)
First, you need to set, on the Facebook app itself (from https://developers.facebook.com) define those permissions
After that, you can tell the mobile service to request those permissions when presenting the authentication page, by setting the ‘MS_FacebookScope’ app setting:
Now, if you have a logged in user, if you talk to the Facebook Graph API (as I showed in this blog post) you’ll get the user’s e-mail if you request the ‘/me’ resource in the API.
The mobile service configuration
I mentioned that you can use the process.env object, or the config object to access the application settings. But those objects aren’t restricted to settings you define in the configure tab in the portal – they contain a lot more useful information as well, including information about the mobile service name, keys, identity providers and so on. Depending on what you have configured in your service, you’ll have more or less information on the config object.
This simple API can be used to show all the information from the config:
- exports.get = function (request, response) {
- console.log('Config: ', request.service.config);
- response.send(statusCodes.OK, {
- message: 'Look at logs for config info'
- });
- };
After invoking the API from Fiddler, I go to the logs and this is the output for my service (with lots of secret information redacted).
{
"mobileServiceName":"blog20131124",
"masterKey":"The-master-key-of-my-mobile-serv",
"applicationKey":"The-app-key-of-my-mobile-service",
"sqlConnectionString":"The-connection-string-to-the-database",
"dynamicSchemaEnabled":"True",
"microsoftClientID":"my-ms-client-id",
"microsoftClientSecret":"my-ms-client-secret",
"facebookAppID":"my-facebook-app-id",
"facebookAppSecret":"my-facebook-app-secret",
"facebookScope":"email user_friends",
"googleClientID":"my-google-client-id",
"googleClientSecret":"my-google-secret",
"twitterConsumerKey":"my-twitter-consumer-key",
"twitterConsumerSecret":"my-twitter-consumer-secret",
"apnsCertificatePassword":"",
"apnsCertificateMode":"None",
"crossDomainWhitelist":"[{\"host\":\"localhost\"}]",
"appSettings":{
"MS_FacebookScope":"email user_friends",
"isDebug":"true"
}
}
One more thing to notice: in custom APIs the configuration object can be obtained via the ‘request.service’ object. In scripts for table operations, there’s no place from where the “services” can be accessed, so you need to require the special ‘mobileservice-config’ module that exports that object. This table read script will do exactly the same as the API shown above:
- function read(query, user, request) {
- var config = require('mobileservice-config');
- console.log('Config: ', config);
- request.respond(statusCodes.OK, {
- message: 'Look at logs for config info'
- });
- }
And I’ll leave to your creativity to decide what you can do with all this new information that you can get in your runtime scripts :)
Coming up
In the next post I’ll expand on the authentication scopes feature, with examples from more authentication providers.
Comments
- Anonymous
December 17, 2013
Hi Carlos. This is fantastic news. Well done to the azure team for listening to the developers and including this and THANK YOU for posting about it. I have been searching and searching to no avail until I found your post!T - Anonymous
December 17, 2013
Just one follow-up question regarding the preview features of new social login scopes...I understand that this means that the user object will have access to user_friends/email etc. Am I correct in assuming that the application itself (with the auth token of "[AppID]|[AppSecret]") can also get this information for any registered user? I have a scheduled service that I would like to run through each user in my user table and query [facebook] for user_friends. I am hoping that this change would mean this would be possible??Thanks again,T - Anonymous
December 18, 2013
Tomás,You can only get the access token (where you'd get additional information) for the logged in user, not all other users which you stored in your database. So no, it would not be possible. In theory when you store your user you can also store its Facebook access token so you could later query the FB Graph API to get that information, but it's likely that the token will have expired. IIRC there's a functionality in the graph API where you can get a long duration access token, which could be used in this case, you can look into the FB documentation for that.Hope this helps,Carlos.