Tuesday, 10 September 2019

How does it affect my tenant? Questions to ask for Office 365/SharePoint solutions

I’m doing some Office 365 architecture work at the moment to ensure our clients have a clear view of our solutions and how they work. Any organisation working with a partner or deploying products based on Office 365 needs to ask “how does it affect my tenant?” – but of course, that’s just the high-level question. Underneath are a whole series of security, compliance, operational, cost and other governance considerations that should be explored for robust long-term successful use of Office 365. However, I find that many organisations don’t yet know how to ask the right questions or dig into the right areas – and this can lead to risks of compliance issues, data leakage, impact to organisational productivity or any number of other problems down the line.

So, I thought it would be good to share a starter checklist of topics and questions to ask related to solutions which extend Office 365 in some way. The focus is on SharePoint-based customisations, and it’s not a comprehensive list – you could certainly broaden the scope, or go deeper in specific areas by asking more questions. But hopefully my list gives a sense of the type of questions you should ask before accepting a solution into your environment, or on the other side, the kind of thing you should be providing as a trustworthy vendor/partner/internal development team in your documentation.

For larger enterprises, my work often involves more than documentation. Commonly, I’m walking various technical teams and service owners through the low-level detail of our solution, and each needs to grant approval before our solution can pass. I’m currently working with one of the world’s largest companies, and we need around 10-12 teams to approve their respective bits, and then to also pass a “unity review” which considers the overall picture. I’m using a combination of PowerPoint and live demos on the conference calls with the respective teams, and it’s all about socialising the concepts and ensuring the low-level detail is covered and all questions are answered. I do think the onus is on the implementation team to proactively “push” the information – as noted earlier, in-house teams don’t always know the right questions to ask. If you have your client’s best interests at heart though, you’ll want them to be well-informed.

My suggested checklist

What does the overall architecture look like?

  • Which Office 365 services are used?
  • What does the architecture diagram(s) of your solution look like?

User data/user profiles

  • Are any custom fields added to AAD profiles?
  • Are any custom fields added to SPO profiles?
  • How does data get into the fields? Is there a sync solution, or do users edit their values through native Office 365 or custom interfaces?

Security

  • Are any changes to the “Custom script” settings proposed (i.e. is there any ad-hoc JavaScript running outside of modern pages and the SPFx security model)? HINT – you really want both of these set to “prevent” if possible:



  • What SPFx permissions are required? (as shown on the Web API permissions page)?



  • Are any AAD app registrations created (related to use of the Microsoft Graph API)?





  • What 3rd party libraries are used by the solution? Can you show us a current npm audit report?
  • What certificates are used by the solution?
    • How are they managed and where are they deployed to?
    • What is the expiry date of any certificates and how is rollover handled?
  • If remote code elements are deployed (Functions or other web APIs), what authentication model is used?
  • Are any code elements or artifacts *not* hosted in our tenants/subscriptions? If so, what purpose do they serve? How can we be sure our data isn’t passed to them?

Taxonomy

  • What term groups and term sets are provisioned?
  • How are they used/what purpose do they serve?
  • Are they open or closed term sets?
  • How are they identified? Will my users confuse them for something else?
  • Are they a duplicate of something already in place?

Search configuration

  • What new managed properties are provisioned?
  • More importantly, are any mappings of existing out-of-the-box properties provisioned?
    • How can I be sure any use of RefinableStringXX, RefinableDateXX, RefinableIntXX and so on don’t clash with existing mappings in use in my tenant?
  • What result sources are provisioned?
  • What other search configuration is provisioned?

Teams

  • What aspects of the Teams dev platform are used (e.g. tabs, connectors, bots, messaging extensions)?
  • What permissions/device permissions are used?
  • What remote domains are used? What for?

Office Add-ins

  • If Office add-ins are used, what are their permission requirements (e.g. “ReadWriteMailbox”)?
  • Is Centralized Deployment used to deploy the add-ins? If not, why not?
  • Which Office applications do the add-ins surface in?

Azure

  • What is deployed to Azure? Is it just PAAS elements or are there any IAAS elements?
  • If Azure Functions are used, are they on the Consumption Plan or App Service Plan?
  • What are the forecast costs? What could vary this?

SharePoint content (see note below)

  • What site types are used (e.g. communication sites, hub sites, team sites etc.)?
  • Are any classic SharePoint elements used (e.g. classic publishing sites)

SPFx

  • What SPFx packages are used?
  • Which are deployed tenant-wide, and which are per site collection?
  • [Also see Security section for considerations on SPFx security]

Notice that the list does not focus too much on SharePoint content. If the solution gets deployed into an existing SharePoint site collection (or several), you might ask questions about the content types and site columns and so on which are provisioned. In most cases however, what goes on within individual SharePoint sites is a lower-level concern where the risks are much lower (at least in SharePoint Online).

Summary

Successful use of Office 365 in the enterprise relies on balancing productivity and agility with security and governance, and part of this involves knowing exactly what’s in your tenant and how it works.

Just because you no longer own and manage the physical servers doesn’t mean that a breach isn’t possible or your data cannot be stolen. Office 365 is designed with customisation in mind (at least, it is these days) and there are many many security features which are designed to ensure that the platform can be extended in safe, governable ways. However, you do need to make sure that you use them - and I think it’s fair to say that some older vendor/product Office 365 solutions that haven’t been updated do not.

No doubt there are some useful products which can help with solution governance in this way, but I’m not sure any of them cover all of the aspects listed here. Hopefully this checklist can help!

Thursday, 18 July 2019

Office 365 dev - tips for building a custom SPFx form

One project I worked on recently involved building a custom form as an SPFx web part – and in general I think this is a great option for “high-end” forms which need to have quite specific behaviour and/or look and feel. Also, the ability to designate the page as an SPFx application page means some of the unnecessary page furniture is removed, which is helpful. When thinking about forms in Office 365, I see a spectrum of options which looks something like (in order of increasing complexity/effort):

  1. Out-of-the-box SharePoint list form 
  2. PowerApps customised SharePoint list form 
  3. Canvas PowerApp, embedded in a SharePoint page with the PowerApps web part 
  4. Custom-developed form with SPFx and React 
So, we’re talking about the last option here.

The good news is that for an adequately-skilled SPFx developer, building one of these forms can be pretty quick - there are some very powerful building blocks to help. I see the overall recipe as something like:
By combining use of these ingredients with some extra steps to help users get to your form (see later sections on this), you can get to a rich solution with less effort than you might think.

Form controls used with SPFx, and dealing with data

Thinking about the list of ingredients above, you'll find you can go a long way by bringing in those controls and integrating them with your data. I think the following arrangement might be common:

Requirement

Source

Standard textboxes, buttons etc. Office UI Fabric React
Dropdowns, including advanced formatting/behaviour Office UI Fabric React
Taxonomy picker PnP React taxonomy picker
People picker PnP React people picker
File upload control (stored as list item attachments) PnP React file upload control
File upload control (stored in another way) Other 3rd party control (you handle the upload to SharePoint)

Most likely you'll need to allow existing items to be edited with your form, as well as new items to be created. PnPJS is perfect for simplifying the operations to fetch an existing item (typically from an item ID passed to the page), and also saving back to SharePoint. In your SPFx web part, you'll use React state as the go-between in the middle of your controls on the front-end, and your service code for the data layer.

In the end, my form looked something like this (shown here zoomed-out). You might notice a series of buttons at the top - these surface functionality such as "Save as draft", and although I think use of something like Office UI Fabric's CommandBar or ContextualMenu would be nice, the client preferred straight-forward buttons in this case. Otherwise it's just use of the controls described above:


Providing the edit item experience


Assuming your custom form stores items in a SharePoint list, you'll probably want to take some steps to integrate the default list experience with your form. A good example is ensuring that when a user edits an item, they are taken to your form rather than the out-of-the-box SharePoint list edit form. This can be accomplished by adding a column to your list with some JSON formatting defined to provide the link. Simply take the URL for your page (i.e. a page that you created and added your web part to), and use it in the JSON for the link. You should end up with something like this:

I used JSON like this:

Notice that I'm passing the current list item ID to my form. Within my SPFx web part, I have code which is looking for a value being passed in the 'itemId' URL parameter - if one is found, as described above I use PnPJS to:
  • Fetch data for this item
  • Set React state with these values, so that my form controls get set to these values
So that takes care of the edit experience.

Providing the 'new item' experience or customising new/edit/disp forms in modern lists


In my case, the new item experience can be provided simply by a big visual representation on the home page. Regular end-users do not use the list, and won't be pressing the 'new' button. In this case, things are simple. Chatting to colleagues (thanks Leo!), it *is* possible to override the new/edit/disp forms of a modern list, but currently there are issues if a modern page is the target and you want to pass any parameters in the URL (e.g. the item ID for the edit experience) - apparently something breaks completely and your form is unlikely to load. One approach which can work is to create a classic page, set the new/edit/disp form URLs of your list accordingly, and add JavaScript on the classic page to redirect on to the modern page hosting your SPFx form. You may need to hash/further encode any ID you're passing, and consider adding CSS to hide some page elements in case the user briefly sees them during the redirect process. That's about as good as it gets in summer 2019 apparently, and there's a UserVoice entry Allow us to develop custom modern forms with custom edit experience to request better integration - the good news is the status of this has recently changed to "Thinking about it". So, hopefully this story will be improved soon for those needing tight integration between your custom form and the out-of-the-box list UI.

Setting the page to be an SPFx app page


Once you've developed your web part, you'll want to make sure it works well on the page - and typically you'll want to remove some of the "page furniture", so that your form is the focus and there are fewer distractions. On a modern page, you can do certain things like set the title area to the "Plain" layout - this will reduce the header area, but if your form has some kind of header/title you'll still get duplication between this and the page title.

And what about the problem that a page author could accidentally edit the page and remove the web part?

Both of these problems can be solved by converting the page to be an SPFx app page. On one of these, only a single web part can be used, it's properties cannot be edited and the title area is removed. The two images below compare my form before being converted to an app page (left) and afterwards (right):

As you can see, the title area is removed. Also, if I flick the page into edit mode, the web part cannot be removed and the only options I see relate to the page title:

So, less chance of an authoring 'accident' happening to your form now. If the page wasn't originally created as an app page, converting can be done by PowerShell or even by some quick JavaScript in the browser console as a one-off. See here for more details - https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/single-part-app-pages. Of course, you could also remove the left navigation if you like too.

Using the PnP Taxonomy Picker control in such a form


One area I wanted to talk about here was a quirk in the PnP Taxonomy Picker control (a common control for these forms). Like many others in this toolkit, the control itself is excellent and would be a significant task on it’s own if you had to write it. Let’s all buy Elio a(nother) beer next time we see him 😉

The taxonomy picker is easy to add to your web part, and it takes care of populating itself with terms from a term set that you provide (by name or ID). A typical declaration looks something like this:

<TaxonomyPicker allowMultipleSelections={false} termsetNameOrID="b2a79b4b-9d64-46d9-8a94-38f8809f8d12"
  panelTitle="Select Region"
  label=""
  initialValues={this.state.selectedRegion}
  context={this.props.context}
  onChange={this._onRegionTaxPickerChange}
  isTermSetSelectable={false} />

That would give something on your page like this:

A couple of other notes would be:
  • initialValues – use this property to set the value of the control. So if your form is being used to edit an existing list item, fetch the value from data and set this property – since I’m using React, this simply comes from a value in my web part state
  • onChange – what should happen when a term is selected. In React, you’d usually store the value in state at this point, ready for later insert/update to SharePoint
So far, so straightforward. However, something to be aware of is that the onChange() method provides the item in the form of an IPickerTerm object – something provided by the PnP code. However, such an object cannot be passed to SharePoint using PnPJS or REST, since the REST API expects a different format. IPickerTerm has the following properties:
  • name
  • path
  • key
  • termSet
  • termSetName
However, PnPJS or the SharePoint REST API expect an object with the following properties (this is for a single-value taxonomy field):
  • TermGuid
  • Label
  • WssId
Sidenote - things are a bit more complex if your field stores multiple values. Alex Terentiev has an article on this that may help you out.

So, you’ll need to some mapping between the two object types if you’re reading/writing data to SharePoint from the PnP taxonomy control (including setting the selected value of the control to the current value stored in a SharePoint list item).

Some important things to know here are:
  • A value of -1 can be used for the WssId value – you don’t need to do anything more, SharePoint will sort this out
  • The TermGuid property maps to the IPickerTerm.key property
  • The Label property maps to the IPickerTerm.name property
With that in mind, we just need some code to map between the two object types - I found that having two methods such as the following is needed (to convert in each direction):

Summary


Hopefully this post has been a useful round-up of considerations when building custom SPFx forms. I think this approach works great for more complex forms, and the building blocks listed here really do help reduce the amount of code required. Setting the page to be an app page to eliminate unnecessary page furniture helps, as does integrating with the SharePoint list UI for the new/edit/display experience. In addition to Office UI Fabric, the PnP React controls are all extremely useful in SPFx forms and the TaxonomyPicker is no exception. If you use that one, you'll probably find you need some code like my sample above to help you map between the format used by the control and that used by the SharePoint REST API or PnPJS, but that's not too complex. Happy coding!

Wednesday, 19 June 2019

Office 365 dev tips – working effectively with the Microsoft Graph and other APIs

I’ve been speaking at various conferences recently about key skills for extending Office 365 – things that an effective architect or developer needs to have in the toolbox these days. Clearly the ability to work with the Microsoft Graph needs to be high on this list, given that it is after all, “the API for Office 365”. It’s great to have one (mainly!) consistent way to work with Teams, SharePoint, mail, calendar, Planner, OneDrive files and many other functions too, but between the various authentication options and coding styles, there’s quite a bit to know.

One thing I find is that developers are perhaps not effective enough with the Graph yet – partly because some things have changed recently, and partly because some devs are only now coming to the Graph from use of say, the SharePoint REST/CSOM APIs and other service-specific APIs.

So my key messages here are:

  • The Postman collections provided by Microsoft can help answer your questions about the Graph and integrate calls into your code
  • The SDKs help more than you’d expect in your code – having types in TypeScript being one example
Why are these things important?

Tip 1 - Using Postman collections instead of Graph Explorer


Graph Explorer (GE) is great for developers to start seeing some calls that can be made to the Graph and what kind of data comes back. If you’re new to the Graph, check it out at https://developer.microsoft.com/en-us/graph/graph-explorer. However, for intermediate and advanced developers, I recommend using Postman over Graph Explorer. Here’s why:

Downsides of Graph Explorer
One drawback of GE is that even though you can sign-in with your account and therefore work with your own Office 365 tenant, this is still not the same thing that your code will be doing. An Azure AD app registration is always needed for code to call the Graph, and GE does NOT use your app registration – meaning different permissions are used. So, it’s common to run into issues when you move from Graph Explorer to your code, usually related to not having correct permission scopes allowed on the app registration. Using Postman allows you to use your app reg, so it’s exactly the same as your code.

Something that makes Postman very powerful with the Graph is that Microsoft have released Postman collections for all the current Graph methods – including those in beta. You can import these into Postman and you’ll then see an item for every method, broken into two folders for app-only calls and on-behalf-of-user calls:

This is great for discoverability! Now, every time I wonder if the Graph allows me to get something, instead of clicking through pages of documentation I just come here and start expanding folders:
I get to see all of the Graph workloads and what data can be retrieved very quickly indeed. The process of getting started with Postman and the Graph collections is a little bit involved - it's outlined on the Github repo where you can obtain Microsoft's Postman Graph collections, but I think it can be helpful to watch someone go through the process, so I made a video with some captions:


The process starts by obtaining the details of an AAD app registration which I'll use, so you should create one (with the appropriate permission scopes defined) if you don't have one already. Overall, the process is:
  • Import the collections
  • Configure various Postman variables
  • Obtain access tokens for app-only and "on behalf of user" calls, and store in other Postman variables
  • Enjoy your new quick access to the Graph! You can start executing the calls and seeing data coming back at this point

It's fairly straightforward to integrate the call into your code, and you won't have any security/permission issues because you've already tested the same thing your code will do.

UPDATE - actually, I realise now that Jeremy also has a video. See https://www.youtube.com/watch?v=4tg-OBdv_8o for that one.

So that's great - we can now see all the URL endpoints in the Graph, what data they expect and what data they return. But how do we ensure we're working effectively with the Graph once we're in code?

Tip 2 - ensure you're using TypeScript types


For many of us, the place that we'll be coding against the Graph will be SPFx or other TypeScript code - perhaps even an Azure Function based on node.js. The key thing to avoid here is use of “any” in TypeScript – we can do better than that, whether it’s another 3rd party API or the Graph itself. It’s common for APIs to return fairly complex JSON structures, and we can avoid lots of coding errors by ensuring we get type-checking through the use of types (interfaces or classes) representing the data. Additionally, having auto-complete against these data structures makes the coding process much faster and more accurate.

Using the Graph in TypeScript

When using the Graph in SPFx, the first thing to note is that your project will not have the Graph types added automatically (e.g. when the Yeoman generator creates the files) – you have to install a separate npm package. To do this, run one of the following:
  • npm install @microsoft/microsoft-graph-types --save-dev
  • npm install @microsoft/microsoft-graph-types-beta --save-dev
Yes, Microsoft kindly provide types even if you’re working the beta Graph endpoints. For most production scenarios, you’ll be using the first option (and staying to release endpoints) though. Once you have the types installed, you can import them to your SPFx classes with:

import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';

It’s a good idea to only import specific entities that you’re actually using rather than *, but that needs some digging (to find the module name). You’ll be rewarded with a smaller bundle size however. Either way, once you’ve got the types imported you can start using them in your code – this changes things from having no zero support at all:
..to having full auto-complete as you type:
Hooray! Things are now much easier.

Wherever possible, don't settle for coding without this kind of support! But what if you're working with an API that isn't the Graph?

Using 3rd party APIs in TypeScript

The first thing to do in this case is establish if the vendor supplies TypeScript types (usually in the form of a npm package or similar). If so, just install that and you should get the support. If not, I like to use Postman to obtain the JSON returned and then use a Visual Studio Code extension such as QuickType to auto-generate types for me, based on that JSON. So you’d make the call to the API in Postman, and then copy the returned JSON to your clipboard.

In the example below, I'm using the Here Maps API. I set up the call in Postman by pasting in the URL endpoint to use, and setting up any authentication. I hit the send button, and then copy the returned JSON (in the lower pane) to my clipboard):
In Visual Studio code, I create a file to hold the interface types from the API, and then find the QuickType "paste JSON as code" option in my command palette:
I supply the name of the top-level type:
..and then QuickType generates the type structure which maps to the JSON. I might want to rename some of the types, but essentially I get interfaces for everything in the structure:

So that's great - this saves me a lot of cross-referencing and typing, and I can now use these interfaces in my calling code and get type-checking and auto-complete.

Summary


Whether it's the Graph or a 3rd party API, you should always code against defined TypeScript interfaces where possible. For the Graph, you should use Microsoft's supplied types by installing their 'microsoft-graph-types' npm package. For a 3rd party API, if no types are supplied then you can generate your own easily with help from something like QuickType.

Whatever you're doing, Postman is a hugely useful tool. In terms of the Graph, it's use gets you around the problem of Graph Explorer not executing with the same permissions as your code, and so is as valuable there as it is with 3rd party APIs.

Happy coding!

Wednesday, 12 June 2019

Quick tip - filter SharePoint items by date in Flow

A quick post on working with dates in Microsoft Flow, because I know I'll need this again and I didn't immediately find something on this when I looked.

When using Flow actions such as "SharePoint Get Items", it's frequently the case that you want to filter items by a date/time field. Often you want to grab items older (or newer) than a certain timestamp - perhaps to delete/archive/take other action on them.

The easiest way is to use the getPastTime function, ensuring you format it in the right way. A clause such as the following can be used in the "Filter Query" property of "Get items":

formatDateTime(getPastTime(1, 'Month'), 'yyyy-MM-dd')

Note that this format is designed to work with a date/time field in SharePoint which is configured for "date only" format:

For dates which include the time, you'll probably need to use formatDateTime with an alternative format (sorry, I didn't test that).

Notes on using getPastTime and similar functions


The signature of the "getPastTime" method is:

getPastTime(<interval>, <timeunit>, <format>?)

The list of possible values for "timeUnit" include:

"Second", "Minute", "Hour", "Day", "Week", "Month", "Year"

As you might expect, there's also a corresponding function called getFutureTime(). To use one of them in the "Get items" action, provide a filter query in OData format which uses the internal name of your date field - something like:

MyDateFieldInternalName lt formatDateTime(getPastTime(1, 'Month'), 'yyyy-MM-dd')

That would filter items to only those older than one month for example. In the Flow designer, this should look like this:



Hope that's useful. May all your Flows execute on time and without error!

Wednesday, 8 May 2019

Speaking at the European Collaboration Summit 2019 and SharePoint Saturday London!


In a few short weeks I'll be speaking at the European Collaboration Summit in Germany. This is a fantastic event with stellar speakers and quite a few folks from Microsoft. The event team go out of their way to make the show a fantastic learning event for attendees, and I highly encourage Office 365/SharePoint/Azure folks based in Europe to try and get there. Topics covered in depth will include Teams, Azure, SharePoint, Yammer and more - covered from business and technical viewpoints.

My session is:

Top Office 365 Development techniques to master - the hitlist


Things move fast in Office 365 development, and as Microsoft evolve the platform and APIs, new techniques and approaches become available all the time. As the head of a talented dev team, I regularly update my list of techniques that I believe are essential to have good capability building Office 365 solutions. Between SPFx, the Graph, Teams development, coding in Azure Functions and building solutions in PowerApps and Flow, let's walk through some high-value scenarios in mid-2019 that should be in every experienced coder's toolbox, with demos and code sample for each. This session will help you close any skills gaps, and should be a great conversation with some bright minds in the room. 

Some of the techniques I consider to be on the list include:
  • Working effectively with the Microsoft Graph from Postman (and coding against the JSON returned)
  • Calling a back-end API (e.g. an Azure Function) securely from SharePoint, with SPFx isolated web parts and AAD auth
  • Templating SharePoint sites effectively with Site Designs and PnP templates
  • Rich PowerApps which can capture images or signatures 
Of course, there are a *million and one* scenarios you could consider for such a list! However, I think any developer with those in the toolbox is quite well-equipped across some important building blocks. I'll also talk about some other techniques such as templating Teams, calling APIs from Flow, offline support in PowerApps and more.

Overall, I think it's important to be quite well-rounded these days - if you're purely a code-oriented developer with little knowledge of PowerApps and Flow, then frankly you (and your clients) are missing out. As ever, being able to select the right architecture and solution approach is vital, and knowing how the technologies fit together (in some detail) is important here.

More details on the European Collaboration Summit 2019:
ECS 2019 is being held in Wiesbaden, Germany (near Frankfurt) between May 27-29. Ticket prices are *extremely* reasonable for an event of this level! Read more at: www.collabsummit.eu

Also available in London!


If you can't make it to ECS, another great event where I'm giving the same talk is SharePoint Saturday London 2019! This is my home turf, and just like past occasions, there are lots of top-ranked speakers from around the world presenting.

For more details on SharePoint Saturday London:

The event is being held on June 1st in central London - and it's free of course! Read more at www.spsevents.org/city/London/home

Hope to see you at one of the events!

Tuesday, 23 April 2019

SPFx isolated web parts – the right way to connect to your back-end API

It’s now possible for SharePoint/Office 365 developers to create *isolated* web parts, thanks to the recent release of SPFx 1.8. If your web part needs permission to talk to a back-end API or the Graph, you should strongly consider making your web part isolated. Simply having the Azure Function or other API secured with AAD authentication isn’t enough. In this post, I’ll talk through some of the details of an SPFx web part which can perform a privileged operation in your Office 365 environment (creating a Microsoft Team from a template in this case) – and therefore is something we should take steps to secure. Specifically, we want to protect the access token which is used behind the scenes, and ensure no other web parts can “piggy-back” onto the permissions we are using. Without isolated web parts:

  • Any other code on the page (perhaps from a 3rd party supplier) can sniff the access token, and potentially use it maliciously, depending on what permissions it has
  • Any standard SPFx web part can use the permissions from any other – meaning it’s a “highest common denominator” situation, where all standard SPFx web parts in the environment have the same permissions i.e. the highest that have ever been granted
These can be very valid security concerns – you’d want to be very sure about which permission levels have been granted to SPFx otherwise, and exactly what code you have in your environment. Isolated web parts can often be part of the answer in ensuring your Office 365 environment is not inadvertently insecure.

But how exactly do isolated web parts help?

Isolated web parts explainer

Web parts from an isolated SPFx package run on a unique domain, hosted within an iFrame - the permissions granted apply only to code hosted on that domain. Since regular SPFx web parts run on your *.sharepoint.com domain, the granted permissions do not apply there. And since any other SPFx isolated web parts run on a different unique domain, they don't apply there either. Essentially, the shared application principal for SPFx is not used – instead, an AAD app registration dedicated to this SPFx solution is created and used for authentication. Note this scope isn’t the individual web part, but the containing solution package. This is fine however - if you have an untrusted source contributing code to the very same solution/codebase, then you probably have bigger security and governance challenges to deal with quite frankly.

So when an isolated web part is added to your pages, you’ll see the containing iFrame – notice the source:

The source is a dynamically-created domain to represent this solution package – similar to how the old “SharePoint-hosted apps” model used to provide a separate domain for code-hosting for those who remember that. In the AD portal, you’ll also see the app registration that has been created on your behalf for this SPFx solution package:


It has a bunch of redirect URIs automatically configured, to support SPFx calling from the domain your iFramed web part code will use:

The combination of the unique domain/iFrame and dedicated AAD app registration gets around the previous trade-offs that came with SPFx and AAD integration, where a permission request for a given security scope (say, Group.ReadWrite.All – which would allow new Office 365 Groups or Microsoft Teams to be created or existing ones updated, as well as a bunch of other operations) would apply to *all* SPFx web parts and extensions in the tenant, not just the one that needed it.

So, you can see that any web part that performs a highly-privileged operation (e.g. creating a Team in my case, to continue that example) really should be isolated – especially if there’s a chance that your tenant could host web parts from different teams or providers. In this way. I am guaranteed that the only thing that can call my API is the web part(s) that are intended to - no other code in my Office 365 tenant will be able to.

Of course, without the iFrame that comes with isolated web parts, the auth token is right there in the page to be sniffed by anything else on the page:

So, isolated web parts are a good thing.

Before we talk about what configuration is needed where, let’s consider some user interface things for a second.

UI considerations with isolated web parts

Imagine you want to use some Office UI Fabric (OUIF) components within an isolated web part. That’s fine, but you need to consider the fact that your content is displayed within an iFrame which has certain dimensions – and certain UI components don’t play well with that. Let’s say we want to use a Dialog from OUIF React. In the example below, I have a button to pop the dialog, and for illustration I’ve also added a black border to my web part so you can see how big it is in the page:


When the button is pressed we get this:


Whoah – doesn’t look right. Of course, that’s because the Dialog is appearing within the iFrame only. If I extend the web part dimensions, the Dialog can be fully shown – effectively I almost need to “reserve” space on the page for any elements which are initially not visible:


And it’s the same with a Fabric React Panel. With a small web part, it’s not clear what’s going on at all:


But in this case, even using a taller web part doesn’t really help – you can see a bit more of the Panel, but since a Panel uses the full height of the screen you still won't see it all:


So, perhaps isolated web parts work better when the content is right there in the page, rather than with any elements that appear on user interaction. You’ll need to design the UI of isolated web parts accordingly.

Creating an isolated web part

Isolated web parts are created by specifying “isDomainIsolated” is true in the package-solution.json file in your SPFx project. This tells SPFx that all web parts in this package should be isolated from other web parts (but not from each other – you’d need separate projects for that):


You can specify this at any time, but the Yeoman Generator helps you out by asking this question when you’re creating a new SPFx project. A “yes” to the following question will result in the config above:


Key elements

I was slightly confused as what values I need in certain config values at first. Knowing that a new AAD app registration is created for me in AAD, is it THAT client ID that I need to use in my code? Or is it the client ID of the AAD app registration that my Azure Function uses internally to actually make calls against the Graph (since the pattern in my case is SPFx web part -> Azure Function -> Graph calls)?

The documentation essentially says that, “everything is done as normal”, but I was still a bit confused.

Here’s a summary of what you need to do:
  • Create your Azure Function app and secure with AAD authentication
  • Create your SPFx project and answer “yes” to the question about isolated web parts (or add “isDomainIsolated” : true in your existing package-solution.json file)
  • Add an appropriate “webApiPemissionRequests” section to your package-solution.json file (more on this next)
  • Write code in your SPFx web part using AadHttpClientFactory to perform the authentication against your API
  • Deploy the package to the app catalog (even if only debugging at this stage)
  • Approve the permission requests on the API management page in tenant administration
Let’s go into a bit more detail:
In package-solution.json
Add an entry into the “webApiPemissionRequests” section which corresponds to your server-side API/Function, with a scope of “user_impersonation”. IMPORTANT:
  • The AAD app reg/API to list is the one for your function app, NOT:
    • The dynamically-created AAD app for your isolated web part (e.g. “cob-teamcreatorwp” in my case)
    • Some other AAD app you have which you may be using inside your Function, but has no bearing on communication from the web part to the API (e.g. “COB Graph Access” in my case)
Your package-solution.json should therefore look something like this:

In your SPFx code
In your code, you’ll have something like this – notice that the Client ID to pass to AadHttpClientFactory is (again) the one for the Function app:

Approving the permissions:
The solution package then needs to be deployed to your tenant, and consent granted.
  • Add the package to the app catalog – notice the message that further action is needed on the Permissions Management Page, with a note about the specific permission to approve:

  • If you then head to that page, you’ll see the permission to approve:  

  • Hit the approve button if you’re satisfied with the permissions being granted. In this case, the permission will be scoped only to web parts within this SPFx package – other web parts in the tenant will not be able to use it.
Reverting back from using an isolated web part
Occasionally you might need to revert a web part back to a standard web part after it was initially defined as an isolated web part - I found myself having to do this one time after writing this article. Note that in addition to changing "isDomainIsolated" to "false" in package-solution.json and repackaging, you'll need to *remove* the SPFx solution completely from the App Catalog and then upload the new version - a simple version upgrade is not sufficient to switch. Hope that helps someone!

Summary

There are lots of ways you can stay assured of what custom code can do in your Office 365/SharePoint Online environment, but isolated web parts can be really helpful in minimising the potential for exploits. Without them, maybe something else could call your back-end API without you realizing it. Notably, Microsoft still have some work to do in lowering the code permissions required for certain operations (e.g. posting a message in a Teams channel requires Group.ReadWrite.All, and certain Planner actions are similar), but hopefully that will come soon.

It’s also worth considering exactly what permissions are required where. If you make calls to the Graph via a back-end API, then maybe SPFx only needs permissions to call *your* API, and the separate AAD app registration used by your back-end has the permissions to take real action. Obviously that can reduce the surface area considerably.

Either way, isolated web parts can play an important role in balancing security with functionality in Office 365. I'll publish the full source code for my Teams Creator web part and Azure Function API in a future article.

Further reading:
https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/isolated-web-parts

Friday, 8 March 2019

Create Microsoft Teams from a template

One thing we’ve been waiting for is the ability to create many Teams from a template, in the same way that many organisations do with SharePoint sites. Microsoft have now released this (in preview at the time of writing), and we can define a template in JSON defining exactly what the Team should look like, including the channels, tabs, installed apps, owners and various configuration settings. This is great, because we can now work on scenarios such as a project team, which might have channels for “Technical”, “Account management”, “Project delivery”, “Client success” and so on. You can imagine various tabs being defined in the different channels - perhaps the Account Management channel would have a tab with a widget to bring in summary data from CRM. Maybe the Technical channel would have a tab displaying current work items from Azure Dev Ops too. Apps being made available across many Teams could be 3rd party apps available in the Teams store, or something custom that has been developed in-house.

The things you need to work with templated teams can be summarised as:



So this is all quite developer-led. It isn’t as though the template is being stored in the Teams service somewhere for example - ultimately a dev is writing code to pass some JSON to a call to the Graph. And this JSON contains all details for team creation – the name, the description, the channel settings, installed apps and so on. As I’ve been working with the API, I’m finding that some code which splits out building the JSON somewhat is useful. In particular, it seems useful to split it into two parts:

  • Things that change for every team being created (name, description, owners)

    ..and..

  • Things that stay the same and are considered part of the template (channel settings, installed apps and so on)
So this post is to provide some simple code around that in case others find it useful. There’s nothing too complex here, but I’m trying to get more in the habit of sharing little bits of code via Github.

For details on the JSON structure and the Graph call, see https://docs.microsoft.com/en-us/graph/api/team-post?view=graph-rest-beta. As the documentation shows, the sample JSON to create a team might look like this (this is the very sample from docs):

So, although we’re constructing this JSON and passing it to the Graph, a developer working with this might choose to:

  • Create a static JSON file with the non-changing parts, and treat this as the “template”
  • Write some code to append JSON representing the team name, description and owner(s)

You might notice from the extract above that the owner needs to be specified in the form of a GUID, rather than what you most likely have (the user’s account name/e-mail address). This GUID is the user identifier in AAD. Consequently, we’ll also need a method in our code to lookup a user GUID from an account name.

What exactly can we define in a Teams template?

Here’s a summary:

Setting Example
Visibility Public/Private
Installed apps [Any app from app catalog]
Owners [List of users]
Channel details Tabs, favourite by default
Member settings Allow create channels, allow add apps etc.
Guest settings Allow create channels, allow delete channels
Fun settings Allow giphys, stickers and memes, content rating
Messaging settings Allow edit/delete of messages, allow team and channel mentions

The code

The main helper code I wanted was a method I could call which would accept parameters for the team name, description, and owner(s) so I could call it many times. Perhaps it could become the core code behind something that reads from an Excel file to create many Teams in bulk. Or perhaps it would be behind a custom form in a nice end-user self-service request process. In terms of authentication, this code uses app-only auth to create the Team (using an AAD client ID and client secret), rather than delegated auth (in the context of the user). But, you can take either approach depending on your needs.

So, the core code I came out with is (shown here in the context of a simple console app - but you can drop the core method into whatever you need):


You might notice that I have a “TeamDetails” class which is also doing some of the work. This is where the code to manipulate the JSON is, providing methods to append the team name, description, and owner(s) to the other details being specified:


Of course, the full code is available in Github – it’s at the following address: https://github.com/chrisobriensp/TeamsProvisioning

The result

We can now create as many teams as we like wih the CreateTeam() method shown above. Each one will be created with the channels, tabs and other properties specified in the template. For example, here are the channels and tabs as defined in the sample JSON shown above:



Summary

Creating many Microsoft Teams in a consistent way with the right set of tools is now possible, and we can do it with app-only permissions too (so no need to do anything dodgy around storing details of a high-privilege account). You might find the code in this article useful if you start working with the Graph API methods to do this. In addition to creating Teams with the 'standard' template, note that Microsoft themselves are also providing some specific base templates baked-in to the service - and these might suit your needs out-of-the-box. For now, these base templates are targeted at education, retail and healthcare scenarios - but more will come in the future no doubt.

Either way, we have some new options for rolling out Teams with specific functionality. Hopefully the Graph methods which underpins this will come out of preview very soon, so this approach can be used in production solutions.

Wednesday, 27 February 2019

SharePoint Conference 2019 sessions from me – Enterprise PowerApps, and Azure Functions for Microsoft 365 scenarios

This year’s SharePoint Conference 2019 in Las Vegas in May is will be a great opportunity to learn about the latest developments from Microsoft in the world of SharePoint, Teams, PowerApps, Yammer, Flow and more. As you’d expect from one of the year’s biggest events, Microsoft are there in force and I hear there will be some interesting announcements in terms of new capabilities within Office 365 and SharePoint. Speakers from Microsoft include Jeff Teper, Bill Baer, Dan Holme, Chris McNulty, Mark Kashman, Vesa Juvonen, Naomi Moneypenny, Adam Harmetz, Omar Shahine, Sean Squires, Mike Ammerlaan and many more. But of course, the other speakers are a huge draw too – it’s an amazing list of people who are known for sharing great knowledge, and somehow I sneaked in there too 😉 Other folks include Andrew Connell, Wictor Wilen, Benjamin Niaulin, Chris Givens, Christian Buckley, Eric Shupps, Erwin van Hunen, Paolo Pialorsi, Sebastien Levert, Vlad Catrinescu and more. In short, a group of people who have deep expertise and who love to get into those conversations about challenges and solutions.

For me, I’ll be talking about two of my favourite subjects – both are topics that I think are really important in being able to build effective solutions on Office 365 and SharePoint: PowerApps and Azure Functions. The details of my sessions are below.

Reasons why I think SPC will be a great event

  • The show will be a “moment” for Microsoft, with lots of innovations and developments announced. To hear this first-hand and in detail from Microsoft themselves will put you in a great position.
  • Conferences are a great way of doing condensed learning these days. You can learn in a few days what would otherwise take many weeks or months to pick up – and in my experience, you get to trade off that knowledge for a long time.
  • There are some great full-day workshops to really get to grips with a topic from all angles – whether it’s modern SharePoint, developing with SPFx, Power BI, PowerApps and Flow, Office 365 security or how to build an I.T. strategy around Office 365, chances are there is a workshop for you. See https://sharepointna.com/#!/workshops for the full list.
  • An amazing few days of sessions, led by people with huge passion and knowledge for the topic – see https://sharepointna.com/#!/sessions for the list
  • Lots of opportunities to chat with speakers and ask questions
  • Vegas – if you don’t find the answer you’re looking for in a session, you’ll probably get chance to talk about it in the bar afterwards

Use code “OBRIEN” for a $50 discount

If you sign-up and use my surname as the discount code, you’ll get $50 off the ticket price - and of course, the organizers get to know which speakers attendees are interested in. Since this is Las Vegas we’re talking about here, so I’ll be amazed if you can’t find a good use for that $50 😉

 
To see pricing/register for the conference:
To conference website has all the details - head to:

https://sharepointna.com/#!/register


My sessions

I’ll be delivering the following breakout sessions:

Azure Functions for Microsoft 365 developer scenarios

Azure Functions are the "get out of jail card" for the architect/developer implementing Microsoft 365 solutions. Can't do exactly what you need in a Flow? Need to look-up some data when your PowerApp loads? Implementing custom team sites using Site Designs? Need to run a process on a schedule? Chances are that an Azure Function is the answer - so you need a thorough understanding of this building block to weave it into your solutions effectively. We'll look at authentication, scaling, coding styles, Microsoft Graph bindings and other advanced features, so that you can always call out to some custom behaviour whatever your scenario is.

Enterprise PowerApps - Rich Apps with Offline Support and On-Premises Data

PowerApps can address many business scenarios with ease, but some learning is needed to include advanced functionality such as offline support and connections to on-premises data. Using a series of demos, this talk will walk through these elements - we'll show a PowerApp designed for airline pilots which has these capabilities and see things from both the user and maker perspectives, meaning you go away understanding how to build them into your apps. We'll also consider practical tips of PowerApps - from use across devices, techniques for improving performance, and common headaches when building applications.


Conference details

The conference will be held at the MGM Grand hotel in Las Vegas. The dates are 21-23 May 2019, with workshops being held on the day before and the day after those dates. There are over 200 sessions in total, so whether you’re a business-focused person considering how to get the most out of Office 365 for your organisation, or you’re a highly-technical practitioner wanting to keep up with the latest techniques, the SharePoint Conference will be a great place to do it. Hopefully see you there!


https://sharepointna.com/#!/register

Wednesday, 30 January 2019

End-to-end guide to SharePoint Site Designs and PnP templates using a C# Azure Function - part 2

This article is the continuation of my mini-series on creating a custom template for a SharePoint site or Microsoft Team using Site Designs and a PnP template. The focus is on use of a C# function, since Microsoft's documentation shows use of PowerShell which is unlikely to be an option in future since it is not supported by Azure Functions v2. In this series:

  1. Part 1 - Azure queue, app registration, Flow, Site Design and Site Script
  2. Part 2 - the Azure Function, Key Vault, enabling Managed Service Identity, and the PnP template [this article]
Configuring the Azure Function for authentication
So we created the Function app in the previous article, but there is no code there yet - and we still have some config to do. It's still in preview here in early 2019, but I'm choosing to use the integration between Azure Key Vault and Azure Functions app settings for storing credentials (the app ID and app secret in this case). This is the thing where the credentials are stored in Key Vault, but you don't need to write any special code to fetch them (or indeed, modify any Azure Function code you already have) - instead, you use tokens in app settings which point over to the items in key vault. See the "Key Vault references for Application Settings" section of Simplifying security for serverless and web apps with Azure Functions and App Service. In general, this is a far better way of dealing with credentials than storing them in App Settings, because you can control exactly who can access them – in terms of users working with Azure and THINGS in Azure (e.g. particular App Services, or anything else with a Managed Service Identity).

Step 1 – enable Managed Service Identity for your Function app
  1. In the Azure Portal, go to the “Platform features” area for your Function app and find the “Identity” item:
  2. Enable the “system assigned” managed identity:
  3. Click “Save” and then acknowledge the message which appears:
  4. Your Function app’s managed identity will now be registered:
Step 2 - add credentials to Key Vault and grant access
I’m going to skim over this bit slightly, but the full documentation is at https://docs.microsoft.com/en-us/azure/app-service/app-service-key-vault-references if you need it.
  1. First, add the Client ID and Client Secret for your SharePoint app registration as secrets in the Key Vault. (N.B. If you don’t already have a Key Vault instance in your Azure subscription, you’ll need to create one). Choose any names you like, but mine look like this:
  2.           
  3. For each of these, I need to obtain the full identifier. Do this by clicking into the current version of each secret once you’ve created it, and finding the “Secret Identifier” property:
  4. Copy these URI values as we’ll need them in a second.
  5. Next, grant access to these secrets to your Azure Function. Still in the Key Vault area, go into the “Access policies” area:
  6. Add a new policy:
  7. First, select the principal – here, you are searching for your Azure Function app by name:

    then:
     
  8. Click the “Select” button once you’ve found it.
  9. Now we amend the “Secret permissions”:
  10. Check the “Get” option:
  11. Finally, click “OK” to confirm the permissions:
Step 3 - add App Settings to point to Key Vault entries
In the App Settings for my Function, I need to use the convention of @Microsoft.KeyVault(SecretUri=secret_uri_with_version) to point to my credentials stored securely in Key Vault. So having obtained the URI for each of my secrets in earlier steps, I add entries like these with the App Settings key names used in my code. For each one, value of secret_uri_with_version is the URI for the appropriate secret:



The Azure Function
The final piece is the Azure Function - the core code for this is below, but you can also download the full project from the Github project linked at the end. Some notes about the code:
  • As noted in the previous article, we’re using SharePoint app-only authentication to talk to SharePoint - and the auth code reflects that. You'll need to use alternative PnP AuthenticationManager methods if you choose to use AAD app-only authentication with a certificate
  • I use a separate class to slightly abstract away the Client ID and Client Secret, but it's simply a class with a property for each one. Feel free to create one, or just use local variables instead
Overall there's nothing too complex here, but I find always need a reference for how to pick up the location of the PnP template file when everything is running in Azure. The paths in the code line up with what's in my Visual Studio project that gets published to the Azure Function app:

The PnP template
For completeness, here's a simple PnP template to illustrate the integration - it provisions a modern home page with specific web parts, a content type and a document library, and also adds an entry to the web property bag:

The result

Once everything is in place, you have a great self-service Teams or SharePoint site provisioning process for your organization - you can configure the sites in just about any way possible between Site Designs and PnP templates.
For use with Teams/Office 365 Groups, you can set the default Site Design to be applied for team sites, and your templates will be invoked. For standalone SharePoint sites, users can request a new site from the SharePoint home page:

Your custom Site Design will appear in the list:

..and then the details of the site are collected:

Once the user hits the “Create site” button, the site will be created and Office 365 will indicate that the Site Design and associated templating is taking place:




After a few seconds the site will be available, and both your Site Design and PnP template will have been applied. In my case, I have:
  • From my Site Design:
    • A content type, document library and navigation links
    • Application of my “COB purple” modern theme
  • From my PnP template:
    • A custom modern home page with specific web parts in specific zones
    • Regional settings applied to the site
    • Another custom document library, for good measure
    • A property bag entry
    • Request access settings applied
It’s slightly eye-watering to look at, but that’s great for testing :)

Summary

Integrating PnP templating with a SharePoint site design is slightly involved, but the power it brings in terms of being able to template both sites for Microsoft Teams and standard SharePoint means it's an important technique. Importantly, the use of PnP means that you can configure the sites in ways which aren't currently possible with Site Designs alone. Hopefully this guide is some use towards understanding the mechanisms. As I mentioned previously, all the files used here can be downloaded from:

https://github.com/chrisobriensp/SiteDesignsAndPnPTemplating