DEV Community

Rainson12
Rainson12

Posted on

SharePoint Framework WebPart & Asp.Net Core WebApi with Azure AD Auth

When developing new Webparts for SharePoint or Addins for Office 365 you might want to make use of your own APIs. This will raise the challenge of how to protect you backend and authenticate your users. Since I haven't found any good and complete guidelines on how to setup an SPFX Webpart together with a C# ASP.Net Core WebApi backend, I wanted to share my approach.

Setup:

Create the Backend

Create a new Project using VS 2019. If you are asked for the project template choose ASP.NET Core Web API. Click on next when asked for the Target Framework and Authentication Type choose Microsoft identity platform:
Image description
After creation of the project you will be prompted for an additional required package called dotnet msidentity tool. Just click finish to complete the project creation.

Configure the Microsoft identity platform

To configure the microsoft identity platform to connect zu your Azure AD click on configure at the connected services screen:
Image description
A Browser Window will open and you are asked to login to your 365 tenant. If you already have an App registered in Azure you can select an existing one, otherwise just let Visual Studio create one for you:
Image description
In the opening dialog just enter the application Name which will be created on the Azure AD side.

After creation, select the newly created APP. When asked for Additional Configuration you do not need to select anything. Additional Graph or Permissions to another API can be revisited when going to the App Registrations in the Azure Admin Portal. After finishing the dialog and installing required nuget packages you will see that the Microsoft identity platform is now configured.
Image description

By configuring the Microsoft identity platform a few things happend with your project. If you check the appsettings.json you will see that there is a configuration part created for AzureAd this includes your azure domain, tenant Id and client id. These configuration settings will match the App that has been created on the Azure side. When opening the Startup.cs you will find that the authentication was added to the service and app configuration:
Image description
For allowing access from other origins we need to configure CORS. To allow all orgins simply add

app.UseCors(x => x
               .AllowAnyMethod()
               .AllowAnyHeader()
               .AllowCredentials()
               .SetIsOriginAllowed(hostName => true));
Enter fullscreen mode Exit fullscreen mode

to the Configure(IApplicationBuilder app, IWebHostEnvironment env) method. Make sure to add the .UseCors before the .UseEndoints for example:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication1 v1"));
            }

            app.UseHttpsRedirection();
            app.UseRouting();

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseCors(x => x
               .AllowAnyMethod()
               .AllowAnyHeader()
               .AllowCredentials()
               .SetIsOriginAllowed(hostName => true));

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            }); 
        }
Enter fullscreen mode Exit fullscreen mode

When checking the WeatherForecastController.cs in the Controllers directory, ensure that the controller is guarded with an Authorize annotation:
Image description

This annotation will ensure that the endpoints of this controller can only be accessed by Users which are authenticated by your Azure AD. You can run the debugger and try to access your endpoint by accessing https://localhost:44340/WeatherForecast in your browser (depending on your debug configurations a different port can be used). You should receive an Http 401 Error, this means you are not authorized since your Browser is not passing the Azure AD token to your backend. This is expected, however when setting up the SharePoint Framework Webpart we will configure it, so that the token will be passed from SharePoint Online to your backend without any additional authentication.

Create the SharePoint Framework WebPart

In this guide I will make use of the Yeoman generator to generate the boilerplate code to get started. Please not that I will be using the react template and name my application HelloWorld for this guide. If you are unsure on how to initialize the SPFX Webpart follow the steps documented by Microsoft. After creation of the boilerplate open the folder in vscode.

In order to pass the Azure Token from your signed in user we to the backend you need to make use of AadHttpClientFactory. The boilerplate code will make it available in the default WebPart class. Since I gave my App the default HelloWorld name, the root file to bootstrap our application can be found at src\webparts\helloWorld\HelloWorldWebPart.ts. Open that file and pass the instance of this.context.aadHttpClientFactory to the generated component:

public render(): void {
    const element: React.ReactElement<IHelloWorldProps> = React.createElement(
      HelloWorld,
      {
        aadHttpClientFactory: this.context.aadHttpClientFactory,
        description: this.properties.description,
        isDarkTheme: this._isDarkTheme,
        environmentMessage: this._environmentMessage,
        hasTeamsContext: !!this.context.sdks.microsoftTeams,
        userDisplayName: this.context.pageContext.user.displayName
      }
    );

    ReactDom.render(element, this.domElement);
  }
Enter fullscreen mode Exit fullscreen mode

Since now the type validation will complain, we need to adjust the interface for the props that will be passed to the component. Open the file src\webparts\helloWorld\components\IHelloWorldProps.ts and add aadHttpClientFactory: AadHttpClientFactory; to the interface:

import { AadHttpClientFactory } from '@microsoft/sp-http';

export interface IHelloWorldProps {
  description: string;
  isDarkTheme: boolean;
  environmentMessage: string;
  hasTeamsContext: boolean;
  userDisplayName: string;
  aadHttpClientFactory: AadHttpClientFactory;
}
Enter fullscreen mode Exit fullscreen mode

Now that we pass the Factory for creating clients to access our Endpoints we need to make use of it. Open the file src\webparts\helloWorld\components\HelloWorld.tsx. I replaced the render code to just render a Button which when being clicked will call our backend endpoint. Please note that you need to update the Id used in the getClient() method. The Id which should be used here is your clientId which you will find in the appsettings.json from you backend project. In my case this is acc8e92b-a093-4514-a9f8-de4e92301aed:

import * as React from 'react';
import styles from './HelloWorld.module.scss';
import { IHelloWorldProps } from './IHelloWorldProps';
import { escape } from '@microsoft/sp-lodash-subset';
import { DefaultButton } from 'office-ui-fabric-react';
import { AadHttpClient, HttpClientResponse } from '@microsoft/sp-http';

export default class HelloWorld extends React.Component<IHelloWorldProps, {}> {
  private async callBackend (): Promise<void> {
    let client = await this.props.aadHttpClientFactory.getClient('acc8e92b-a093-4514-a9f8-de4e92301aed');
    let response: HttpClientResponse = await client.get('https://localhost:44340/WeatherForecast', AadHttpClient.configurations.v1);
    let jsonData = await response.json();
    console.log(jsonData);
  }

  public render(): React.ReactElement<IHelloWorldProps> {
    const {
      description,
      isDarkTheme,
      environmentMessage,
      hasTeamsContext,
      userDisplayName
    } = this.props;

    return (
      <section className={`${styles.helloWorld} ${hasTeamsContext ? styles.teams : ''}`}>
        <DefaultButton onClick={this.callBackend.bind(this)}>Click me</DefaultButton>
      </section>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Now that the code is finished we need to add the required permission which has to be approved by the Admin when adding our WebPart to our SharePoint App Catalog. Therefore you have to open the package-solution.json and add (make sure to replace the resource id with your client id from above).

"webApiPermissionRequests": [
      {
        "resource": "acc8e92b-a093-4514-a9f8-de4e92301aed",
        "scope": "user_impersonation"
      }
    ],
Enter fullscreen mode Exit fullscreen mode

to the solution so it will look like this:
Image description

If you now want to run your SPFX Webpart using gulp serve in your SharePoint Online Workbench we need to grant the Workbench App permissions, this however is not required when packaging and deploying the App without using the workbench. To grant permission to the workbench open your azure portal. Navigate to App registrations:
Image description. Select All applications and search for SharePoint Online Client Extensibility Web Application Principal. Choose the first one:
Image description. Now we need to add the permission to allow passing the user to our backend. Click on API Permissions and then Add a permission and then APIs my organization uses. Search for your clientId or App Name which you used during the VS Wizard for setting up the microsoft identity platform:
Image description. Select the App and add access_as_user permission:
Image description
After adding the permission grant the admin consent to put the added permission effective:
Image description.

If you now run gulp server in your SPFX folder and open your workbench, you should see a button. When clicking it you will have to login (unless you already logged in to your tenant). After authentication you will see the backend response in your console:
Image description

Deployment

When deploying the WebPart you need to adjust the appregistration since your URLs will change. In order to do that access your Azure Portal and open the app registration site. Choose again All applications and search for your application name which you gave during the VS Wizard for the setup of the microsoft identity platform. You can also filter by clicking on the Application (client) ID starts with field and paste your clientId which we used previously. You should now find your app:
Image description
Click on it and open the Authentication Panel:
Image description

All you have to do now is updating the redirect URLs to the final URLs.

Discussion (0)