Create Office 365 Groups With SPFx

Overview

 
MS Graph APIs offers a wide range of capabilities. It can be effectively used to create Office 365 groups from SharePoint Framework solutions. An SPFx web part can be a useful asset to create Office 365 groups right from SharePoint page, instead of navigating to Office 365 admin center.
 
During this article, we will develop a practical scenario to create Office 365 groups using MS Graph.
 

Develop SPFx Web Part

 
Open a command prompt. Create a directory for SPFx solution.
  1. md spfx-create-o365-groups  
Navigate to the above created directory.
  1. cd spfx-create-o365-groups  
Run the Yeoman SharePoint Generator to create the solution.
  1. yo @microsoft/sharepoint  
Yeoman generator will present you with the wizard by asking questions about the solution to be created.
 
Create Office 365 Groups With SPFx 
 
Yeoman generator will perform a scaffolding process to generate the solution. The scaffolding process will take a significant amount of time.
 
Once the scaffolding process is completed, lock down the version of project dependencies by running the below command.
  1. npm shrinkwrap  
In the command prompt type the below command to open the solution in the code editor of your choice.
  1. code .   

NPM Packages Dependency

 
Microsoft Graph TypeScript types
 
The typing will help in providing IntelliSense while writing the code.
 
On the command prompt, run the below command to include the npm package.
  1. npm install @microsoft/microsoft-graph-types --save-dev  
 
On the command prompt, run the below command to include the npm package.
  1. npm install @pnp/spfx-controls-react --save   
 
On the command prompt, run the below command.
  1. npm i @pnp/logging @pnp/common @pnp/odata @pnp/sp --save  

Set Permission Scopes

 
To consume MS Graph or any third-party REST APIs, the permissions need to be explicitly set in the solution manifest.
 
Open “config\package-solution.json” and add the below permission scope.
  1. {  
  2.   "$schema""https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",  
  3.   "solution": {  
  4.     "name""spfx-create-o365-groups-client-side-solution",  
  5.     "id""899531e0-cbce-4e4d-a96e-6dd6f18c7e7e",  
  6.     "version""1.0.0.0",  
  7.     "includeClientSideAssets"true,  
  8.     "isDomainIsolated"false,  
  9.     "webApiPermissionRequests": [  
  10.       {  
  11.         "resource""Microsoft Graph",  
  12.         "scope""Group.Read.All"  
  13.       },  
  14.       {  
  15.         "resource""Microsoft Graph",  
  16.         "scope""Group.ReadWrite.All"  
  17.       },  
  18.       {  
  19.         "resource""Microsoft Graph",  
  20.         "scope""Directory.Read.All"  
  21.       },  
  22.       {  
  23.         "resource""Microsoft Graph",  
  24.         "scope""Directory.ReadWrite.All"  
  25.       },  
  26.       {  
  27.         "resource""Microsoft Graph",  
  28.         "scope""Directory.AccessAsUser.All"  
  29.       }  
  30.     ]  
  31.   },  
  32.   "paths": {  
  33.     "zippedPackage""solution/spfx-create-o365-groups.sppkg"  
  34.   }  
  35. }   

Define State

 
Define a state to represent O365 group creation information.
 
Add a file IO365GroupCreationState.ts file under folder “src\webparts\o365GroupCreation\components\IO365GroupCreationState.ts”.
  1. import { MessageBarType } from 'office-ui-fabric-react';  
  2.   
  3. export interface IO365GroupCreationState {  
  4.     name: string;  
  5.     description: string;  
  6.     visibility: string;  
  7.     owners: string[];  
  8.     members: string[];  
  9.     showMessageBar: boolean;  
  10.     messageType?: MessageBarType;  
  11.     message?: string;  
  12. }  

Implement O365 Groups Service

 
Implement service to perform operations against O365 groups.
 
Under src, create a folder named "services".
 
Add a file O365GroupService.ts file under it.
  1. import { MSGraphClient } from "@microsoft/sp-http";  
  2. import { WebPartContext } from "@microsoft/sp-webpart-base";  
  3. import { Group } from "@microsoft/microsoft-graph-types";  
  4.   
  5. export class O365GroupService {  
  6.     public context: WebPartContext;  
  7.   
  8.     public setup(context: WebPartContext): void {  
  9.         this.context = context;  
  10.     }  
  11.   
  12.     public createGroup(groupName: string, groupDescription: string, groupVisibility: string, groupOwners: string[], groupMembers: string[]): Promise<void> {  
  13.         return new Promise<void>((resolve, reject) => {  
  14.             try {  
  15.   
  16.                 const groupRequest: Group = {  
  17.                     displayName: groupName,  
  18.                     description: groupDescription,  
  19.                     groupTypes: [  
  20.                         "Unified"  
  21.                     ],  
  22.                     mailEnabled: true,  
  23.                     mailNickname: groupName.replace(/\s/g, ""),  
  24.                     securityEnabled: false,  
  25.                     visibility: groupVisibility  
  26.                 };  
  27.   
  28.                 if (groupOwners && groupOwners.length) {  
  29.                     groupRequest['owners@odata.bind'] = groupOwners.map(owner => {  
  30.                         return `https://graph.microsoft.com/v1.0/users/${owner}`;  
  31.                     });  
  32.                 }  
  33.   
  34.                 if (groupMembers && groupMembers.length) {  
  35.                     groupRequest['members@odata.bind'] = groupMembers.map(member => {  
  36.                         return `https://graph.microsoft.com/v1.0/users/${member}`;  
  37.                     });  
  38.                 }  
  39.   
  40.                 this.context.msGraphClientFactory  
  41.                     .getClient()  
  42.                     .then((client: MSGraphClient) => {  
  43.                         client  
  44.                             .api("/groups")  
  45.                             .post(groupRequest)  
  46.                             .then((groupResponse) => {  
  47.                                 console.log(groupResponse);  
  48.                                 resolve();  
  49.                             });  
  50.                     });  
  51.             } catch (error) {  
  52.                 console.error(error);  
  53.             }  
  54.         });  
  55.     }  
  56. }  
  57.   
  58. const GroupService = new O365GroupService();  
  59. export default GroupService;  
Under services folder, add a file index.ts.
  1. export * from './O365GroupService' 

Consume service from web part

 
Open web part file at “src\webparts\o365GroupCreation\O365GroupCreationWebPart.ts”
 
Import the service.
  1. import O365GroupService from '../../services/O365GroupService';  
Implement onInit() method to set up the service.
  1. protected onInit(): Promise<void> {  
  2.   return super.onInit().then(() => {  
  3.     O365GroupService.setup(this.context);  
  4.   });  
  5. }  

Pass the context from web part to React Component

 
We will have to pass the SharePoint context from our web part to the React component.
 
Open React component properties at “src\webparts\o365GroupCreation\components\IO365GroupCreationProps.ts”
 
Add the below properties.
  1. import { WebPartContext } from '@microsoft/sp-webpart-base';  
  2.   
  3. export interface IO365GroupCreationProps {  
  4.   description: string;  
  5.   context: WebPartContext;  
  6. }   

Implement the NewGroup React Component

 
Open the React component at src\webparts\o365GroupCreation\components\O365GroupCreation.tsx
 
Add the below imports.
  1. import { TextField } from 'office-ui-fabric-react/lib/TextField';  
  2. import { Label } from 'office-ui-fabric-react/lib/Label';  
  3. import { ChoiceGroup, IChoiceGroupOption } from 'office-ui-fabric-react/lib/ChoiceGroup';  
  4. import { PeoplePicker, PrincipalType, IPeoplePickerUserItem } from "@pnp/spfx-controls-react/lib/PeoplePicker";  
  5. import { MessageBar, MessageBarType, IStackProps, Stack } from 'office-ui-fabric-react';  
  6. import { autobind } from 'office-ui-fabric-react';  
  7. import O365GroupService from '../../../services/O365GroupService';  
Use the React state.
  1. import { IO365GroupCreationState } from './IO365GroupCreationState';  
  2.   
  3. export default class O365GroupCreation extends React.Component<IO365GroupCreationProps, IO365GroupCreationState> {  
  4.   constructor(props: IO365GroupCreationProps) {  
  5.     super(props);  
  6.   
  7.     this.state = {  
  8.       name: '',  
  9.       description: '',  
  10.       visibility: 'Public',  
  11.       owners: [],  
  12.       members: [],  
  13.       showMessageBar: false  
  14.     };  
  15.   }  
  16. .  
  17. .  
  18. .  
  19. }  
Implement render method to add the UI controls.
  1. public render(): React.ReactElement<IO365GroupCreationProps> {  
  2.   return (  
  3.     <div className={styles.container}>  
  4.       <div className={styles.row}>  
  5.         {  
  6.           this.state.showMessageBar  
  7.             ?  
  8.             <div className="form-group">  
  9.               <Stack {...verticalStackProps}>  
  10.                 <MessageBar messageBarType={this.state.messageType}>{this.state.message}</MessageBar>  
  11.               </Stack>  
  12.             </div>  
  13.             :  
  14.             null  
  15.         }  
  16.   
  17.         <div className="form-group">  
  18.           <TextField label="Name" required onChanged={this.onchangedName} />  
  19.         </div>  
  20.   
  21.         <div className="form-group">  
  22.           <TextField label="Description" required multiline rows={3} onChanged={this.onchangedDescription} />  
  23.         </div>  
  24.   
  25.         <div className="form-group">  
  26.           <Label required={true}>Visibility</Label>  
  27.           <ChoiceGroup  
  28.             defaultSelectedKey="Public"  
  29.             options={[  
  30.               {  
  31.                 key: 'Public',  
  32.                 text: 'Public - Anyone can see group content'  
  33.               },  
  34.               {  
  35.                 key: 'Private',  
  36.                 text: 'Private - Only members can see group content'  
  37.               }  
  38.             ]}  
  39.             onChange={this.onChangeVisibility}  
  40.           />  
  41.         </div>  
  42.   
  43.         <div className="form-group">  
  44.           <PeoplePicker  
  45.             context={this.props.context}  
  46.             titleText="Owners"  
  47.             personSelectionLimit={3}  
  48.             showHiddenInUI={false}  
  49.             principalTypes={[PrincipalType.User]}  
  50.             selectedItems={this._getPeoplePickerOwners}  
  51.             isRequired={true} />  
  52.         </div>  
  53.   
  54.         <div className="form-group">  
  55.           <PeoplePicker  
  56.             context={this.props.context}  
  57.             titleText="Members"  
  58.             personSelectionLimit={3}  
  59.             showHiddenInUI={false}  
  60.             principalTypes={[PrincipalType.User]}  
  61.             selectedItems={this._getPeoplePickerMembers}  
  62.             isRequired={true} />  
  63.         </div>  
  64.   
  65.         <div className={`${styles.buttonRow} form-group`}>  
  66.           <button type="button" className="btn btn-primary" onClick={this.createNewGroup}>Submit</button>  
  67.         </div>  
  68.       </div>  
  69.     </div>  
  70.   );  
  71. }  
Implement the event handlers for UI controls.
  1. @autobind  
  2. private _getPeoplePickerOwners(items: IPeoplePickerUserItem[]) {  
  3.   this.setState(() => {  
  4.     return {  
  5.       ...this.state,  
  6.       owners: items.map(x => x.id.replace('i:0#.f|membership|'''))  
  7.     };  
  8.   });  
  9. }  
  10.   
  11. @autobind  
  12. private _getPeoplePickerMembers(items: IPeoplePickerUserItem[]) {  
  13.   this.setState(() => {  
  14.     return {  
  15.       ...this.state,  
  16.       members: items.map(x => x.id.replace('i:0#.f|membership|'''))  
  17.     };  
  18.   });  
  19. }  
  20.   
  21. @autobind  
  22. private onchangedName(groupName: any): void {  
  23.   this.setState({ name: groupName });  
  24. }  
  25.   
  26. @autobind  
  27. private onchangedDescription(groupDescription: any): void {  
  28.   this.setState({ description: groupDescription });  
  29. }  
  30.   
  31. @autobind  
  32. private onChangeVisibility(ev: React.FormEvent<HTMLInputElement>, option: IChoiceGroupOption): void {  
  33.   this.setState({ visibility: option.key });  
  34. }  
  35.   
  36. @autobind  
  37. private createNewGroup(): void {  
  38.   try {  
  39.     O365GroupService.createGroup(this.state.name, this.state.description, this.state.visibility, this.state.owners, this.state.members);  
  40.   
  41.     this.setState({  
  42.       message: "Group " + this.state.name + " is created successfully!",  
  43.       showMessageBar: true,  
  44.       messageType: MessageBarType.success  
  45.     });  
  46.   } catch (error) {  
  47.     this.setState({  
  48.       message: "Group " + this.state.name + " creation failed with error: " + error,  
  49.       showMessageBar: true,  
  50.       messageType: MessageBarType.error  
  51.     });  
  52.   }  
  53. }  

Deploy the SPFx Package to SharePoint App Catalog

 
Follow the below steps to deploy the SPFx package (.sppkg) to SharePoint app catalog.
 
Build minified assets
 
On the command prompt, type the below command.
  1. gulp bundle --ship  
Prepare the package
 
On the command prompt, type the below command.
  1. gulp package-solution --ship  
The .sppkg package will be available inside “sharepoint\solution” folder.
 
Upload package to app catalog
  1. Open SharePoint app catalog site.
  2. Upload the package to app catalog.

    Create Office 365 Groups With SPFx

  3. Click Deploy.

API Management

 
After deploying the web part, follow the below steps to approve API requests.
  1. Open SharePoint Admin Center (https://[tenant]-admin.sharepoint.com).
  2. From left navigation, click “API Management”.
  3. Approve the pending requests.
Create Office 365 Groups With SPFx

Test the WebPart

  1. On the command prompt, type “gulp serve”.
  2. Open SharePoint site.
  3. Navigate to /_layouts/15/workbench.aspx
  4. Locate and add the webpart (named O365GroupCreation) to page.
  5. Fill in the group information.
  6. Click Submit.
Create Office 365 Groups With SPFx 

Troubleshoot

 
The page generates an alert “To view the information on this page, you need to verify your identity”, to resolve this add below urls to trusted site in browser.
  • https://graph.microsoft.com
  • https://.office365.com
  • https://.microsoftonline.com
  • https://.sharepoint.com
  • https://.outlook.com

Summary

 
Microsoft Graph offers a wide range of APIs to access the content and services provided by Office 365. Creating a group by using MS Graph API is one of the business cases supporting it. As this solution uses an application permission, a page hosting this web part has to be carefully exposed to a certain set of users.