with TypeScript SSO
Open File Explorer and create the (C:\temp\vscode-yeoman) project folder.
Open Visual Studio Code.
Display the Terminal window (View > Terminal).
Change to that folder.
cd C:\temp\vscode-yeoman
Run the Yeoman generator to create the project.
yo office
Choose "Office Add-in Task Pane project supporting single sign-on".
Use the arrow keys and press Enter to select.
![]() |
Choose a script type: Select "TypeScript".
What do you want to name your add-in: Type "Word-TypeScript-SSO".
Which office client application would you like to support: Select "Word".
All the necessary files will be created for you.
package.json file
Change to that folder.
cd Word-TypeScript-SSO
Open the Explorer pane (View > Explorer).
Open this folder in the current VS Code instance.
code -a .
Click on the package.json file.
![]() |
{
"name": "office-addin-taskpane-sso",
"version": "0.0.0",
"private": true,
"config": {
"app_to_debug": "word",
"app_type_to_debug": "desktop",
"dev_server_port": 3000
},
"scripts": {
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"configure-sso": "office-addin-sso configure manifest.xml",
"dev-server": "webpack serve --mode development",
"lint": "office-addin-lint check",
"lint:fix": "office-addin-lint fix",
"prettier": "office-addin-lint prettier",
"sideload": "office-addin-debugging start manifest.xml",
"start": "npm run build:dev && concurrently \"npm run start:server\" \"npm run sideload\"",
"start:server": "office-addin-sso start manifest.xml",
"stop": "office-addin-debugging stop manifest.xml",
"validate": "office-addin-manifest validate manifest.xml",
"watch": "webpack --mode development --watch"
},
"dependencies": {
"@azure/msal-browser": "^2.28.1",
"core-js": "^3.9.1",
"dotenv": "^8.2.0",
"node-fetch": "^2.6.1",
"office-addin-sso": "^2.1.1",
"regenerator-runtime": "^0.13.7"
},
"devDependencies": {
"@babel/core": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@types/jquery": "^3.3.34",
"@types/office-js": "^1.0.180",
"@types/office-runtime": "^1.0.17",
"acorn": "^8.5.0",
"babel-loader": "^8.2.5",
"buffer": "^6.0.3",
"concurrently": "^6.3.0",
"copy-webpack-plugin": "^9.0.1",
"eslint-plugin-office-addins": "^2.1.1",
"file-loader": "^6.2.0",
"html-loader": "^4.1.0",
"html-webpack-plugin": "^5.5.0",
"https-browserify": "^1.0.0",
"office-addin-debugging": "^4.4.1",
"office-addin-lint": "^2.1.1",
"office-addin-manifest": "^1.9.1",
"office-addin-prettier-config": "^1.2.0",
"source-map-loader": "^3.0.0",
"stream-http": "^3.2.0",
"ts-loader": "^9.3.1",
"typescript": "^4.7.4",
"url": "0.11.0",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "4.10.0"
},
"prettier": "office-addin-prettier-config",
"browserslist": [
"ie 11"
]
}
manifest.xml
Click on the manifest.xml file.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0"
xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides"
xsi:type="TaskPaneApp">
<Id>da4fb0dd-2ad4-405c-b112-7c57e6e91e0c</Id>
<Version>1.0.0.0</Version>
<ProviderName>Contoso</ProviderName>
<DefaultLocale>en-US</DefaultLocale>
<DisplayName DefaultValue="Word-TypeScript-SSO"/>
<Description DefaultValue="An add-in that shows how to use SSO, and to fallback to interactive login when SSO is not available."/>
<IconUrl DefaultValue="https://localhost:{PORT}/assets/icon-32.png"/>
<HighResolutionIconUrl DefaultValue="https://localhost:{PORT}/assets/icon-64.png"/>
<SupportUrl DefaultValue="https://www.contoso.com/help"/>
<AppDomains>
<AppDomain>https://www.contoso.com</AppDomain>
</AppDomains>
<Hosts>
<Host Name="Document"/>
</Hosts>
<DefaultSettings>
<SourceLocation DefaultValue="https://localhost:{PORT}/taskpane.html"/>
</DefaultSettings>
<Permissions>ReadWriteDocument</Permissions>
<VersionOverrides xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="VersionOverridesV1_0">
<Hosts>
<Host xsi:type="Document">
<DesktopFormFactor>
<GetStarted>
<Title resid="GetStarted.Title"/>
<Description resid="GetStarted.Description"/>
<LearnMoreUrl resid="GetStarted.LearnMoreUrl"/>
</GetStarted>
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<OfficeTab id="TabHome">
<Group id="CommandsGroup">
<Label resid="CommandsGroup.Label"/>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Control xsi:type="Button" id="TaskpaneButton">
<Label resid="TaskpaneButton.Label"/>
<Supertip>
<Title resid="TaskpaneButton.Label"/>
<Description resid="TaskpaneButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ShowTaskpane">
<TaskpaneId>ButtonId1</TaskpaneId>
<SourceLocation resid="Taskpane.Url"/>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16" DefaultValue="https://localhost:{PORT}/assets/icon-16.png"/>
<bt:Image id="Icon.32x32" DefaultValue="https://localhost:{PORT}/assets/icon-32.png"/>
<bt:Image id="Icon.80x80" DefaultValue="https://localhost:{PORT}/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/>
<bt:Url id="Commands.Url" DefaultValue="https://localhost:{PORT}/commands.html"/>
<bt:Url id="Taskpane.Url" DefaultValue="https://localhost:{PORT}/taskpane.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GetStarted.Title" DefaultValue="Get started with your sample add-in!"/>
<bt:String id="CommandsGroup.Label" DefaultValue="Commands Group"/>
<bt:String id="TaskpaneButton.Label" DefaultValue="Show Taskpane"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="GetStarted.Description" DefaultValue="Your sample add-in loaded succesfully."/>
<bt:String id="TaskpaneButton.Tooltip" DefaultValue="Click to Show a Taskpane"/>
</bt:LongStrings>
</Resources>
<WebApplicationInfo>
<Id>{application GUID here}</Id>
<Resource>api://localhost:{PORT}/{application GUID here}</Resource>
<Scopes>
<Scope>User.Read</Scope>
<Scope>profile</Scope>
</Scopes>
</WebApplicationInfo>
</VersionOverrides>
</OfficeApp>
webpack.config.js
Click on the webpack.config.js file.
/* eslint-disable no-undef */
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const urlDev = "https://localhost:3000/";
const urlProd = "https://www.contoso.com/"; // CHANGE THIS TO YOUR PRODUCTION DEPLOYMENT LOCATION
module.exports = async (env, options) => {
const dev = options.mode === "development";
const config = {
devtool: "source-map",
entry: {
polyfill: ["core-js/stable", "regenerator-runtime/runtime"],
taskpane: "./src/taskpane/taskpane.ts",
commands: "./src/commands/commands.ts",
fallbackauthdialog: "./src/helpers/fallbackauthdialog.ts",
},
output: {
clean: true,
},
resolve: {
extensions: [".ts", ".tsx", ".html", ".js"],
fallback: {
buffer: require.resolve("buffer/"),
http: require.resolve("stream-http"),
https: require.resolve("https-browserify"),
url: require.resolve("url/"),
},
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-typescript"],
},
},
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: "ts-loader",
},
{
test: /\.html$/,
exclude: /node_modules/,
use: "html-loader",
},
{
test: /\.(png|jpg|jpeg|gif|ico)$/,
type: "asset/resource",
generator: {
filename: "assets/[name][ext][query]",
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
filename: "taskpane.html",
template: "./src/taskpane/taskpane.html",
chunks: ["polyfill", "taskpane"],
}),
new HtmlWebpackPlugin({
filename: "commands.html",
template: "./src/commands/commands.html",
chunks: ["polyfill", "commands"],
}),
new HtmlWebpackPlugin({
filename: "fallbackauthdialog.html",
template: "./src/helpers/fallbackauthdialog.html",
chunks: ["polyfill", "fallbackauthdialog"],
}),
new CopyWebpackPlugin({
patterns: [
{
from: "assets/*",
to: "assets/[name][ext][query]",
},
{
from: "manifest*.xml",
to: "[name]" + "[ext]",
transform(content) {
if (dev) {
return content;
} else {
return content.toString().replace(new RegExp(urlDev, "g"), urlProd);
}
},
},
],
}),
],
};
return config;
};
Other Source Files
The other project files are displayed on this page for reference.
PORT Number
Before you do anything else, you need to decide or find out which port number you will be testing on.
We will be using 8080, but yours might be different.
SSO Manual App Registration
To work with SSO you need to register your Office Add-in with the Microsoft identity platform.
The following command can be run to set this up for you.
Before you run this though, it is worth noting that it will install Microsoft Azure CLI which is 250 MB.
Also worth noting is that this command is not always successful.
npm configure-sso
For these reasons we have outlined the manual steps here.
![]() |
Edit package.json
Change the port number.
{
"name": "office-addin-taskpane-sso",
"version": "0.0.0",
"private": true,
"config": {
"app_to_debug": "word",
"app_type_to_debug": "desktop",
"dev_server_port": 8080
Change build to setting the NODE_OPTIONS environment variable to --openssl-legacy-provider (later versions of Node).
"scripts": {
"build": "webpack --mode production",
"build:dev": "set NODE_OPTIONS=--openssl-legacy-provider && webpack --mode development",
Edit manifest.xml
Insert the "Application (client) ID" into the WebApplicationInfo tag.
Add the Client ID to the ID tag.
Add the Port Number and Client ID to the Resource tag.
<WebApplicationInfo>
<Id> Application Client ID </Id>
<Resource> api://localhost:8080/Application Client ID </Resource>
<Scopes>
<Scope>User.Read</Scope>
<Scope>profile</Scope>
</Scopes>
</WebApplicationInfo>
</VersionOverrides>
</OfficeApp>
Edit webpack.config.js
Change the Port Number in the urlDev.
const urlDev = "https://localhost:8080/";
const urlProd = "https://bettersolutions.com/";
Edit .ENV
Insert the Client ID to the CLIENT_ID constant.
Insert the Port Number to the PORT constant.
CLIENT_ID= Application Client ID
GRAPH_URL_SEGMENT=/me
NODE_ENV=development
PORT= 8080
QUERY_PARAM_SEGMENT=
SCOPE=User.Read
Edit fallbackauthdialog.ts
Click on the src/helpers/fallbackauthdialog.ts file.
Add the Client ID to the clientId parameter.
Add the Port Number to the redirectUrl parameter.
const msalConfig: Configuration = {
auth: {
clientId: "Application Client ID",
authority: "https://login.microsoftonline.com/common",
redirectUri: "https://localhost:8080/fallbackauthdialog.html",
navigateToLoginRequestUrl: false,
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: true,
},
};
Build the Add-in
Execute the following command.
npm run build:dev
Check that the project builds successfully.
Start the Local Server
Execute the following command.
npm run start:server
You should see a Security Warning message asking if you want to install the certificate.
Press Yes.
Check the server is running on 8080.
Press Ctrl + C to stop the server and press Y, Enter to terminate the batch job.
Load the Add-in - Desktop
Execute the following command.
npm run start
![]() |
Customise the Add-in Further
link - learn.microsoft.com/en-us/office/dev/add-ins/quickstarts/sso-quickstart
link - learn.microsoft.com/en-us/office/dev/add-ins/develop/sso-in-office-add-ins
link - learn.microsoft.com/en-us/office/dev/add-ins/develop/create-sso-office-add-ins-nodejs
© 2023 Better Solutions Limited. All Rights Reserved. © 2023 Better Solutions Limited TopPrevNext