Skip to content

Commit 6b037dc

Browse files
sebastienlevertnmetulevmusalevogtnwaldekmastykarz
authored
Adding support for TeamsFx (#1480)
Co-authored-by: Nikola Metulev <[email protected]> Co-authored-by: Nikola Metulev <[email protected]> Co-authored-by: Musale Martin <[email protected]> Co-authored-by: Nicolas Vogt <[email protected]> Co-authored-by: Waldek Mastykarz <[email protected]> Co-authored-by: Caroline Miaro <[email protected]> Co-authored-by: turenlong <[email protected]> Co-authored-by: DeVere Dyett <[email protected]> Co-authored-by: rentu <[email protected]>
1 parent f33e416 commit 6b037dc

File tree

11 files changed

+290
-27
lines changed

11 files changed

+290
-27
lines changed

.vscode/settings.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,5 @@
33
"editor.defaultFormatter": "esbenp.prettier-vscode",
44
"editor.codeActionsOnSave": {
55
"source.fixAll.tslint": true
6-
},
7-
"cSpell.words": ["Templated", "flyout", "semibold", "xmlns"],
8-
"tslint.configFile": "./tslint.json"
6+
}
97
}

\

Lines changed: 0 additions & 6 deletions
This file was deleted.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"samples/angular-app",
1010
"samples/vue-app",
1111
"samples/electron-app",
12-
"samples/sp-webpart"
12+
"samples/sp-webpart",
13+
"samples/teamsfx-app/tabs"
1314
],
1415
"scripts": {
1516
"build": "npm run prettier:check && npm run clean && lerna run build --scope @microsoft/*",
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Microsoft Graph Toolkit TeamsFx Provider
2+
3+
[![npm](https://img.shields.io/npm/v/@microsoft/mgt-teamsfx-provider?style=for-the-badge)](https://www.npmjs.com/package/@microsoft/mgt-teamsfx-provider)
4+
5+
The [Microsoft Graph Toolkit (mgt)](https://aka.ms/mgt) library is a collection of authentication providers and UI components powered by Microsoft Graph.
6+
7+
The `@microsoft/mgt-teamsfx-provider` package exposes the `TeamsFxProvider` class which uses [TeamsFx](https://www.npmjs.com/package/@microsoft/teamsfx) to sign in users and acquire tokens to use with Microsoft Graph.
8+
9+
## Usage
10+
11+
1. Install the packages
12+
13+
```bash
14+
npm install @microsoft/mgt-element @microsoft/mgt-teamsfx-provider @microsoft/teamsfx
15+
```
16+
17+
2. Initialize the provider as below:
18+
19+
```ts
20+
import {Providers} from '@microsoft/mgt-element';
21+
import {TeamsFxProvider} from '@microsoft/mgt-teamsfx-provider';
22+
import {TeamsUserCredential} from "@microsoft/teamsfx";
23+
24+
const scope = ["User.Read"];
25+
const teamsfx = new TeamsFx();
26+
const provider = new TeamsFxProvider(teamsfx, scope);
27+
Providers.globalProvider = provider;
28+
```
29+
30+
3. Perform consent process to get access token for certain scopes
31+
```ts
32+
await teamsfx.login(this.scope);
33+
Providers.globalProvider.setState(ProviderState.SignedIn);
34+
```
35+
36+
37+
See [provider usage documentation](https://docs.microsoft.com/graph/toolkit/providers) to learn about how to use the providers with the mgt components, to sign in/sign out, get access tokens, call Microsoft Graph, and more.
38+
39+
You can also refer [this sample](https://github.com/OfficeDev/TeamsFx-Samples/tree/ga/graph-toolkit-contact-exporter) to learn how to use this auth provider in TeamsFx project.
40+
41+
## See also
42+
* [Microsoft Graph Toolkit docs](https://aka.ms/mgt-docs)
43+
* [Microsoft Graph Toolkit repository](https://aka.ms/mgt)
44+
* [Microsoft Graph Toolkit playground](https://mgt.dev)
45+
* [TeamsFx docs](https://aka.ms/teamsfx-docs)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"name": "@microsoft/mgt-teamsfx-provider",
3+
"version": "2.0.0",
4+
"description": "The Microsoft Graph Toolkit TeamsFx Provider",
5+
"keywords": [
6+
"microsoft graph",
7+
"microsoft graph toolkit",
8+
"mgt",
9+
"msal",
10+
"auth",
11+
"msal 2.0",
12+
"teamsfx",
13+
"authentication"
14+
],
15+
"homepage": "https://github.com/microsoftgraph/microsoft-graph-toolkit",
16+
"bugs": {
17+
"url": "https://github.com/microsoftgraph/microsoft-graph-toolkit/issues"
18+
},
19+
"repository": {
20+
"type": "git",
21+
"url": "https://github.com/microsoftgraph/microsoft-graph-toolkit"
22+
},
23+
"author": "Microsoft",
24+
"license": "MIT",
25+
"main": "./dist/es6/index.js",
26+
"types": "./dist/es6/index.d.ts",
27+
"module": "./dist/es6/index.js",
28+
"files": [
29+
"dist",
30+
"src"
31+
],
32+
"scripts": {
33+
"build": "npm run clean && npm run build:compile",
34+
"build:compile": "npm run compile",
35+
"build:watch": "npm run compile:watch",
36+
"clean": "shx rm -rf ./dist && shx rm -rf ./tsconfig.tsbuildinfo",
37+
"compile": "tsc -b",
38+
"compile:watch": "tsc -w",
39+
"lint": "tslint -c ../../../tslint.json 'src/**/*.ts'",
40+
"postpack": "cpx *.tgz ../../../artifacts"
41+
},
42+
"peerDependencies": {
43+
"@microsoft/teamsfx": "0.6.x - 1.0.x"
44+
},
45+
"devDependencies": {
46+
"@microsoft/teamsfx": "0.6.x - 1.0.x"
47+
},
48+
"dependencies": {
49+
"@microsoft/mgt-element": "*"
50+
},
51+
"publishConfig": {
52+
"directory": "dist"
53+
}
54+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/**
2+
* -------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
4+
* See License in the project root for license information.
5+
* -------------------------------------------------------------------------------------------
6+
*/
7+
8+
import { IProvider, ProviderState, createFromProvider } from '@microsoft/mgt-element';
9+
import { TeamsFx } from '@microsoft/teamsfx';
10+
11+
/**
12+
* TeamsFx Provider handler
13+
*
14+
* @export
15+
* @class TeamsFxProvider
16+
* @extends {IProvider}
17+
*/
18+
export class TeamsFxProvider extends IProvider {
19+
/**
20+
* Name used for analytics
21+
*
22+
* @readonly
23+
* @memberof TeamsFxProvider
24+
*/
25+
public get name(): string {
26+
return 'MgtTeamsFxProvider';
27+
}
28+
29+
/**
30+
* returns teamsfx instance
31+
*
32+
* @readonly
33+
* @memberof TeamsFxProvider
34+
*/
35+
public get teamsfx(): TeamsFx {
36+
return this._teamsfx;
37+
}
38+
39+
/**
40+
* Privilege level for authentication
41+
*
42+
* Can use string array or space-separated string, such as ["User.Read", "Application.Read.All"] or "User.Read Application.Read.All"
43+
*
44+
* @type {string | string[]}
45+
* @memberof TeamsFxProvider
46+
*/
47+
private scopes: string | string[] = [];
48+
49+
/**
50+
* TeamsFx instance
51+
*
52+
* @type {TeamsFx}
53+
* @memberof TeamsFxProvider
54+
*/
55+
private readonly _teamsfx: TeamsFx;
56+
57+
/**
58+
* Access token provided by TeamsFx
59+
*
60+
* @type {string}
61+
* @memberof TeamsFxProvider
62+
*/
63+
private _accessToken: string = '';
64+
65+
constructor(teamsfx: TeamsFx, scopes: string | string[]) {
66+
super();
67+
68+
if (!this._teamsfx) {
69+
this._teamsfx = teamsfx;
70+
}
71+
72+
this.validateScopesType(scopes);
73+
74+
const scopesArr = this.getScopesArray(scopes);
75+
76+
if (!scopesArr || scopesArr.length === 0) {
77+
this.scopes = ['.default'];
78+
} else {
79+
this.scopes = scopesArr;
80+
}
81+
82+
this.graph = createFromProvider(this);
83+
}
84+
85+
/**
86+
* Uses provider to receive access token via TeamsFx
87+
*
88+
* @returns {Promise<string>}
89+
* @memberof TeamsFxProvider
90+
*/
91+
public async getAccessToken(): Promise<string> {
92+
try {
93+
const accessToken = await this.teamsfx.getCredential().getToken(this.scopes);
94+
this._accessToken = accessToken ? accessToken.token : '';
95+
if (!this._accessToken) {
96+
throw new Error('Access token is null');
97+
}
98+
} catch (error) {
99+
console.error('Cannot get access token due to error: ' + error.toString());
100+
this.setState(ProviderState.SignedOut);
101+
this._accessToken = '';
102+
}
103+
return this._accessToken;
104+
}
105+
106+
/**
107+
* Performs the login using TeamsFx
108+
*
109+
* @returns {Promise<void>}
110+
* @memberof TeamsFxProvider
111+
*/
112+
public async login(): Promise<void> {
113+
const token: string = await this.getAccessToken();
114+
115+
if (!token) {
116+
await this.teamsfx.login(this.scopes);
117+
}
118+
119+
this._accessToken = token ?? (await this.getAccessToken());
120+
this.setState(this._accessToken ? ProviderState.SignedIn : ProviderState.SignedOut);
121+
}
122+
123+
private validateScopesType(value: any): void {
124+
// string
125+
if (typeof value === 'string' || value instanceof String) {
126+
return;
127+
}
128+
129+
// empty array
130+
if (Array.isArray(value) && value.length === 0) {
131+
return;
132+
}
133+
134+
// string array
135+
if (Array.isArray(value) && value.length > 0 && value.every(item => typeof item === 'string')) {
136+
return;
137+
}
138+
139+
throw new Error('The type of scopes is not valid, it must be string or string array');
140+
}
141+
142+
private getScopesArray(scopes: string | string[]): string[] {
143+
const scopesArray: string[] = typeof scopes === 'string' ? scopes.split(' ') : scopes;
144+
return scopesArray.filter(x => x !== null && x !== '');
145+
}
146+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './TeamsFxProvider';
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"extends": "../../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"outDir": "dist/es6",
5+
"sourceRoot": "src",
6+
"rootDir": "src",
7+
"composite": true
8+
},
9+
"references": [{ "path": "../../mgt-element" }],
10+
"include": ["src"],
11+
"exclude": ["src/bundle"]
12+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "./tsconfig",
3+
"compilerOptions": {
4+
"allowJs": true
5+
}
6+
}

readme.md

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,29 +23,29 @@
2323

2424
## Packages
2525

26-
| Package | Latest | Next |
27-
| - | - | - |
28-
| [`@microsoft/mgt`](https://www.npmjs.com/package/@microsoft/mgt) | <img src="https://img.shields.io/npm/v/@microsoft/mgt/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt/next.svg">
29-
| [`@microsoft/mgt-element`](https://www.npmjs.com/package/@microsoft/mgt-element) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-element/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-element/next.svg"> |
30-
| [`@microsoft/mgt-components`](https://www.npmjs.com/package/@microsoft/mgt-components) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-components/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-components/next.svg"> |
31-
| [`@microsoft/mgt-react`](https://www.npmjs.com/package/@microsoft/mgt-react) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-react/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-react/next.svg"> |
32-
| [`@microsoft/mgt-msal-provider`](https://www.npmjs.com/package/@microsoft/mgt-msal-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-msal-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-msal-provider/next.svg"> |
33-
| [`@microsoft/mgt-msal2-provider`](https://www.npmjs.com/package/@microsoft/mgt-msal2-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-msal2-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-msal2-provider/next.svg"> |
34-
| [`@microsoft/mgt-teams-provider`](https://www.npmjs.com/package/@microsoft/mgt-teams-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-teams-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-teams-provider/next.svg"> |
26+
| Package | Latest | Next |
27+
| ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
28+
| [`@microsoft/mgt`](https://www.npmjs.com/package/@microsoft/mgt) | <img src="https://img.shields.io/npm/v/@microsoft/mgt/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt/next.svg"> |
29+
| [`@microsoft/mgt-element`](https://www.npmjs.com/package/@microsoft/mgt-element) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-element/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-element/next.svg"> |
30+
| [`@microsoft/mgt-components`](https://www.npmjs.com/package/@microsoft/mgt-components) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-components/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-components/next.svg"> |
31+
| [`@microsoft/mgt-react`](https://www.npmjs.com/package/@microsoft/mgt-react) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-react/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-react/next.svg"> |
32+
| [`@microsoft/mgt-msal-provider`](https://www.npmjs.com/package/@microsoft/mgt-msal-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-msal-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-msal-provider/next.svg"> |
33+
| [`@microsoft/mgt-msal2-provider`](https://www.npmjs.com/package/@microsoft/mgt-msal2-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-msal2-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-msal2-provider/next.svg"> |
34+
| [`@microsoft/mgt-teams-provider`](https://www.npmjs.com/package/@microsoft/mgt-teams-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-teams-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-teams-provider/next.svg"> |
3535
| [`@microsoft/mgt-teams-msal2-provider`](https://www.npmjs.com/package/@microsoft/mgt-teams-msal2-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-teams-msal2-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-teams-msal2-provider/next.svg"> |
36-
| [`@microsoft/mgt-sharepoint-provider`](https://www.npmjs.com/package/@microsoft/mgt-sharepoint-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-sharepoint-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-sharepoint-provider/next.svg"> |
37-
| [`@microsoft/mgt-proxy-provider`](https://www.npmjs.com/package/@microsoft/mgt-proxy-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-proxy-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-proxy-provider/next.svg"> |
38-
| [`@microsoft/mgt-spfx`](https://www.npmjs.com/package/@microsoft/mgt-spfx) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-spfx/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-spfx/next.svg"> |
39-
| [`@microsoft/mgt-electron-provider`](https://www.npmjs.com/package/@microsoft/mgt-electron-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-electron-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-electron-provider/next.svg"> |
40-
36+
| [`@microsoft/mgt-teamsfx-provider`](https://www.npmjs.com/package/@microsoft/mgt-teamsfx-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-teamsfx-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-teamsfx-provider/next.svg"> |
37+
| [`@microsoft/mgt-sharepoint-provider`](https://www.npmjs.com/package/@microsoft/mgt-sharepoint-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-sharepoint-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-sharepoint-provider/next.svg"> |
38+
| [`@microsoft/mgt-proxy-provider`](https://www.npmjs.com/package/@microsoft/mgt-proxy-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-proxy-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-proxy-provider/next.svg"> |
39+
| [`@microsoft/mgt-spfx`](https://www.npmjs.com/package/@microsoft/mgt-spfx) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-spfx/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-spfx/next.svg"> |
40+
| [`@microsoft/mgt-electron-provider`](https://www.npmjs.com/package/@microsoft/mgt-electron-provider) | <img src="https://img.shields.io/npm/v/@microsoft/mgt-electron-provider/latest.svg"> | <img src="https://img.shields.io/npm/v/@microsoft/mgt-electron-provider/next.svg"> |
4141

4242
### Preview packages
4343

4444
In addition to the `@next` preview packages, we also ship packages under several other preview tags with various features in progress:
4545

46-
| Tag | Description |
47-
| - | - |
48-
| `next` | Next release - updated on each commit to `main` |
46+
| Tag | Description |
47+
| --------------- | ------------------------------------------------------------------------ |
48+
| `next` | Next release - updated on each commit to `main` |
4949
| `next.fluentui` | Next major release (v3) with components based on FluentUI web components |
5050

5151
To install these packages, use the tag as the version in your `npm i` command. Ex: `npm i @microsoft/[email protected]`. Make sure to install the same version for all mgt packages to avoid any conflicts. Keep in mind, these are features in preview and are not recommended for production use.
@@ -81,6 +81,7 @@ All web components are also available as React component - see [@microsoft/mgt-r
8181
* [SharePointProvider](https://docs.microsoft.com/graph/toolkit/providers/sharepoint)
8282
* [TeamsProvider](https://docs.microsoft.com/graph/toolkit/providers/teams)
8383
* [TeamsMsal2Provider](https://docs.microsoft.com/graph/toolkit/providers/teams-msal2)
84+
* [TeamsFxProvider](https://docs.microsoft.com/graph/toolkit/providers/teamsfx)
8485
* [ProxyProvider](https://docs.microsoft.com/graph/toolkit/providers/proxy)
8586
* [SimpleProvider](https://docs.microsoft.com/graph/toolkit/providers/custom)
8687
* [ElectronProvider](https://docs.microsoft.com/graph/toolkit/providers/electron)

0 commit comments

Comments
 (0)