@azure/msal-react 1.1.2 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MsalProvider.d.ts +3 -0
- package/dist/error/ReactAuthError.d.ts +16 -0
- package/dist/hooks/useAccount.d.ts +1 -1
- package/dist/hooks/useMsalAuthentication.d.ts +6 -4
- package/dist/msal-react.cjs.development.js +284 -129
- package/dist/msal-react.cjs.development.js.map +1 -1
- package/dist/msal-react.cjs.production.min.js +1 -1
- package/dist/msal-react.cjs.production.min.js.map +1 -1
- package/dist/msal-react.esm.js +286 -131
- package/dist/msal-react.esm.js.map +1 -1
- package/dist/packageMetadata.d.ts +1 -1
- package/dist/utils/utilities.d.ts +2 -0
- package/package.json +4 -4
- package/CHANGELOG.json +0 -632
- package/CHANGELOG.md +0 -144
package/dist/MsalProvider.d.ts
CHANGED
|
@@ -3,4 +3,7 @@ import { IPublicClientApplication } from "@azure/msal-browser";
|
|
|
3
3
|
export declare type MsalProviderProps = PropsWithChildren<{
|
|
4
4
|
instance: IPublicClientApplication;
|
|
5
5
|
}>;
|
|
6
|
+
/**
|
|
7
|
+
* MSAL context provider component. This must be rendered above any other components that use MSAL.
|
|
8
|
+
*/
|
|
6
9
|
export declare function MsalProvider({ instance, children }: MsalProviderProps): React.ReactElement;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AuthError } from "@azure/msal-browser";
|
|
2
|
+
export declare const ReactAuthErrorMessage: {
|
|
3
|
+
invalidInteractionType: {
|
|
4
|
+
code: string;
|
|
5
|
+
desc: string;
|
|
6
|
+
};
|
|
7
|
+
unableToFallbackToInteraction: {
|
|
8
|
+
code: string;
|
|
9
|
+
desc: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export declare class ReactAuthError extends AuthError {
|
|
13
|
+
constructor(errorCode: string, errorMessage?: string);
|
|
14
|
+
static createInvalidInteractionTypeError(): ReactAuthError;
|
|
15
|
+
static createUnableToFallbackToInteractionError(): ReactAuthError;
|
|
16
|
+
}
|
|
@@ -4,4 +4,4 @@ import { AccountIdentifiers } from "../types/AccountIdentifiers";
|
|
|
4
4
|
* Given 1 or more accountIdentifiers, returns the Account object if the user is signed-in
|
|
5
5
|
* @param accountIdentifiers
|
|
6
6
|
*/
|
|
7
|
-
export declare function useAccount(accountIdentifiers
|
|
7
|
+
export declare function useAccount(accountIdentifiers?: AccountIdentifiers): AccountInfo | null;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { PopupRequest, RedirectRequest, SsoSilentRequest, InteractionType, AuthenticationResult, AuthError } from "@azure/msal-browser";
|
|
1
|
+
import { PopupRequest, RedirectRequest, SsoSilentRequest, InteractionType, AuthenticationResult, AuthError, SilentRequest } from "@azure/msal-browser";
|
|
2
2
|
import { AccountIdentifiers } from "../types/AccountIdentifiers";
|
|
3
3
|
export declare type MsalAuthenticationResult = {
|
|
4
|
-
login:
|
|
4
|
+
login: (callbackInteractionType?: InteractionType | undefined, callbackRequest?: PopupRequest | RedirectRequest | SilentRequest) => Promise<AuthenticationResult | null>;
|
|
5
|
+
acquireToken: (callbackInteractionType?: InteractionType | undefined, callbackRequest?: SilentRequest | undefined) => Promise<AuthenticationResult | null>;
|
|
5
6
|
result: AuthenticationResult | null;
|
|
6
7
|
error: AuthError | null;
|
|
7
8
|
};
|
|
8
9
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
10
|
+
* If a user is not currently signed in this hook invokes a login. Failed logins can be retried using the login callback returned.
|
|
11
|
+
* If a user is currently signed in this hook attempts to acquire a token. Subsequent token requests can use the acquireToken callback returned.
|
|
12
|
+
* Optionally provide a request object to be used in the login/acquireToken call.
|
|
11
13
|
* Optionally provide a specific user that should be logged in.
|
|
12
14
|
* @param interactionType
|
|
13
15
|
* @param authenticationRequest
|
|
@@ -60,15 +60,101 @@ function accountArraysAreEqual(arrayA, arrayB) {
|
|
|
60
60
|
return elementA.homeAccountId === elementB.homeAccountId && elementA.localAccountId === elementB.localAccountId && elementA.username === elementB.username;
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
|
+
function getAccountByIdentifiers(allAccounts, accountIdentifiers) {
|
|
64
|
+
if (allAccounts.length > 0 && (accountIdentifiers.homeAccountId || accountIdentifiers.localAccountId || accountIdentifiers.username)) {
|
|
65
|
+
const matchedAccounts = allAccounts.filter(accountObj => {
|
|
66
|
+
if (accountIdentifiers.username && accountIdentifiers.username.toLowerCase() !== accountObj.username.toLowerCase()) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (accountIdentifiers.homeAccountId && accountIdentifiers.homeAccountId.toLowerCase() !== accountObj.homeAccountId.toLowerCase()) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (accountIdentifiers.localAccountId && accountIdentifiers.localAccountId.toLowerCase() !== accountObj.localAccountId.toLowerCase()) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return true;
|
|
79
|
+
});
|
|
80
|
+
return matchedAccounts[0] || null;
|
|
81
|
+
} else {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
63
85
|
|
|
64
86
|
/* eslint-disable header/header */
|
|
65
87
|
const name = "@azure/msal-react";
|
|
66
|
-
const version = "1.1
|
|
88
|
+
const version = "1.3.1";
|
|
67
89
|
|
|
68
90
|
/*
|
|
69
91
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
70
92
|
* Licensed under the MIT License.
|
|
71
93
|
*/
|
|
94
|
+
var MsalProviderActionType;
|
|
95
|
+
|
|
96
|
+
(function (MsalProviderActionType) {
|
|
97
|
+
MsalProviderActionType["UNBLOCK_INPROGRESS"] = "UNBLOCK_INPROGRESS";
|
|
98
|
+
MsalProviderActionType["EVENT"] = "EVENT";
|
|
99
|
+
})(MsalProviderActionType || (MsalProviderActionType = {}));
|
|
100
|
+
/**
|
|
101
|
+
* Returns the next inProgress and accounts state based on event message
|
|
102
|
+
* @param previousState
|
|
103
|
+
* @param action
|
|
104
|
+
*/
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
const reducer = (previousState, action) => {
|
|
108
|
+
const {
|
|
109
|
+
type,
|
|
110
|
+
payload
|
|
111
|
+
} = action;
|
|
112
|
+
let newAccounts = previousState.accounts;
|
|
113
|
+
let newInProgress = previousState.inProgress;
|
|
114
|
+
|
|
115
|
+
switch (type) {
|
|
116
|
+
case MsalProviderActionType.UNBLOCK_INPROGRESS:
|
|
117
|
+
if (previousState.inProgress === msalBrowser.InteractionStatus.Startup) {
|
|
118
|
+
newInProgress = msalBrowser.InteractionStatus.None;
|
|
119
|
+
payload.logger.info("MsalProvider - handleRedirectPromise resolved, setting inProgress to 'none'");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
break;
|
|
123
|
+
|
|
124
|
+
case MsalProviderActionType.EVENT:
|
|
125
|
+
const message = payload.message;
|
|
126
|
+
const status = msalBrowser.EventMessageUtils.getInteractionStatusFromEvent(message, previousState.inProgress);
|
|
127
|
+
|
|
128
|
+
if (status) {
|
|
129
|
+
payload.logger.info(`MsalProvider - ${message.eventType} results in setting inProgress from ${previousState.inProgress} to ${status}`);
|
|
130
|
+
newInProgress = status;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
break;
|
|
134
|
+
|
|
135
|
+
default:
|
|
136
|
+
throw new Error(`Unknown action type: ${type}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const currentAccounts = payload.instance.getAllAccounts();
|
|
140
|
+
|
|
141
|
+
if (!accountArraysAreEqual(currentAccounts, previousState.accounts)) {
|
|
142
|
+
payload.logger.info("MsalProvider - updating account state");
|
|
143
|
+
newAccounts = currentAccounts;
|
|
144
|
+
} else {
|
|
145
|
+
payload.logger.verbose("MsalProvider - no account changes");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { ...previousState,
|
|
149
|
+
inProgress: newInProgress,
|
|
150
|
+
accounts: newAccounts
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* MSAL context provider component. This must be rendered above any other components that use MSAL.
|
|
155
|
+
*/
|
|
156
|
+
|
|
157
|
+
|
|
72
158
|
function MsalProvider({
|
|
73
159
|
instance,
|
|
74
160
|
children
|
|
@@ -79,56 +165,24 @@ function MsalProvider({
|
|
|
79
165
|
|
|
80
166
|
const logger = React.useMemo(() => {
|
|
81
167
|
return instance.getLogger().clone(name, version);
|
|
82
|
-
}, [instance]);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const inProgressRef = React.useRef(inProgress);
|
|
89
|
-
React.useEffect(() => {
|
|
90
|
-
const callbackId = instance.addEventCallback(message => {
|
|
91
|
-
switch (message.eventType) {
|
|
92
|
-
case msalBrowser.EventType.ACCOUNT_ADDED:
|
|
93
|
-
case msalBrowser.EventType.ACCOUNT_REMOVED:
|
|
94
|
-
case msalBrowser.EventType.LOGIN_SUCCESS:
|
|
95
|
-
case msalBrowser.EventType.SSO_SILENT_SUCCESS:
|
|
96
|
-
case msalBrowser.EventType.HANDLE_REDIRECT_END:
|
|
97
|
-
case msalBrowser.EventType.LOGIN_FAILURE:
|
|
98
|
-
case msalBrowser.EventType.SSO_SILENT_FAILURE:
|
|
99
|
-
case msalBrowser.EventType.LOGOUT_END:
|
|
100
|
-
case msalBrowser.EventType.ACQUIRE_TOKEN_SUCCESS:
|
|
101
|
-
case msalBrowser.EventType.ACQUIRE_TOKEN_FAILURE:
|
|
102
|
-
const currentAccounts = instance.getAllAccounts();
|
|
103
|
-
|
|
104
|
-
if (!accountArraysAreEqual(currentAccounts, accounts)) {
|
|
105
|
-
logger.info("MsalProvider - updating account state");
|
|
106
|
-
setAccounts(currentAccounts);
|
|
107
|
-
} else {
|
|
108
|
-
logger.info("MsalProvider - no account changes");
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
break;
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
logger.verbose(`MsalProvider - Registered event callback with id: ${callbackId}`);
|
|
115
|
-
return () => {
|
|
116
|
-
// Remove callback when component unmounts or accounts change
|
|
117
|
-
if (callbackId) {
|
|
118
|
-
logger.verbose(`MsalProvider - Removing event callback ${callbackId}`);
|
|
119
|
-
instance.removeEventCallback(callbackId);
|
|
120
|
-
}
|
|
168
|
+
}, [instance]);
|
|
169
|
+
const [state, updateState] = React.useReducer(reducer, undefined, () => {
|
|
170
|
+
// Lazy initialization of the initial state
|
|
171
|
+
return {
|
|
172
|
+
inProgress: msalBrowser.InteractionStatus.Startup,
|
|
173
|
+
accounts: instance.getAllAccounts()
|
|
121
174
|
};
|
|
122
|
-
}
|
|
175
|
+
});
|
|
123
176
|
React.useEffect(() => {
|
|
124
177
|
const callbackId = instance.addEventCallback(message => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
178
|
+
updateState({
|
|
179
|
+
payload: {
|
|
180
|
+
instance,
|
|
181
|
+
logger,
|
|
182
|
+
message
|
|
183
|
+
},
|
|
184
|
+
type: MsalProviderActionType.EVENT
|
|
185
|
+
});
|
|
132
186
|
});
|
|
133
187
|
logger.verbose(`MsalProvider - Registered event callback with id: ${callbackId}`);
|
|
134
188
|
instance.handleRedirectPromise().catch(() => {
|
|
@@ -139,12 +193,16 @@ function MsalProvider({
|
|
|
139
193
|
* If handleRedirectPromise returns a cached promise the necessary events may not be fired
|
|
140
194
|
* This is a fallback to prevent inProgress from getting stuck in 'startup'
|
|
141
195
|
*/
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
196
|
+
updateState({
|
|
197
|
+
payload: {
|
|
198
|
+
instance,
|
|
199
|
+
logger
|
|
200
|
+
},
|
|
201
|
+
type: MsalProviderActionType.UNBLOCK_INPROGRESS
|
|
202
|
+
});
|
|
146
203
|
});
|
|
147
204
|
return () => {
|
|
205
|
+
// Remove callback when component unmounts or accounts change
|
|
148
206
|
if (callbackId) {
|
|
149
207
|
logger.verbose(`MsalProvider - Removing event callback ${callbackId}`);
|
|
150
208
|
instance.removeEventCallback(callbackId);
|
|
@@ -153,8 +211,8 @@ function MsalProvider({
|
|
|
153
211
|
}, [instance, logger]);
|
|
154
212
|
const contextValue = {
|
|
155
213
|
instance,
|
|
156
|
-
inProgress,
|
|
157
|
-
accounts,
|
|
214
|
+
inProgress: state.inProgress,
|
|
215
|
+
accounts: state.accounts,
|
|
158
216
|
logger
|
|
159
217
|
};
|
|
160
218
|
return React__default.createElement(MsalContext.Provider, {
|
|
@@ -177,61 +235,9 @@ const useMsal = () => React.useContext(MsalContext);
|
|
|
177
235
|
* Licensed under the MIT License.
|
|
178
236
|
*/
|
|
179
237
|
|
|
180
|
-
function
|
|
181
|
-
const allAccounts = instance.getAllAccounts();
|
|
182
|
-
|
|
183
|
-
if (allAccounts.length > 0 && (accountIdentifiers.homeAccountId || accountIdentifiers.localAccountId || accountIdentifiers.username)) {
|
|
184
|
-
const matchedAccounts = allAccounts.filter(accountObj => {
|
|
185
|
-
if (accountIdentifiers.username && accountIdentifiers.username.toLowerCase() !== accountObj.username.toLowerCase()) {
|
|
186
|
-
return false;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (accountIdentifiers.homeAccountId && accountIdentifiers.homeAccountId.toLowerCase() !== accountObj.homeAccountId.toLowerCase()) {
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (accountIdentifiers.localAccountId && accountIdentifiers.localAccountId.toLowerCase() !== accountObj.localAccountId.toLowerCase()) {
|
|
194
|
-
return false;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return true;
|
|
198
|
-
});
|
|
199
|
-
return matchedAccounts[0] || null;
|
|
200
|
-
} else {
|
|
201
|
-
return null;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Given 1 or more accountIdentifiers, returns the Account object if the user is signed-in
|
|
206
|
-
* @param accountIdentifiers
|
|
207
|
-
*/
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
function useAccount(accountIdentifiers) {
|
|
211
|
-
const {
|
|
212
|
-
instance,
|
|
213
|
-
inProgress
|
|
214
|
-
} = useMsal();
|
|
215
|
-
const initialStateValue = inProgress === msalBrowser.InteractionStatus.Startup ? null : getAccount(instance, accountIdentifiers);
|
|
216
|
-
const [account, setAccount] = React.useState(initialStateValue);
|
|
217
|
-
React.useEffect(() => {
|
|
218
|
-
const currentAccount = getAccount(instance, accountIdentifiers);
|
|
219
|
-
|
|
220
|
-
if (!msalBrowser.AccountEntity.accountInfoIsEqual(account, currentAccount, true)) {
|
|
221
|
-
setAccount(currentAccount);
|
|
222
|
-
}
|
|
223
|
-
}, [inProgress, accountIdentifiers, instance, account]);
|
|
224
|
-
return account;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/*
|
|
228
|
-
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
229
|
-
* Licensed under the MIT License.
|
|
230
|
-
*/
|
|
231
|
-
|
|
232
|
-
function isAuthenticated(allAccounts, account, matchAccount) {
|
|
238
|
+
function isAuthenticated(allAccounts, matchAccount) {
|
|
233
239
|
if (matchAccount && (matchAccount.username || matchAccount.homeAccountId || matchAccount.localAccountId)) {
|
|
234
|
-
return !!
|
|
240
|
+
return !!getAccountByIdentifiers(allAccounts, matchAccount);
|
|
235
241
|
}
|
|
236
242
|
|
|
237
243
|
return allAccounts.length > 0;
|
|
@@ -244,15 +250,12 @@ function isAuthenticated(allAccounts, account, matchAccount) {
|
|
|
244
250
|
|
|
245
251
|
function useIsAuthenticated(matchAccount) {
|
|
246
252
|
const {
|
|
247
|
-
accounts: allAccounts
|
|
248
|
-
inProgress
|
|
253
|
+
accounts: allAccounts
|
|
249
254
|
} = useMsal();
|
|
250
|
-
const
|
|
251
|
-
const initialStateValue = inProgress === msalBrowser.InteractionStatus.Startup ? false : isAuthenticated(allAccounts, account, matchAccount);
|
|
252
|
-
const [hasAuthenticated, setHasAuthenticated] = React.useState(initialStateValue);
|
|
255
|
+
const [hasAuthenticated, setHasAuthenticated] = React.useState(() => isAuthenticated(allAccounts, matchAccount));
|
|
253
256
|
React.useEffect(() => {
|
|
254
|
-
setHasAuthenticated(isAuthenticated(allAccounts,
|
|
255
|
-
}, [allAccounts,
|
|
257
|
+
setHasAuthenticated(isAuthenticated(allAccounts, matchAccount));
|
|
258
|
+
}, [allAccounts, matchAccount]);
|
|
256
259
|
return hasAuthenticated;
|
|
257
260
|
}
|
|
258
261
|
|
|
@@ -320,13 +323,86 @@ function UnauthenticatedTemplate({
|
|
|
320
323
|
return null;
|
|
321
324
|
}
|
|
322
325
|
|
|
326
|
+
/*
|
|
327
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
328
|
+
* Licensed under the MIT License.
|
|
329
|
+
*/
|
|
330
|
+
|
|
331
|
+
function getAccount(instance, accountIdentifiers) {
|
|
332
|
+
if (!accountIdentifiers || !accountIdentifiers.homeAccountId && !accountIdentifiers.localAccountId && !accountIdentifiers.username) {
|
|
333
|
+
// If no account identifiers are provided, return active account
|
|
334
|
+
return instance.getActiveAccount();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return getAccountByIdentifiers(instance.getAllAccounts(), accountIdentifiers);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Given 1 or more accountIdentifiers, returns the Account object if the user is signed-in
|
|
341
|
+
* @param accountIdentifiers
|
|
342
|
+
*/
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
function useAccount(accountIdentifiers) {
|
|
346
|
+
const {
|
|
347
|
+
instance,
|
|
348
|
+
inProgress,
|
|
349
|
+
logger
|
|
350
|
+
} = useMsal();
|
|
351
|
+
const [account, setAccount] = React.useState(() => getAccount(instance, accountIdentifiers));
|
|
352
|
+
React.useEffect(() => {
|
|
353
|
+
setAccount(currentAccount => {
|
|
354
|
+
const nextAccount = getAccount(instance, accountIdentifiers);
|
|
355
|
+
|
|
356
|
+
if (!msalBrowser.AccountEntity.accountInfoIsEqual(currentAccount, nextAccount, true)) {
|
|
357
|
+
logger.info("useAccount - Updating account");
|
|
358
|
+
return nextAccount;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return currentAccount;
|
|
362
|
+
});
|
|
363
|
+
}, [inProgress, accountIdentifiers, instance, logger]);
|
|
364
|
+
return account;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/*
|
|
368
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
369
|
+
* Licensed under the MIT License.
|
|
370
|
+
*/
|
|
371
|
+
const ReactAuthErrorMessage = {
|
|
372
|
+
invalidInteractionType: {
|
|
373
|
+
code: "invalid_interaction_type",
|
|
374
|
+
desc: "The provided interaction type is invalid."
|
|
375
|
+
},
|
|
376
|
+
unableToFallbackToInteraction: {
|
|
377
|
+
code: "unable_to_fallback_to_interaction",
|
|
378
|
+
desc: "Interaction is required but another interaction is already in progress. Please try again when the current interaction is complete."
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
class ReactAuthError extends msalBrowser.AuthError {
|
|
382
|
+
constructor(errorCode, errorMessage) {
|
|
383
|
+
super(errorCode, errorMessage);
|
|
384
|
+
Object.setPrototypeOf(this, ReactAuthError.prototype);
|
|
385
|
+
this.name = "ReactAuthError";
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
static createInvalidInteractionTypeError() {
|
|
389
|
+
return new ReactAuthError(ReactAuthErrorMessage.invalidInteractionType.code, ReactAuthErrorMessage.invalidInteractionType.desc);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
static createUnableToFallbackToInteractionError() {
|
|
393
|
+
return new ReactAuthError(ReactAuthErrorMessage.unableToFallbackToInteraction.code, ReactAuthErrorMessage.unableToFallbackToInteraction.desc);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
}
|
|
397
|
+
|
|
323
398
|
/*
|
|
324
399
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
325
400
|
* Licensed under the MIT License.
|
|
326
401
|
*/
|
|
327
402
|
/**
|
|
328
|
-
*
|
|
329
|
-
*
|
|
403
|
+
* If a user is not currently signed in this hook invokes a login. Failed logins can be retried using the login callback returned.
|
|
404
|
+
* If a user is currently signed in this hook attempts to acquire a token. Subsequent token requests can use the acquireToken callback returned.
|
|
405
|
+
* Optionally provide a request object to be used in the login/acquireToken call.
|
|
330
406
|
* Optionally provide a specific user that should be logged in.
|
|
331
407
|
* @param interactionType
|
|
332
408
|
* @param authenticationRequest
|
|
@@ -340,8 +416,28 @@ function useMsalAuthentication(interactionType, authenticationRequest, accountId
|
|
|
340
416
|
logger
|
|
341
417
|
} = useMsal();
|
|
342
418
|
const isAuthenticated = useIsAuthenticated(accountIdentifiers);
|
|
343
|
-
const
|
|
344
|
-
const [
|
|
419
|
+
const account = useAccount(accountIdentifiers);
|
|
420
|
+
const [[result, error], setResponse] = React.useState([null, null]); // Boolean used to check if interaction is in progress in acquireTokenSilent fallback. Use Ref instead of state to prevent acquireToken function from being regenerated on each change to interactionInProgress value
|
|
421
|
+
|
|
422
|
+
const interactionInProgress = React.useRef(inProgress !== msalBrowser.InteractionStatus.None);
|
|
423
|
+
React.useEffect(() => {
|
|
424
|
+
interactionInProgress.current = inProgress !== msalBrowser.InteractionStatus.None;
|
|
425
|
+
}, [inProgress]); // Flag used to control when the hook calls login/acquireToken
|
|
426
|
+
|
|
427
|
+
const shouldAcquireToken = React.useRef(true);
|
|
428
|
+
React.useEffect(() => {
|
|
429
|
+
if (!!error) {
|
|
430
|
+
// Errors should be handled by consuming component
|
|
431
|
+
shouldAcquireToken.current = false;
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (!!result) {
|
|
436
|
+
// Token has already been acquired, consuming component/application is responsible for renewing
|
|
437
|
+
shouldAcquireToken.current = false;
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
}, [error, result]);
|
|
345
441
|
const login = React.useCallback(async (callbackInteractionType, callbackRequest) => {
|
|
346
442
|
const loginType = callbackInteractionType || interactionType;
|
|
347
443
|
const loginRequest = callbackRequest || authenticationRequest;
|
|
@@ -361,9 +457,59 @@ function useMsalAuthentication(interactionType, authenticationRequest, accountId
|
|
|
361
457
|
return instance.ssoSilent(loginRequest);
|
|
362
458
|
|
|
363
459
|
default:
|
|
364
|
-
throw
|
|
460
|
+
throw ReactAuthError.createInvalidInteractionTypeError();
|
|
365
461
|
}
|
|
366
462
|
}, [instance, interactionType, authenticationRequest, logger]);
|
|
463
|
+
const acquireToken = React.useCallback(async (callbackInteractionType, callbackRequest) => {
|
|
464
|
+
const fallbackInteractionType = callbackInteractionType || interactionType;
|
|
465
|
+
let tokenRequest;
|
|
466
|
+
|
|
467
|
+
if (callbackRequest) {
|
|
468
|
+
logger.trace("useMsalAuthentication - acquireToken - Using request provided in the callback");
|
|
469
|
+
tokenRequest = { ...callbackRequest
|
|
470
|
+
};
|
|
471
|
+
} else if (authenticationRequest) {
|
|
472
|
+
logger.trace("useMsalAuthentication - acquireToken - Using request provided in the hook");
|
|
473
|
+
tokenRequest = { ...authenticationRequest,
|
|
474
|
+
scopes: authenticationRequest.scopes || msalBrowser.OIDC_DEFAULT_SCOPES
|
|
475
|
+
};
|
|
476
|
+
} else {
|
|
477
|
+
logger.trace("useMsalAuthentication - acquireToken - No request object provided, using default request.");
|
|
478
|
+
tokenRequest = {
|
|
479
|
+
scopes: msalBrowser.OIDC_DEFAULT_SCOPES
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (!tokenRequest.account && account) {
|
|
484
|
+
logger.trace("useMsalAuthentication - acquireToken - Attaching account to request");
|
|
485
|
+
tokenRequest.account = account;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const getToken = async () => {
|
|
489
|
+
logger.verbose("useMsalAuthentication - Calling acquireTokenSilent");
|
|
490
|
+
return instance.acquireTokenSilent(tokenRequest).catch(async e => {
|
|
491
|
+
if (e instanceof msalBrowser.InteractionRequiredAuthError) {
|
|
492
|
+
if (!interactionInProgress.current) {
|
|
493
|
+
logger.error("useMsalAuthentication - Interaction required, falling back to interaction");
|
|
494
|
+
return login(fallbackInteractionType, tokenRequest);
|
|
495
|
+
} else {
|
|
496
|
+
logger.error("useMsalAuthentication - Interaction required but is already in progress. Please try again, if needed, after interaction completes.");
|
|
497
|
+
throw ReactAuthError.createUnableToFallbackToInteractionError();
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
throw e;
|
|
502
|
+
});
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
return getToken().then(response => {
|
|
506
|
+
setResponse([response, null]);
|
|
507
|
+
return response;
|
|
508
|
+
}).catch(e => {
|
|
509
|
+
setResponse([null, e]);
|
|
510
|
+
throw e;
|
|
511
|
+
});
|
|
512
|
+
}, [instance, interactionType, authenticationRequest, logger, account, login]);
|
|
367
513
|
React.useEffect(() => {
|
|
368
514
|
const callbackId = instance.addEventCallback(message => {
|
|
369
515
|
switch (message.eventType) {
|
|
@@ -393,18 +539,27 @@ function useMsalAuthentication(interactionType, authenticationRequest, accountId
|
|
|
393
539
|
};
|
|
394
540
|
}, [instance, logger]);
|
|
395
541
|
React.useEffect(() => {
|
|
396
|
-
if (
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
542
|
+
if (shouldAcquireToken.current && inProgress === msalBrowser.InteractionStatus.None) {
|
|
543
|
+
shouldAcquireToken.current = false;
|
|
544
|
+
|
|
545
|
+
if (!isAuthenticated) {
|
|
546
|
+
logger.info("useMsalAuthentication - No user is authenticated, attempting to login");
|
|
547
|
+
login().catch(() => {
|
|
548
|
+
// Errors are saved in state above
|
|
549
|
+
return;
|
|
550
|
+
});
|
|
551
|
+
} else if (account) {
|
|
552
|
+
logger.info("useMsalAuthentication - User is authenticated, attempting to acquire token");
|
|
553
|
+
acquireToken().catch(() => {
|
|
554
|
+
// Errors are saved in state above
|
|
555
|
+
return;
|
|
556
|
+
});
|
|
557
|
+
}
|
|
404
558
|
}
|
|
405
|
-
}, [isAuthenticated,
|
|
559
|
+
}, [isAuthenticated, account, inProgress, login, acquireToken, logger]);
|
|
406
560
|
return {
|
|
407
561
|
login,
|
|
562
|
+
acquireToken,
|
|
408
563
|
result,
|
|
409
564
|
error
|
|
410
565
|
};
|