Month: January 2023

A user configured Teams personal app with SPFx web part

A user configured Teams personal app with SPFx web part

Recently I already wrote about Microsoft 365 across applications that can be ran in either Teams, Office (Microsoft 365) or Outlook. Since version 1.16 now it is also possible to develop and host those applications in SharePoint with SharePoint Framework (SPFx). Such a sample application, realized with SharePoint Framework (SPFx), I showed in my last post. Now let’s add a personal configuration option based on another simple web part to it.

Series

Content

Setup

To setup an additional configuration web part first and additional web part needs to be added to the existing solution:

In the second step, this additional web part should be set to a hidden state, so it cannot be used on its own. This can be done in the web part manifest. Simply empty the supportedHosts so the web part is not visible anywhere for selection:

“supportedHosts”: [],

Form

The form comes in a very simple way as it only needs one text field for the configurable siteUrl. On initial rendering of course any already configured url needs to be loaded.

Configuration settings form to set Site Url
Configuration settings form to set Site Url

Load and save of the siteUrl is established with a Microsoft Graph service.

Graph Service

To store a personal configuration value the solution makes use of the capability of Microsoft Graph to handle an application’s personal folder.

The standard endpoint in Microsoft Graph is:

https://graph.microsoft.com/v1.0/me/drive/special/approot

Which will result in an /Apps/[App registration name] folder of the user’s mySite / OneDrive url. In case of MSGraphClient/MSGraphClientV3 usage it’s always the same app name. So it’s recommended to incorporate a specific sub folder which is done in code here.

The load is a two-step process, as the “simple” Graph endpoint url turns into a redirect url (302) that can be called anonymously. To circumvent CORS issues (change from graph.microsoft.com to your mySite-host url!) this needs to be done in two separate steps. Thanks to Waldek Mastykarz for pointing this out as well.

public async getPersonalSiteUrl(): Promise<string> {
    const downloadUrl = await this.getDownloadUrl();
    const siteUrl = await this.getSiteUrl(downloadUrl);        
    return siteUrl;
}
private async getDownloadUrl(): Promise<string> {
    const client: MSGraphClientV3 = await this.msGraphClientFactory.getClient('3');
    const response = await client
            .api('/me/drive/special/approot:/createOffer/settings.json:/?select=@microsoft.graph.downloadUrl')
            .get();
    const downloadUrl: string = response['@microsoft.graph.downloadUrl'];
    return Promise.resolve(downloadUrl);
}
private async getSiteUrl(downloadUrl: string): Promise<string> {    
    return fetch(downloadUrl)
      .then(async (response) => {
        const httpResp = await response.json();
        return httpResp.siteUrl;
      })
      .catch(error => {
        console.log(error);
        return "";
      });
}

The store instead is pretty straightforward against the known endpoint. A Json object is PUT against the known endpoint:

public async storePersonalSiteUrl(siteUrl: string): Promise<void> {
    const settings = { siteUrl: siteUrl };
    return this.msGraphClientFactory.getClient('3').then((client: MSGraphClientV3) => {
      client
        .api('/me/drive/special/approot:/createOffer/settings.json:/content')
        .header('content-type', 'text/plain')
        .put(JSON.stringify(settings));
      return Promise.resolve();
    });
}

All in all it results in a settings.json located in the following user’s OneDrive path with the content shown afterwards:

Location of the settings.json inside user’s OneDrive holding siteUrl
Location of the settings.json holding siteUrl
Content of the Settings.json holding siteUrl​
Content of the settings.json holding siteUrl

In the path note the “SharePoint Online Client Extensibility Web Application Principal” which is the app registration name every SPFx web part uses when connecting with the MSGraphClient/MSGraphClientV3.

To be precise and clear, I am not a friend of using MSGraphClient/MSGraphClientV3 in SPFx solutions because of security reasons. Anyway, for simplicity demonstration purposes, it’s implemented here and for full functionality the solution needs to request adequate permissions in the package-solution.json.

“webApiPermissionRequests”: [
{
“resource”: “Microsoft Graph”,
“scope”: “Files.ReadWrite”
}
],

With this personal configuration option the sample alternative to create a SharePoint based offer document realized with SPFx is finalized. For the full solution refer to my GitHub repository. In the final post of my series I will extend the parallel yo teams solution with a search-based messaging extension to send the created documents for review in Outlook or Teams.

Markus is a SharePoint architect and technical consultant with focus on latest technology stack in Microsoft 365 Development. He loves SharePoint Framework but also has a passion for Microsoft Graph and Teams Development.
He works for Avanade as an expert for Microsoft 365 Dev and is based in Munich.
In 2021 he received his first Microsoft MVP award in M365 Development for his continuous community contributions.
Although if partially inspired by his daily work opinions are always personal.