How do you manage/enforce licensing on a fully Sharepoint hosted app?

Answered How do you manage/enforce licensing on a fully Sharepoint hosted app?

  • Sunday, November 18, 2012 4:58 PM
     
     

    Hi,

    I have currently building a Sharepoint hosted app (my first ever app!) for Sharepoint and have started investigating how I can licence it on the App store, but am getting highly confused!.

    I'm struggling to work out how I can block functionality or people using the app without a licence on Sharepoint hosted apps, which are fully client side.

    Ideally I need to be able to stop the site owner from adding new items to a list held on the app web (which powers a client app part) unless they have a valid licence. I do not want to put a check on the client web part itself, as this would mean the check is done by every user that visits the site, where as my plan is to have a one-time only cost that allows unlimited use by any number of users/sites on a tenant (Perpetual all user).

    Any one any ideas, advice, good resources to learn more about this?

    To summaries, I need advice on ways to licence / enforce licences by blocking use or functionality a fully Sharepoint hosted (client side) app.

    Thanks!

    Martin

     

All Replies

  • Monday, November 19, 2012 6:36 PM
    Moderator
     
     

    Hello Arktic,

    The general process for licensing your apps is described in this post. 

    http://blogs.msdn.com/b/officeapps/archive/2012/11/09/licensing-your-apps-for-sharepoint.aspx

    Specifically for SharePoint hosted apps we are working on a sample (should be ready in a day or 2) but the process is very similar, you retrieve*, verify and then use a license; I bet you can derive most of it from the sample in the post above.

    Be aware though that for purely client side apps there are inherent limitations with the technology because all code is ultimately interpreted by the browser; obfuscating your code usually helps.  

    I'll keep this thread updated once we have the full sample.

    *The retrieval portion can be done using our JS OM or REST. For the latter the syntax is similar to this:

    http://<appweburl>/_api/SP.Utilities.Utility.GetAppLicenseInformation(guid'<productId>')


  • Monday, November 19, 2012 7:02 PM
     
     

    Thanks Humberto! I'll have a play about and see if I can get it working, i was thinking about obfuscating the code to make it a bit more secure, but was worried that this might impact it getting accepted to the app store as that part of code would be hard to review?

    Also looking forward to seeing the sample, so really appreciate your offer to post back in thread once its completed :)


  • Monday, November 19, 2012 7:55 PM
    Moderator
     
     

    Obfuscating your code shouldn't affect app validation for the store.  There are multiple valid reasons (performance, security/etc.) that require minification and/or obfuscation of code.

    I'll post the sample once we have it ready.

  • Wednesday, November 21, 2012 12:33 AM
    Moderator
     
     Answered Has Code

    Ok so here is a rough draft of the sample code (put this in App.js to see how it works).  It still needs polish but I wanted to post this right away just in case. Whenever I have a polished version I'll update the thread but this should get you going.

    To test your code, you can use the tools included in this post to import a test license:

    http://blogs.msdn.com/b/officeapps/archive/2012/11/09/licensing-your-apps-for-sharepoint.aspx

    var context;
    var licenseCollection;
    var topLicense;
    var encodedTopLicense;
    var verifiedLicense;
    var response;
    
    // This code runs when the DOM is ready and creates a context object which is needed to use the SharePoint object model
    $(document).ready(function () {
        context = SP.ClientContext.get_current();
    
        //Retrieve license from SharePoint; change this productId with the one for your app; you can get it from AppManifest.xml
        licenseCollection = SP.Utilities.Utility.getAppLicenseInformation(context, '{b7224c84-b20c-45b0-88ab-a9f897f7aa4f}');
        context.executeQueryAsync(onRetrieveLicenseFromSPSuccess, onRetrieveLicenseFromSPFailure);
        
    });
    
    
    //Retrieval call succeded (doesn't mean there is a license, look at the contents to see if there is one)
    function onRetrieveLicenseFromSPSuccess() {
    
        if (licenseCollection.get_count() > 0) {
            topLicense = licenseCollection.get_item(0).get_rawXMLLicenseToken();
    
            //debug
            alert("License retrieved from SharePoint: \n" + topLicense);
    
            //encode license; required to call the verification service since it will be sent on the URL 
            encodedTopLicense = encodeURIComponent(topLicense);
    
            //debug, display the encoded license 
            alert("License ready to be verified:\n" + encodedTopLicense);
        }
        else {
            alert("The user doesn't have a license");
        }
    
    
        //Call verification service via the WebProxy; this ensures the validity of the license in case SharePoint was tampered with
        var request = new SP.WebRequestInfo();
        //We use the REST flavor of the verification service
        request.set_url("https://verificationservice.officeapps.live.com/ova/verificationagent.svc/rest/verify?token=" + encodedTopLicense);
        request.set_method("GET");
        response = SP.WebProxy.invoke(context, request);
        // Set the event handlers and invoke the request
        context.executeQueryAsync(onVerificationCallSuccess, onVerificationCallFailure);
    
    }
    
    // This function is executed if the above call fails
    function onRetrieveLicenseFromSPFailure(sender, args) {
        alert('Failed to retrieve license:' + args.get_message());
    }
    
    function onVerificationCallSuccess() {
        var stories;
        var storiesHTML;
        var xmlDOM;
    
        //It is highly recommended to cache (e.g. cookies) the response
        //If you are concerned about tampering only re-retrieve and re-validate the license for sensitive operations in your App. 
        var verificationResponse= response.get_body();
    
    
        //Debug, display the raw response
        alert("Verification Service Response" + verificationResponse);
    
        xmlDoc = $.parseXML(verificationResponse);
        $xml = $(xmlDoc);
        licenseType = $xml.find("EntitlementType").text();
        licenseIsValid = $xml.find("IsValid").text();
        licenseIsTest = $xml.find("IsTest").text();
    
        //DO SOMETHING NOW THAT YOU KNOW WHAT TYPE OF LICENSE THE USER HAS
        switch (licenseType)
        {
            case "Free":
                alert("Free app");
                break;
            case "Paid":
                alert("Paid app");
                break;
            case "Trial":
                alert("Trial app");
                //You can then look at the expiration date on the response
                break;
        }
        
       
    }
    
    function onVerificationCallFailure() {
        alert('Failed to call verification service via WebProxy:' + args.get_message());
    }
    
    
    
    


    Program Manager, Office Developer Platform.


  • Wednesday, November 21, 2012 12:30 PM
     
     
    You sir, are a legend! thanks, this example is really helpful :)
  • Wednesday, November 28, 2012 9:27 PM
     
     
    I think it's a great concept to check licensing in client side javascript code - nobody will ever be able to steal your code and remove your license check in 60 seconds.
  • Friday, December 07, 2012 2:31 PM
    Answerer
     
     
    It's a risk, but then again I think are people really going to go through the effort to remove my license check for an app that costs a few hundred dollars at most?  Maybe, but we're also talking about business people using SharePoint and not kids trying to steal the latest game.

    Corey Roth - SharePoint Server MVP blog: www.dotnetmafia.com twitter: @coreyroth