Security
Access Online Services with the Windows Runtime and OAuth
Tim KulpDownload the Code Sample
With the Windows Runtime (WinRT), you can bring the power of mashups to your next Windows Store app. Whether you’re managing data with XmlHttpRequest (XHR) or authenticating to a remote service with the WebAuthenticationBroker class, Windows Library for JavaScript (WinJS) and the Windows Runtime make mashing online services with your app easy.
Contoso Photo Finish
In this article I’m going to build a mashup called Contoso Photo Finish. It lets runners track their miles and post a picture from their runs. Many runners like to share information such as distance and location of their runs on social networks. Contoso Photo Finish lets users tell their friends about their runs with comments and pictures on Facebook. This app will connect to two different services:- Windows SkyDrive to retrieve a picture from the run
- Facebook to post the picture for their friends to view
Mashup Hurdles: Authorization and Authentication
If an app (Web or Windows Store) wants to post content to Facebook, the first hurdle to overcome is authentication. Facebook needs to know who’s connecting to it. When users try to log in to apps, they claim an identity (usually in the form of a username) and a credential (such as a password, security token, biometric device and so on) to prove they should have access to the requested identity. Authentication is the process of validating a user’s identity through a credential.After authenticating the user, the mashup has another challenge: determining what the user can do in the system. Authorization is the process of permitting or denying actions an identity is attempting to perform based on some attribute or security role membership. As an example, in Twitter my identity is not permitted to delete all the tweets of all users. I’m not authorized to perform that action because I’m not a member of the security role with permission to do that. Together, authentication and authorization (A&A) represent the question: User, who are you and what can you do?
Mashups amplify these challenges because the developer building the mashup doesn’t have access to where the identities, credentials and security roles are stored (often referred to as a credential store). So if I can’t verify who’s who and what they can do, how can I build a mashup for apps such as Facebook? OAuth to the rescue!
OAuth: Accessing Resources, Not Apps
OAuth addresses the challenge of A&A for mashups. Imagine App X wants to access content from Online Service Y. Instead of the user authenticating to App X, the user authenticates to Online Service Y because the user’s credentials are stored in Online Service Y’s credential store. The user then permits App X to access specified resources from Online Service Y for a limited time. Permission to access Online Service Y resources is returned to App X as an access token (sometimes referred to as just a “token”).In traditional Web A&A models, two participants work together to determine a user’s access: the app and the user (or the server and client). In OAuth a third participant is introduced: the resource server. Resource servers are the third parties who have a resource (such as a photo) stored on the server that a client needs to access. In Contoso Photo Finish, Facebook is a resource server. The resource that Contoso Photo Finish wants to access is the user’s status, in order to post a message.
OAuth Clients and Their Authentication Processes
There are two types of clients in OAuth, and which type to use is decided by the client’s level of trust. Confidential clients can keep their credentials secure and are meant for highly trusted environments. Examples of confidential clients are server-side Web apps where the client secret can be maintained in a controlled, secure environment. Confidential clients use the Authorization Code process to obtain a security token by providing the client secret to the resource server as a means of authenticating the client.Public clients can’t keep their credentials secure because they run in a hostile environment. Example public clients would be user-agent apps (that is, JavaScript Web apps) or native apps (such as Windows Store apps). Public clients use the “implicit grant” process to obtain a security token because the client secret can’t be stored in a secure manner within a hostile environment that’s outside the developer’s control.
Windows Store apps can be configured to use either implicit grant or authorization code processes for OAuth (you can read more about implicit grant and authorization code processes at bit.ly/yQjyQZ). It’s a security best practice to use implicit grant any time an app is out of the developer’s control.
In Figure 1 I examine an implicit grant process where the client starts the conversation by attempting to determine a user’s identity with the resource server.
Figure 1 Windows Store App Implicit Grant Conversation
- The Windows Store app needs to perform some functionality that requires access to the Facebook API.
- The user connects to the resource server through a URI that includes information about the Windows Store app trying to access the Facebook API. This is usually in the form of an app ID or client ID code. The user provides a username and password to log in to Facebook.
- Assuming successful login, Facebook provides the Windows Store app with an access token.
- The Windows Store app can now provide the user with data from the Facebook API using the access token provided by Facebook to get the user’s feed, post pictures and so on.
WebAuthenticationBroker
In Windows Store apps the WebAuthenticationBroker class (bit.ly/RW8czT) is the component that will communicate with the resource server, provide the login controls and respond to a successful login, all without needing the Windows Store app to know anything about the user’s credentials. For the sample app, Contoso Photo Finish needs to post pictures to Facebook. This requires the user to authenticate to Facebook and receive an access token.Add a new page control to the Contoso Photo Finish project called input.html. By default Visual Studio provides a lot of markup for you. Replace “<p>Content goes here.</p>” in the Main content section with the following button:
- <input type="button" id="btnAddRun" value="Add Run" />
- function btnAddRun_Click(e) {
- var facebookOauthUrl = "https://www.facebook.com/dialog/oauth";
- var facebookClientId = "[YOUR CLIENT ID]";
- var redirectUrl = "https://www.facebook.com/connect/login_success.html";
- var requestUri = Windows.Foundation.Uri(facebookOauthUrl +
- "?client_id=" + facebookClientId +
- "&redirect_uri=" + encodeURIComponent(redirectUrl) +
- "&response_type=" +
- "token&scope=read_stream,publish_actions&display=popup");
- var callbackUri = Windows.Foundation.Uri(redirectUrl);
- // Web authentication broker will go here
- }
The redirectUrl parameter determines where the app will go after the user authenticates and approves the app’s access to specified resources. In this case the redirectUrl is set to a Facebook standard that’s available to all Facebook API apps. Some services require the Windows Store app’s URI to be identified with the resource server when the app is registered. The app’s URI can be found using the Web authentication broker’s getCurrentApplicationCallbackUri method. This will return the app’s local context URI (beginning with “ms-app://”). Some resource servers don’t support ms-app:// as a valid protocol for a redirectUrl, in which case you should check for a default redirect address such as what Facebook provides.
Next, the callbackUri is defined. This is the address that informs the Web authentication broker when authentication is complete and returns control back to the Windows Store app. The broker never actually goes to this URL; it simply watches for the resource server to call for this page and then returns the callbackUri with any query string or hash parameters that were appended. In this case, the hash parameter “access_token” will provide Contoso Photo Finish the token needed to interact with the API.
The WebAuthenticationBroker class uses the authenticateAsync method to connect to and complete the authentication process with the resource server. When authenticateAsync is called, the app opens a pop-up that displays the resource server’s login screen, as shown in Figure 2. Once authentication is complete or the callbackUri is encountered, the pop-up will close.
Figure 2 Resource Server’s Login Pop-up from authenticateAsync
A key advantage to using this pop-up is that the Windows Store app never handles or needs to know the user’s credentials for the resource manager. All the app knows is the access token that’s returned by the resource server. This separation keeps the resource server’s credentials isolated from the app, which avoids the security risk of the app storing the credentials. On top of the security benefits, the developer doesn’t have to code anything to get this interface; it’s built in to the authenticateAsync method. When developers call the method, the interface comes with it.
Now, back to code. Replace the “Web authentication broker will go here” comment with the following code:
- Windows.Security.Authentication.Web.WebAuthenticationBroker.
- authenticateAsync(Windows.Security.Authentication.Web.
- WebAuthenticationOptions.none, requestUri, callbackUri)
- .done(
- function (result) {
- // Check the response status here
- },
- function (ex) {
- Log(ex);
- }
- );
- WebAuthenticationOptions: This is used to provide instructions to the Web authentication broker on how to render the authentication dialog or what data to return in the response. In the preceding example, the app uses “none” to show a common implementation that passes no options to the broker using a default setup.
- requestUri: This is the login entry point for the resource server. In this case, Contoso Photo Finish is connecting to Facebook’s OAuth service. RequestUri must be over a secure connection using the HTTPS protocol.
- callbackUri: This is the page that, when navigated to, returns control back to the Web authentication broker as described earlier. This argument is optional, but if the resource server can’t (or won’t) redirect to ms-app://, this parameter is how the app will escape the resource server’s control. For example, in the earlier code when https://www.facebook.com/connect/login_success.html is navigated to after a successful login, the Web authentication broker will take control of the app from the resource server by closing the authentication dialog and processing the success of the promise. CallbackUri doesn’t have to be in the immediate next page; it could be after a wizard or some other process that must occur on the resource server’s site. This URI will normally be the same as the redirectUrl but provides the flexibility to extend the authentication process, if necessary.
Figure 3 Working with the Result of the Authentication Process
- switch (result.responseStatus) {
- case Windows.Security.Authentication.Web.WebAuthenticationStatus.success:
- var fragment = Windows.Foundation.Uri(result.responseData).fragment;
- if (fragment.indexOf("#access_token=") != -1) {
- var token = fragment.substring(
- new String("#access_token=").length,
- fragment.indexOf("&expires_in="));
- // Add API calls here
- }
- break;
- case Windows.Security.Authentication.Web.WebAuthenticationStatus.userCancel:
- Log(window.toStaticHTML(result.responseData));
- Display("User cancelled the authentication to Facebook.");
- break;
- case Windows.Security.Authentication.Web.WebAuthenticationStatus.errorHttp:
- Log(window.toStaticHTML(result.responseData));
- Display("An error occurred while communicating with Facebook.");
- break;
- }
With the btnAddRun_Click function complete, connect it to the btnAddRun object in the WinJS.UI.Pages.define { ready } function:
- var btnAddRun = document.getElementById("btnAddRun");
- if (null != btnAddRun)
- btnAddRun.addEventListener("click", btnAddRun_Click, false);
Getting the Picture
Windows 8 provides a variety of contracts that allow apps to talk with each other, such as search, share and file picker. These contracts can turn any app into a mashup with just a few lines of code. Contoso Photo Finish is going to tap into the power of the file picker contract to find an image for the user’s run.One of the many things I love about my Windows Phone is the integration with SkyDrive. I can upload my photos instantly to storage in the cloud so the next time I break my phone (which is often), my pictures are waiting for me online. The SkyDrive app for Windows 8 provides data to the file picker, making the selection of files from my SkyDrive account as simple as selecting them from the picture library. The next part of the Contoso Photo Finish mashup will consume data from the SkyDrive app through the file picker. To do this, input.html needs some, well . . . inputs.
Replace the btnAddRun button with the code shown in Figure 4. This code includes the input fields for the user to provide content for Contoso Photo Finish. The btnSelectPhoto button will use the file picker to select which file on the system to use. Add a new function to input.js that will be the click handler for btnSelectPhoto:
- function btnSelectPhoto_Click(e) {
- var imgSelectedPhoto = document.getElementById("imgSelectedPhoto");
- var filePicker = new Windows.Storage.Pickers.FileOpenPicker();
- filePicker.fileTypeFilter.replaceAll([".jpg", ".jpeg", ".png"]);
- filePicker.suggestedStartLocation =
- Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
- filePicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
- // Pick file here
- }
Figure 4 Input Fields to Provide Content for the App
- <p>
- <label>Distance</label>
- <input type="number" min="0" max="15" id="txtDistance"
- required /> miles
- </p>
- <p>
- <label>Comment</label>
- <input type="text" min="0" max="15" id="txtComment" />
- </p>
- <p>
- <label>Photo</label>
- <input id="btnSelectPhoto" value="Select Photo" type="button" />
- <img src="" id="imgSelectedPhoto" alt="Selected Photo" />
- </p>
- <p>
- <input type="button" id="btnAddRun" value="Add Run" />
- </p>
With the options set, it’s time to select the file to use for the run. First, add these two variable declarations directly below the “use strict” statement:
- var selectedPhotoStream = null;
- var selectedPhotoFile = null;
Figure 5 Picking a File
- filePicker.pickSingleFileAsync().then(
- function (storageFile) {
- if (storageFile) {
- selectedPhotoFile = storageFile;
- selectedPhotoFile.openAsync(
- Windows.Storage.FileAccessMode.read).then(
- function (stream) {
- selectedPhotoStream = stream;
- document.getElementById("imgSelectedPhoto").src =
- URL.createObjectURL(selectedPhotoFile);
- },
- function (ex) {
- Log(ex);
- Display("An error has occurred while reading the file.");
- });
- }
- else {
- Display("File was not selected");
- }
- });
- Select the file that the app will be using via the file picker (pickSingleFileAsync).
- Open the file stream to be read (openAsync).
- Store the stream and file into variables for later use.
Finally, associate the btnSelectPhoto_Click event with the btnSelectPhoto object. Add the following code in the WinJS.UI.Pages.define { ready } function:
- var btnSelectPhoto = document.getElementById("btnSelectPhoto");
- if (null != btnSelectPhoto)
- btnSelectPhoto.addEventListener(
- "click", btnSelectPhoto_Click, false);
Getting and Posting Information via XHR
Remember when AJAX was new and exciting? XHR came on to the scene in Internet Explorer 5.5 and made Web developers start to rethink how Web apps were being made. Time passed and AJAX grew with many different libraries (such as jQuery) into an easy-to-understand and (more important) easy-to-implement solution. WinJS.xhr continues this tradition with a simple API to get and post data to online services.Return to the btnAddRun_Click function and replace the “Add API calls here” comment with the code shown in Figure 6.
Figure 6 Generating a Blob Object from selectedPhotoStream
- var fileBlob = MSApp.createBlobFromRandomAccessStream(
- selectedPhotoFile.contentType,
- selectedPhotoStream);
- var message = "I just ran " + document.getElementById(
- "txtDistance").value + " miles with PhotoFinish! " +
- document.getElementById("txtComment").value;
- var data = new FormData();
- data.append("source", fileBlob);
- data.append("filename", selectedPhotoFile.name);
- data.append("access_token", token);
- data.append("message", window.toStaticHTML(message));
- WinJS.xhr({
- type: "POST",
- url: "https://graph.facebook.com/me/photos",
- data: data,
- }).then(
- function (photoid_response) {
- ProcessResponse(photoid_response);
- },
- function (ex) {
- Display("An error occurred while posting the photo.");
- Log(ex);
- });
Next, the code uses the FormData object (new to HTML5) to create the parameters that will be sent in the HTTP POST. FormData is a key/value pair object with just one method: append. Using the append method, developers can build form fields dynamically and submit them with a POST as if the form’s submit event was called. FormData also provides the parameters as if they belonged to a form with multipart/form-data encoding. This allows developers to post any input type (including files) to the target server.
Notice in the FormData.append method call that I use toStaticHTML (bit.ly/ZRKBka) to ensure that the message content is safe for delivery. Using toStaticHTML will remove any event attributes or script content from the message variable prior to adding it to the FormData object. While I imagine Facebook is good about preventing cross-site scripting attacks (among others), as a mashup developer, I want to provide clean content to my fellow apps. The Internet is a big place, so we all need to watch out for each other.
The rest of the code block is the WinJS.xhr call. This time around, the code uses some more attributes of XHR, including:
- type: This sets the HTTP method to be used. By default type is set to GET. This code uses POST because the app is sending content to the Facebook API.
- data: This consists of parameters to pass with the POST.
WinJS.xhr is a lot like other XHR wrappers. If you’re familiar with JavaScript libraries such as jQuery, you’ll be able to pick up WinJS.xhr easily. One gotcha that you could encounter is that, unlike XHR, there’s no timeout option on the WinJS.xhr method. Setting a timeout is accomplished by wrapping the WinJS.xhr call with a WinJS.Promise.timeout method (bit.ly/Qgtx7a). By adding the following code to the beginning of the WinJS.xhr call, I set a timeout of 10 seconds to the POST:
- WinJS.Promise.timeout(1000, WinJS.xhr({ ... });
First Steps in Mashing Your App
In this article I examined authenticating, getting files and sending data with WinJS and the Windows Runtime. These foundation skills can be built upon to design Windows Store apps that are limited only by your imagination and developer keys. Take the material in this article and explore your favorite online service. Using WinJS.xhr, your Windows Store app can interact with the countless APIs available online. With the Web authentication broker, your app can connect users with their online personalities, content and communities using OAuth or OpenID. WinJS and the Windows Runtime give you all the tools to easily build an app that’s greater than the sum of its online services.
Tim Kulp leads the development team at FrontierMEDEX in Baltimore. You can find Kulp on his blog at seccode.blogspot.com or on Twitter at Twitter.com/seccode, where he talks code, security and the Baltimore foodie scene.
Thanks to the following technical experts for reviewing this article: Sunil Gottumukkala and Jeremy Viegas
<a
id="ctl00_ctl15"
href="http://ox-d.101m3.com/w/1.0/rc?cs=4f2320cbb2378&cb=INSERT_RANDOM_NUMBER_HERE"
onclick="javascript:Track('ctl00_ctl14|ctl00_ctl15',this);"><img
alt="" border="0"
src="http://ox-d.101m3.com/w/1.0/ai?auid=139281&amp;cs=4f2320cbb2378&amp;cb=INSERT_RANDOM_NUMBER_HERE"
/></a>
<a
id="ctl00_ctl16"
href="http://ox-d.101m3.com/w/1.0/rc?cs=4f2320971b57d&cb=INSERT_RANDOM_NUMBER_HERE"
onclick="javascript:Track('ctl00_ctl14|ctl00_ctl16',this);"><img
alt="" border="0"
src="http://ox-d.101m3.com/w/1.0/ai?auid=139280&amp;cs=4f2320971b57d&amp;cb=INSERT_RANDOM_NUMBER_HERE"
/></a>
MSDN Magazine Blog
MSDN Magazine June Issue Preview
Monday morning the June issue of MSDN Magazine will go live on our Web site. Here’s what you can expect to find in the magazine. Windows 8 figures pr... More...
Friday, May 31
Monday morning the June issue of MSDN Magazine will go live on our Web site. Here’s what you can expect to find in the magazine. Windows 8 figures pr... More...
Friday, May 31
MSDN Magazine May Issue Preview
Tomorrow afternoon the May issue of MSDN Magazine will go live on our Web site. Here’s what you can look forward to in the upcoming issue. Craig Shoe... More...
Tuesday, Apr 30
Tomorrow afternoon the May issue of MSDN Magazine will go live on our Web site. Here’s what you can look forward to in the upcoming issue. Craig Shoe... More...
Tuesday, Apr 30
No comments:
Post a Comment