Share via


How to implement Shared Access Signatures using Azure Mobile Services and Node.js

This post will provide essential skills to enable you to use shared access signatures to upload photos as blobs. Azure mobile services using node.JS.

This is supporting documentation for an upcoming MSDN article around the creation of a raspberry pi application that is fitted with the camera and capable of uploading images to the cloud.

This same code can be used for virtually any client application that wishes to upload images to the cloud.

The end result of this post is to provide client applications a shared access signature, which is a secure and efficient way to enable client applications to upload files to the cloud.

Here are the high-level steps of this post:

  1. Provisioning an Azure Storage Account

    • Recording the account name, account key, and container name
  2. Provisioning an Azure Mobile Service

    • Adding Node.js code to it
  3. Testing with a REST client

SmartDoor Client on Github - Mono-based C# Raspberry PI Client https://github.com/sedouard/SmartDoorDemo
Raspberry Pi - Basic hardware setup, Plugging in camera, Connecting GPIO breakout, Closing up case https://stevenedouard.com/wiring-raspberry-pi-send-photos-cloud/
Running code on your Raspberry Pi to Send Photos the Cloud https://stevenedouard.com/running-code-raspberry-pi-send-photos-cloud/
How to upload Node Packages to Azure Mobile Services https://blogs.msdn.com/b/brunoterkaly/archive/2014/06/18/how-to-upload-node-packages-to-azure-mobile-services.aspx#
How To Provision A Shared Access Signature That Allows Clients To Upload Files To To Azure Storage Using Node.js Inside Of Azure Mobile Services https://blogs.msdn.com/b/brunoterkaly/archive/2014/06/13/how-to-provision-a-shared-access-signatures-that-allows-clients-to-upload-files-to-to-azure-storage-using-node-js-inside-of-azure-mobile-services.aspx#
Running .net Applications On A Raspberry Pi That Communicates With Azure https://blogs.msdn.com/b/brunoterkaly/archive/2014/06/11/mono-how-to-install-on-a-raspberry-pi.aspx#
Using Fiddler and Advanced Rest Client to test Azure Storage and Azure Mobile Services https://blogs.msdn.com/b/brunoterkaly/archive/2014/06/18/using-fiddler-and-advanced-rest-client-to-test-azure-storage-and-azure-mobile-services.aspx

PROVISIONING AN AZURE STORAGE ACCOUNT

  1. If a client is to upload a file storage, we need to provision a storage account

  2. The storage account will have a name, key, and container for blobs

  3. Hit "+" to create a new storage account.

    image001

    Figure 1: Creating a new storage account

  4. Click Quick Create

    image002

    Figure 2: Choosing QUICK CREATE

  5. Type in a unique URL.

  6. Choose a region that you are consistent with. Mobile Services that we will provision will need the same region.

    image003

    Figure 3: Specifying URL, location, etc

  7. It will take less than 1 minute to provision.

    image004

    Figure 4: Viewing progress

  8. Click MANAGE ACCESS KEYS. We will need this later for Azure Mobile Services.

    image005

    Figure 5: Managing Access Keys

  9. Drill into the service by hitting

    image006

    Figure 6: Verifying online

  10. Choose CONTAINERS.

    image007

    Figure 7: Choosing CONTAINERS

  11. Select CREATE A CONTAINER

  12. Provide a container name and write it down. You will need it later.

    image008

    Figure 8: Providing a container name and access

  13. Note the container name

    image009

    Figure 9: Validating container creation

RECORDING THE ACCOUNT NAME, ACCOUNT KEY, AND CONTAINER NAME

  1. Take note of the information (account name, access key, container name, etc).

    image010

    Figure 10: Recording Access Keys

PROVISIONING AN AZURE MOBILE SERVICE

  1. Provision an Azure Mobile Service account

  2. It will be used to respond to client devices that want to upload files

  3. It will provide a Shared Access Signature

    • A shared access signature provides delegated access to resources in your storage account. This means that you can grant a client limited permissions to your blobs, queues, or tables for a specified period of time and with a specified set of permissions, without having to share your account access keys
    • This allows clients to upload to storage directly on a secure fashion
  4. Navigator mobile services and click the + to provision a new service

    image011

    Figure 11: Creating a new Mobile Service

  5. Make sure to select CREATE

    image012

    Figure 12: Creating a new Mobile Service

  6. Enter the URL for the new mobile service

  7. We will not initially be using the database so you can select whatever you want there

    image013

    Figure 13: Providing a URL, Database, etc

  8. Provision a new SQL Database or use an existing one

  9. We will not initially use a database so it doesn?t matter much right now.

    image014

    Figure 14: Indicating database settings

  10. It will take a few moments to provision.

    image015

    Figure 15: Verifying creation of mobile service

CREATING THE NODE.JS BACKEND

  1. Drill into to the service by hitting ->

    image016

    Figure 16: Verifying mobile service is ready

  2. From the menu below choose API

    image017

    Figure 17: Creating a custom API (for get requests)

  3. Provide a new API name. This is the API name used by clients in their web request. Leave permissions to their default values.

    image018

    Figure 18: Providing an API name

  4. Verify that you have provisioned a new API. Click the right arrow (->) to drill into the API just created.

    image019

    Figure 19: Verifying API

  5. To note is the default code below. We will replace it with our own code that returns a shared access signature

    image020

    Figure 20: Viewing default API code

  6. Here is what the code looks after you paste in the code provided below    

    Node.js in Azure Mobile Services
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 var azure = require('azure'); var qs = require('qs'); var blobService; // used to communicate with blob storage service var containerName; // container must exist to support photo uploads var accountName; // storage account name (you create at portal) var accountKey; // storage account key (generated for you) var blob = 'sassample' var BlobConstants = azure.Constants.BlobConstants; var ServiceClient = azure.ServiceClient; var CloudBlobClient = azure.CloudBlobClient; // Issued by Raspberry Pi // https://[you put yours here].azure-mobile.net/api/photos // With headers = "X-ZUMO-APPLICATION: [get the mobile servies app key from the portal]" // Header contains your "application key" /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Entry point here // // /////////////////////////////////////////////////////////////////////////////////////////////////////////////// exports.get = function(request, response) {     // These are part of "App Settings" in the configuration section     // of your service. Shouldn't be hard-coded into this Node.js script     containerName = request.service.config.appSettings.PhotoContainerName;     accountName = request.service.config.appSettings.AccountName;     accountKey = request.service.config.appSettings.AccountKey;     // Connect to the blob service     blobService = azure.createBlobService(accountName,                         accountKey,                         accountName + '.blob.core.windows.net');     createContainer();     createPolicies();     var sasResponse = GetSAS();     return request.respond(201, sasResponse); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // // /////////////////////////////////////////////////////////////////////////////////////////////////////////////// function GetSAS() {   var startDate = new Date();   var expiryDate = new Date(startDate);   expiryDate.setMinutes(startDate.getMinutes() + 15);   var sharedAccessPolicy = {     AccessPolicy: {       Permissions: azure.Constants.BlobConstants.SharedAccessPermissions.WRITE,       Start: startDate,       Expiry: expiryDate     }   };   var blobService = azure.createBlobService(accountName,                         accountKey,                         accountName + '.blob.core.windows.net');   var blobname = genRandNum() + '.jpg';   var signature = blobService.generateSharedAccessSignature(containerName,     blobname, sharedAccessPolicy);       var sharedAccessSignature = new azure.SharedAccessSignature(blobService.storageAccount,             blobService.storageAccessKey);               blobService.authenticationProvider = sharedAccessSignature;   sharedAccessSignature.permissionSet = [signature];     console.log('baseUrl = ' + signature.baseUrl);   console.log('path = ' + signature.path);   console.log('queryString = ' + encodeURIComponent(signature.queryString));   console.log('queryString = ' + signature.queryString);       var sasResponse = { 'sasUrl': signature.baseUrl + signature.path + '?' +                       qs.stringify(signature.queryString),                       'photoId': blobname, 'expiry':expiryDate };   return sasResponse; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // Purpose: Generate a random number to use in the filename // // /////////////////////////////////////////////////////////////////////////////////////////////////////////////// var genRandNum = function() {     return Math.floor(Math.random() * 90000) + 10000; }

    image021

    Figure 21: Pasting in code

  7. Return back to the portal main menu and choose MANAGE KEYS, as seen in the lower right corner of the diagram below.

    image022

    Figure 22: Retrieving the application key

  8. Take note that the application keys below. Clients will use these to connect to the service. Save this application key to be used later when we use a rest-based client to test our mobile service.

    image023

    Figure 23: Getting the applications

STORING CONFIDENTIAL INFORMATION INSIDE APP SETTINGS

  1. App settings is a safe and convenient way to avoid hardcoded in your node.JS scripts

  2. It is similar to the configuration file for a web application

  3. We will use it to store our storage account information, such as the computer name, storage account name, and access keys

ADDING APP SETTINGS

  1. Choose CONFIGURE from the menu below

    image024

    Figure 24: Configuring App Settings

  2. Notice the app settings provided below

  3. This information comes from the previously provisioned storage account. This information is available from the Azure storage account portal

  4. Putting it here avoids hard coding it into our mobile service application

    image025

    Figure 25: Specifying App Settings

TESTING WITH A REST CLIENT

  1. We are now ready to begin testing our freshly created service.

  2. There are any number of rest-based client applications to test with

  3. The one below is a Google Chrome extension called advanced rest client

  4. It is free and works well for testing purposes

    image026

    Figure 26: Using Advanced REST Client

HOW TO USE ADVANCED REST CLIENT

  1. Notice that there are five pieces to this

    • This is the URL by clients who used to request the shared access signature

      • Notice the first part of the URL is the name of the mobile service
      • The last part of the URL is the actual API name we provided
    • The request type will be GET

    • There needs to be one header entry is seen below.

      • X-XUMO-APPLICATION is the key
      • The value here is the application key for the mobile service we created
    • Click send to call into the mobile service API

    • View the shared access signature returned by the service.

      • Client applications that received this signature can then upload blobs to the specified storage account
      • The scenario might be a client application that wants to upload a photo using a shared access signature

    image027

    Figure 27: Verifying the Shared Access Signature

Conclusion

This post illustrated all the needed steps to be able to call into a mobile services API. . It even demonstrated how to test the API using the Google Chrome extension, Advanced REST client.

You are required to provision both a Azure storage account as well as an Azure mobile service.

This post is useful for those who wish to upload blobs to Azure storage. having a shared access signature makes it easy for client applications to directly upload into Azure storage.

This post is part of a larger article coming in MSDN magazine, where we enable a raspberry pi device to upload photos to Azure storage services.

Comments

  • Anonymous
    August 27, 2014
    Returns a error :( { code: 500 error: "Error: Internal Server Error" }

  • Anonymous
    August 28, 2014
    Corrected for those who need it :) var azure = require('azure'); var qs = require('querystring'); exports.get = function(request, response) {    // These are part of "App Settings" in the configuration section    // of your service. Shouldn't be hard-coded into this Node.js script var containerName = request.service.config.appSettings.PhotoContainerName;    var accountName = request.service.config.appSettings.AccountName; var accountKey = request.service.config.appSettings.AccountKey; var host = accountName + '.blob.core.windows.net';    // Connect to the blob service    var blobService = azure.createBlobService(accountName, accountKey, host);      var startDate = new Date();  var expiryDate = new Date(startDate);  expiryDate.setMinutes(startDate.getMinutes() + 15);  var sharedAccessPolicy = {    AccessPolicy: {      Permissions: azure.Constants.BlobConstants.SharedAccessPermissions.WRITE,      Start: startDate,      Expiry: expiryDate    }  };    var genRandNum = Math.floor(Math.random() * 90000) + 10000;    var blobname = genRandNum + '.jpg';  var signature = blobService.generateSharedAccessSignature(containerName, blobname, sharedAccessPolicy);  var sasResponse = { 'sasUrl': signature.baseUrl + signature.path + '?' + qs.stringify(signature.queryString), 'photoId': blobname, 'expiry': expiryDate };    return request.respond(201, sasResponse); } By @PeterConchaR and @BrunoTerkaly

  • Anonymous
    October 24, 2014
    The comment has been removed

  • Anonymous
    October 25, 2014
    Found the issue:  I copied the text for the Header....it is misspelled WebPage shows:  X-XUMO-APPLICATION Should be: X-ZUMO-APPLICATION correction on ZUNO

  • Anonymous
    October 26, 2014
    The comment has been removed

  • Anonymous
    October 26, 2014
    In regards to my question above you can make sure that the correct version will get added to the PUT for your generated SAS by adding it to your PUT request;    beforeSend: function(xhr) {        xhr.setRequestHeader('x-ms-version','2014-02-14');    }

  • Anonymous
    November 06, 2014
    The comment has been removed

  • Anonymous
    November 06, 2014
    Hey AI How to solve error of 401 ? ???

  • Anonymous
    December 01, 2014
    The comment has been removed

  • Anonymous
    April 10, 2015
    a hint on testing if you get 500 errors like I did comment out most of the get code and just send the following as response. Then check that the info you get back is what you expected. var sasResponse = { 'accountkey': accountKey, 'accountName': accountName}; check done revert to (corrected) get code

  • Anonymous
    April 23, 2015
    Hi all, Know if they've made any changes as generated the SAS for writing Blobs; because my project was working, but now it shows me the following error when using the SAS: "Error: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature." Excuse my English, I speak Spanish.

  • Anonymous
    August 19, 2015
    Hola a todos, yo tengo problemas con el PUT, me aparece el error 403... parece que es algo de autenticacion/permisos o cosas así. AYUDA Hello to all, I have problems whit the PUT, returns me an error  '403'... i think is something about authentication or similar. Please HELP

  • Anonymous
    November 19, 2015
    Hi Bruno, Do you know what is needed to get blobService.generateSharedAccessSignature() to return an HTTPS sasURL? I've tried the code above and I only get a signature.baseUrl with HTTP. Thanks, Al