Skip to content

Commit 599b2e8

Browse files
authored
Merge pull request #155460 from tnorling/update-scenario-spa-docs
Update scenario-spa docs
2 parents 08ca507 + 9124067 commit 599b2e8

File tree

3 files changed

+527
-21
lines changed

3 files changed

+527
-21
lines changed

articles/active-directory/develop/scenario-spa-acquire-token.md

Lines changed: 220 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,52 @@ The silent token requests to Azure AD might fail for reasons like an expired Azu
2727

2828
## Choose between a pop-up or redirect experience
2929

30-
You can't use both the pop-up and redirect methods in your application. The choice between a pop-up or redirect experience depends on your application flow:
30+
The choice between a pop-up or redirect experience depends on your application flow:
3131

32-
* If you don't want users to move away from your main application page during authentication, we recommended the pop-up method. Because the authentication redirect happens in a pop-up window, the state of the main application is preserved.
32+
* If you don't want users to move away from your main application page during authentication, we recommend the pop-up method. Because the authentication redirect happens in a pop-up window, the state of the main application is preserved.
3333

34-
* If users have browser constraints or policies where pop-ups windows are disabled, you can use the redirect method. Use the redirect method with the Internet Explorer browser, because there are [known issues with pop-up windows on Internet Explorer](https://github.com/AzureAD/microsoft-authentication-library-for-js/wiki/Known-issues-on-IE-and-Edge-Browser).
34+
* If users have browser constraints or policies where pop-up windows are disabled, you can use the redirect method. Use the redirect method with the Internet Explorer browser, because there are [known issues with pop-up windows on Internet Explorer](https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/internet-explorer.md#popups).
3535

3636
You can set the API scopes that you want the access token to include when it's building the access token request. Note that all requested scopes might not be granted in the access token. That depends on the user's consent.
3737

3838
## Acquire a token with a pop-up window
3939

40-
# [JavaScript](#tab/javascript)
40+
# [JavaScript (MSAL.js v2)](#tab/javascript2)
41+
42+
The following code combines the previously described pattern with the methods for a pop-up experience:
43+
44+
```javascript
45+
// MSAL.js v2 exposes several account APIs, logic to determine which account to use is the responsibility of the developer
46+
const account = publicClientApplication.getAllAccounts()[0];
47+
48+
const accessTokenRequest = {
49+
scopes: ["user.read"],
50+
account: account
51+
}
52+
53+
publicClientApplication.acquireTokenSilent(accessTokenRequest).then(function(accessTokenResponse) {
54+
// Acquire token silent success
55+
let accessToken = accessTokenResponse.accessToken;
56+
// Call your API with token
57+
callApi(accessToken);
58+
}).catch(function (error) {
59+
//Acquire token silent failure, and send an interactive request
60+
if (error instanceof InteractionRequiredAuthError) {
61+
publicClientApplication.acquireTokenPopup(accessTokenRequest).then(function(accessTokenResponse) {
62+
// Acquire token interactive success
63+
let accessToken = accessTokenResponse.accessToken;
64+
// Call your API with token
65+
callApi(accessToken);
66+
}).catch(function(error) {
67+
// Acquire token interactive failure
68+
console.log(error);
69+
});
70+
}
71+
console.log(error);
72+
});
73+
```
74+
75+
# [JavaScript (MSAL.js v1)](#tab/javascript1)
4176

4277
The following code combines the previously described pattern with the methods for a pop-up experience:
4378

@@ -126,11 +161,123 @@ ngOnDestroy() {
126161

127162
Alternatively, you can explicitly acquire tokens by using the acquire-token methods as described in the core MSAL.js library.
128163

164+
# [React](#tab/react)
165+
166+
The following code combines the previously described pattern with the methods for a pop-up experience:
167+
168+
```javascript
169+
import { InteractionRequiredAuthError, InteractionStatus } from "@azure/msal-browser";
170+
import { AuthenticatedTemplate, useMsal } from "@azure/msal-react";
171+
172+
function ProtectedComponent() {
173+
const { instance, inProgress, accounts } = useMsal();
174+
const [apiData, setApiData] = useState(null);
175+
176+
177+
useEffect(() => {
178+
if (!apiData && inProgress === InteractionStatus.None) {
179+
const accessTokenRequest = {
180+
scopes: ["user.read"],
181+
account: accounts[0]
182+
}
183+
instance.acquireTokenSilent(accessTokenRequest).then((accessTokenResponse) => {
184+
// Acquire token silent success
185+
let accessToken = accessTokenResponse.accessToken;
186+
// Call your API with token
187+
callApi(accessToken).then((response) => { setApiData(response) });
188+
}).catch((error) => {
189+
if (error instanceof InteractionRequiredAuthError) {
190+
instance.acquireTokenPopup(accessTokenRequest).then(function(accessTokenResponse) {
191+
// Acquire token interactive success
192+
let accessToken = accessTokenResponse.accessToken;
193+
// Call your API with token
194+
callApi(accessToken).then((response) => { setApiData(response) });
195+
}).catch(function(error) {
196+
// Acquire token interactive failure
197+
console.log(error);
198+
});
199+
}
200+
console.log(error);
201+
})
202+
}
203+
}, [instance, accounts, inProgress, apiData]);
204+
205+
return <p>Return your protected content here: {apiData}</p>
206+
}
207+
208+
function App() {
209+
return (
210+
<AuthenticatedTemplate>
211+
<ProtectedComponent />
212+
</ AuthenticatedTemplate>
213+
)
214+
}
215+
```
216+
217+
Alternatively, if you need to acquire a token outside of a React component you can call `acquireTokenSilent` but should not fallback to interaction if it fails. All interaction should take place underneath the `MsalProvider` component in your component tree.
218+
219+
```javascript
220+
// MSAL.js v2 exposes several account APIs, logic to determine which account to use is the responsibility of the developer
221+
const account = publicClientApplication.getAllAccounts()[0];
222+
223+
const accessTokenRequest = {
224+
scopes: ["user.read"],
225+
account: account
226+
}
227+
228+
// Use the same publicClientApplication instance provided to MsalProvider
229+
publicClientApplication.acquireTokenSilent(accessTokenRequest).then(function(accessTokenResponse) {
230+
// Acquire token silent success
231+
let accessToken = accessTokenResponse.accessToken;
232+
// Call your API with token
233+
callApi(accessToken);
234+
}).catch(function (error) {
235+
//Acquire token silent failure
236+
console.log(error);
237+
});
238+
```
239+
129240
---
130241

131242
## Acquire a token with a redirect
132243

133-
# [JavaScript](#tab/javascript)
244+
# [JavaScript (MSAL.js v2)](#tab/javascript2)
245+
246+
The following pattern is as described earlier but shown with a redirect method to acquire tokens interactively. You'll need to call and await `handleRedirectPromise` on page load.
247+
248+
```javascript
249+
const redirectResponse = await publicClientApplication.handleRedirectPromise();
250+
if (redirectResponse !== null) {
251+
// Acquire token silent success
252+
let accessToken = redirectResponse.accessToken;
253+
// Call your API with token
254+
callApi(accessToken);
255+
} else {
256+
// MSAL.js v2 exposes several account APIs, logic to determine which account to use is the responsibility of the developer
257+
const account = publicClientApplication.getAllAccounts()[0];
258+
259+
const accessTokenRequest = {
260+
scopes: ["user.read"],
261+
account: account
262+
}
263+
264+
publicClientApplication.acquireTokenSilent(accessTokenRequest).then(function(accessTokenResponse) {
265+
// Acquire token silent success
266+
// Call API with token
267+
let accessToken = accessTokenResponse.accessToken;
268+
// Call your API with token
269+
callApi(accessToken);
270+
}).catch(function (error) {
271+
//Acquire token silent failure, and send an interactive request
272+
console.log(error);
273+
if (error instanceof InteractionRequiredAuthError) {
274+
publicClientApplication.acquireTokenRedirect(accessTokenRequest);
275+
}
276+
});
277+
}
278+
```
279+
280+
# [JavaScript (MSAL.js v1)](#tab/javascript1)
134281

135282
The following pattern is as described earlier but shown with a redirect method to acquire tokens interactively. You'll need to register the redirect callback as mentioned earlier.
136283

@@ -192,6 +339,74 @@ To learn more, see [Optional claims](active-directory-optional-claims.md).
192339
193340
This code is the same as described earlier.
194341
342+
# [React](#tab/react)
343+
344+
If `acquireTokenSilent` fails, fallback to `acquireTokenRedirect`. This method will initiate a full-frame redirect and the response will be handled when returning to the application. When this component is rendered after returning from the redirect, `acquireTokenSilent` should now succeed as the tokens will be pulled from the cache.
345+
346+
```javascript
347+
import { InteractionRequiredAuthError, InteractionStatus } from "@azure/msal-browser";
348+
import { AuthenticatedTemplate, useMsal } from "@azure/msal-react";
349+
350+
function ProtectedComponent() {
351+
const { instance, inProgress, accounts } = useMsal();
352+
const [apiData, setApiData] = useState(null);
353+
354+
355+
useEffect(() => {
356+
const accessTokenRequest = {
357+
scopes: ["user.read"],
358+
account: accounts[0]
359+
}
360+
if (!apiData && inProgress === InteractionStatus.None) {
361+
instance.acquireTokenSilent(accessTokenRequest).then((accessTokenResponse) => {
362+
// Acquire token silent success
363+
let accessToken = accessTokenResponse.accessToken;
364+
// Call your API with token
365+
callApi(accessToken).then((response) => { setApiData(response) });
366+
}).catch((error) => {
367+
if (error instanceof InteractionRequiredAuthError) {
368+
instance.acquireTokenRedirect(accessTokenRequest);
369+
}
370+
console.log(error);
371+
})
372+
}
373+
}, [instance, accounts, inProgress, apiData]);
374+
375+
return <p>Return your protected content here: {apiData}</p>
376+
}
377+
378+
function App() {
379+
return (
380+
<AuthenticatedTemplate>
381+
<ProtectedComponent />
382+
</ AuthenticatedTemplate>
383+
)
384+
}
385+
```
386+
387+
Alternatively, if you need to acquire a token outside of a React component you can call `acquireTokenSilent` but should not fallback to interaction if it fails. All interaction should take place underneath the `MsalProvider` component in your component tree.
388+
389+
```javascript
390+
// MSAL.js v2 exposes several account APIs, logic to determine which account to use is the responsibility of the developer
391+
const account = publicClientApplication.getAllAccounts()[0];
392+
393+
const accessTokenRequest = {
394+
scopes: ["user.read"],
395+
account: account
396+
}
397+
398+
// Use the same publicClientApplication instance provided to MsalProvider
399+
publicClientApplication.acquireTokenSilent(accessTokenRequest).then(function(accessTokenResponse) {
400+
// Acquire token silent success
401+
let accessToken = accessTokenResponse.accessToken;
402+
// Call your API with token
403+
callApi(accessToken);
404+
}).catch(function (error) {
405+
//Acquire token silent failure
406+
console.log(error);
407+
});
408+
```
409+
195410
---
196411
197412
## Next steps

articles/active-directory/develop/scenario-spa-app-configuration.md

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,23 @@ The following Microsoft libraries support single-page apps:
3030

3131
In an MSAL library, the application registration information is passed as configuration during the library initialization.
3232

33-
# [JavaScript](#tab/javascript)
33+
# [JavaScript (MSAL.js v2)](#tab/javascript2)
34+
35+
```javascript
36+
// Configuration object constructed.
37+
const config = {
38+
auth: {
39+
clientId: 'your_client_id'
40+
}
41+
};
42+
43+
// create PublicClientApplication instance
44+
const publicClientApplication = new PublicClientApplication(config);
45+
```
46+
47+
For more information on the configurable options, see [Initializing application with MSAL.js](msal-js-initializing-client-applications.md).
48+
49+
# [JavaScript (MSAL.js v1)](#tab/javascript1)
3450

3551
```javascript
3652
// Configuration object constructed.
@@ -65,6 +81,33 @@ import { MsalModule } from '@azure/msal-angular';
6581
export class AppModule { }
6682
```
6783

84+
# [React](#tab/react)
85+
86+
```javascript
87+
import { PublicClientApplication } from "@azure/msal-browser";
88+
import { MsalProvider } from "@azure/msal-react";
89+
90+
// Configuration object constructed.
91+
const config = {
92+
auth: {
93+
clientId: 'your_client_id'
94+
}
95+
};
96+
97+
// create PublicClientApplication instance
98+
const publicClientApplication = new PublicClientApplication(config);
99+
100+
// Wrap your app component tree in the MsalProvider component
101+
ReactDOM.render(
102+
<React.StrictMode>
103+
<MsalProvider instance={publicClientApplication}>
104+
<App />
105+
</ MsalProvider>
106+
</React.StrictMode>,
107+
document.getElementById('root')
108+
);
109+
```
110+
68111
---
69112

70113
## Next steps

0 commit comments

Comments
 (0)