3
3
4
4
/* This file provides MSAL auth configuration to get access token through nested app authentication. */
5
5
6
- /* global console */
6
+ /* global console, Office */
7
7
8
- import { PublicClientNext , type IPublicClientApplication } from "@azure/msal-browser" ;
8
+ import {
9
+ type AccountInfo ,
10
+ PublicClientNext ,
11
+ type IPublicClientApplication ,
12
+ Configuration ,
13
+ LogLevel ,
14
+ } from "@azure/msal-browser" ;
9
15
10
16
export { AccountManager } ;
11
17
18
+ interface AuthContext {
19
+ loginHint : string ;
20
+ userPrincipalName : string ;
21
+ userObjectId : string ;
22
+ tenantId : string ;
23
+ }
24
+
12
25
const applicationId = "Enter_the_Application_Id_Here" ;
13
26
14
- const msalConfig = {
15
- auth : {
16
- clientId : applicationId ,
17
- authority : "https://login.microsoftonline.com/common" ,
18
- supportsNestedAppAuth : true ,
19
- } ,
20
- } ;
27
+ function getMsalConfig ( enableDebugLogging : boolean ) {
28
+ const msalConfig : Configuration = {
29
+ auth : {
30
+ clientId : applicationId ,
31
+ authority : "https://login.microsoftonline.com/common" ,
32
+ supportsNestedAppAuth : true ,
33
+ } ,
34
+ system : { } ,
35
+ } ;
36
+ if ( enableDebugLogging ) {
37
+ msalConfig . system . loggerOptions = {
38
+ logLevel : LogLevel . Verbose ,
39
+ loggerCallback : ( level : LogLevel , message : string ) => {
40
+ switch ( level ) {
41
+ case LogLevel . Error :
42
+ console . error ( message ) ;
43
+ return ;
44
+ case LogLevel . Info :
45
+ console . info ( message ) ;
46
+ return ;
47
+ case LogLevel . Verbose :
48
+ console . debug ( message ) ;
49
+ return ;
50
+ case LogLevel . Warning :
51
+ console . warn ( message ) ;
52
+ return ;
53
+ }
54
+ } ,
55
+ piiLoggingEnabled : true ,
56
+ } ;
57
+ }
58
+ return msalConfig ;
59
+ }
21
60
22
61
// Encapsulate functions for getting user account and token information.
23
62
class AccountManager {
24
- loginHint : string = "" ;
25
- pca : IPublicClientApplication | undefined = undefined ;
63
+ private pca : IPublicClientApplication | undefined = undefined ;
64
+ private account : AccountInfo | undefined = undefined ;
65
+ private loginHint : string | undefined = undefined ;
26
66
27
67
// Initialize MSAL public client application.
28
- async initialize ( loginHint : string ) {
29
- this . loginHint = loginHint ;
30
- this . pca = await PublicClientNext . createPublicClientApplication ( msalConfig ) ;
68
+ async initialize ( ) {
69
+ // If auth is not working, enable debug logging to help diagnose.
70
+ this . pca = await PublicClientNext . createPublicClientApplication ( getMsalConfig ( false ) ) ;
71
+
72
+ // Initialize account by matching account known by Outlook with MSAL.js
73
+ let username = "" ;
74
+ let tenantId = "" ;
75
+ let localAccountId = "" ;
76
+ try {
77
+ const authContext : AuthContext = await Office . auth . getAuthContext ( ) ;
78
+ username = authContext . userPrincipalName ;
79
+ tenantId = authContext . tenantId ;
80
+ localAccountId = authContext . userObjectId ;
81
+ this . loginHint = authContext . loginHint || authContext . userPrincipalName ;
82
+ } catch {
83
+ // Intentionally empty catch block.
84
+ }
85
+
86
+ if ( ! this . loginHint ) {
87
+ const accountType = Office . context . mailbox . userProfile . accountType ;
88
+ this . loginHint =
89
+ accountType === "office365" || accountType === "outlookCom"
90
+ ? Office . context . mailbox . userProfile . emailAddress
91
+ : "" ;
92
+ }
93
+
94
+ // Try to use auth context to find account
95
+ this . account = this . pca . getAllAccounts ( ) . find ( ( account ) => {
96
+ return (
97
+ ( localAccountId && account . localAccountId ?. toLowerCase ( ) === localAccountId . toLowerCase ( ) ) ||
98
+ ( account . username &&
99
+ account . username === username . toLowerCase ( ) &&
100
+ account . tenantId ?. toLowerCase ( ) === tenantId )
101
+ ) ;
102
+ } ) ;
31
103
}
32
104
33
105
/**
34
- *
106
+ *
35
107
* @param scopes the minimum scopes needed.
36
108
* @returns An access token.
37
109
*/
@@ -41,10 +113,10 @@ class AccountManager {
41
113
}
42
114
43
115
/**
44
- *
116
+ *
45
117
* Uses MSAL and nested app authentication to get the user account from Office SSO.
46
118
* This demonstrates how to work with user identity from the token.
47
- *
119
+ *
48
120
* @param scopes The minimum scopes needed.
49
121
* @returns The user account data (including identity).
50
122
*/
@@ -57,27 +129,31 @@ class AccountManager {
57
129
const tokenRequest = {
58
130
scopes : scopes ,
59
131
loginHint : this . loginHint ,
132
+ account : this . account ,
60
133
} ;
61
134
62
135
try {
63
136
console . log ( "Trying to acquire token silently..." ) ;
64
137
65
138
//acquireTokenSilent requires an active account. Check if one exists, otherwise use ssoSilent.
66
- const account = this . pca . getActiveAccount ( ) ;
67
- const userAccount = account ? await this . pca . acquireTokenSilent ( tokenRequest ) : await this . pca . ssoSilent ( tokenRequest ) ;
139
+ const authResult = this . account
140
+ ? await this . pca . acquireTokenSilent ( tokenRequest )
141
+ : await this . pca . ssoSilent ( tokenRequest ) ;
142
+ this . account = authResult . account ;
68
143
69
144
console . log ( "Acquired token silently." ) ;
70
- return userAccount ;
145
+ return authResult ;
71
146
} catch ( error ) {
72
147
console . log ( `Unable to acquire token silently: ${ error } ` ) ;
73
148
}
74
149
75
150
// Acquire token silent failure. Send an interactive request via popup.
76
151
try {
77
152
console . log ( "Trying to acquire token interactively..." ) ;
78
- const userAccount = await this . pca . acquireTokenPopup ( tokenRequest ) ;
153
+ const authResult = await this . pca . acquireTokenPopup ( tokenRequest ) ;
154
+ this . account = authResult . account ;
79
155
console . log ( "Acquired token interactively." ) ;
80
- return userAccount ;
156
+ return authResult ;
81
157
} catch ( popupError ) {
82
158
// Acquire token interactive failure.
83
159
console . log ( `Unable to acquire token interactively: ${ popupError } ` ) ;
0 commit comments