Skip to content

Commit 189cbe7

Browse files
author
Prithvi Kanherkar
authored
Merge pull request #1711 from AzureAD/msal-node-cache-silentFlow
[msal-node][#1] SilentFlow support in msal-common
2 parents 504d352 + a156fcf commit 189cbe7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1935
-1410
lines changed

build/sdl-tasks.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ steps:
1010
optionsXS: 1
1111
optionsHMENABLE: 0
1212

13-
# - task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@3
14-
# displayName: 'Run CredScan3'
15-
# inputs:
16-
# scanFolder: './'
17-
# debugMode: false
13+
- task: securedevelopmentteam.vss-secure-development-tools.build-task-credscan.CredScan@3
14+
displayName: 'Run CredScan3'
15+
inputs:
16+
scanFolder: './'
17+
debugMode: false
1818

1919
- task: securedevelopmentteam.vss-secure-development-tools.build-task-postanalysis.PostAnalysis@1
2020
displayName: 'Post Analysis'

lib/msal-browser/src/app/PublicClientApplication.ts

+26-25
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under the MIT License.
44
*/
55
import {
6-
Account,
6+
IAccount,
77
SPAClient,
88
INetworkModule,
99
TokenResponse,
@@ -23,7 +23,10 @@ import {
2323
AuthorizationCodeRequest,
2424
Constants,
2525
ClientAuthError,
26-
AuthorityType
26+
AuthorityType,
27+
AuthenticationResult,
28+
SilentFlowRequest,
29+
AccountEntity
2730
} from "@azure/msal-common";
2831
import { buildConfiguration, Configuration } from "../config/Configuration";
2932
import { BrowserStorage } from "../cache/BrowserStorage";
@@ -57,7 +60,7 @@ export class PublicClientApplication {
5760
private readonly networkClient: INetworkModule;
5861

5962
// Response promise
60-
private readonly tokenExchangePromise: Promise<TokenResponse>;
63+
private readonly tokenExchangePromise: Promise<AuthenticationResult>;
6164

6265
// Input configuration by developer/user
6366
private config: Configuration;
@@ -182,7 +185,7 @@ export class PublicClientApplication {
182185
* auth flows.
183186
* @returns token response or null. If the return value is null, then no auth redirect was detected.
184187
*/
185-
async handleRedirectPromise(): Promise<TokenResponse | null> {
188+
async handleRedirectPromise(): Promise<AuthenticationResult | null> {
186189
return this.tokenExchangePromise;
187190
}
188191

@@ -191,7 +194,7 @@ export class PublicClientApplication {
191194
* - if true, performs logic to cache and navigate
192195
* - if false, handles hash string and parses response
193196
*/
194-
private async handleRedirectResponse(): Promise<TokenResponse> {
197+
private async handleRedirectResponse(): Promise<AuthenticationResult> {
195198
// Get current location hash from window or cache.
196199
const {location: {hash}} = window;
197200
const cachedHash = this.browserStorage.getItem(TemporaryCacheKeys.URL_HASH);
@@ -244,7 +247,7 @@ export class PublicClientApplication {
244247
* @param responseHash
245248
* @param interactionHandler
246249
*/
247-
private async handleHash(responseHash: string): Promise<TokenResponse> {
250+
private async handleHash(responseHash: string): Promise<AuthenticationResult> {
248251
const interactionHandler = new RedirectHandler(this.authModule, this.browserStorage);
249252
if (!StringUtils.isEmpty(responseHash)) {
250253
// Hash contains known properties - handle and return in callback
@@ -328,9 +331,9 @@ export class PublicClientApplication {
328331
*
329332
* @param {@link (AuthenticationParameters:type)}
330333
*
331-
* @returns {Promise.<TokenResponse>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthResponse} object
334+
* @returns {Promise.<AuthenticationResult>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthResponse} object
332335
*/
333-
async loginPopup(request: AuthorizationUrlRequest): Promise<TokenResponse> {
336+
async loginPopup(request: AuthorizationUrlRequest): Promise<AuthenticationResult> {
334337
try {
335338
// Preflight request
336339
const validRequest: AuthorizationUrlRequest = this.preflightRequest(request);
@@ -354,9 +357,9 @@ export class PublicClientApplication {
354357
* @param {@link AuthenticationParameters}
355358
*
356359
* To acquire only idToken, please pass clientId as the only scope in the Authentication Parameters
357-
* @returns {Promise.<TokenResponse>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthResponse} object
360+
* @returns {Promise.<AuthenticationResult>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthResponse} object
358361
*/
359-
async acquireTokenPopup(request: AuthorizationUrlRequest): Promise<TokenResponse> {
362+
async acquireTokenPopup(request: AuthorizationUrlRequest): Promise<AuthenticationResult> {
360363
try {
361364
// Preflight request
362365
const validRequest: AuthorizationUrlRequest = this.preflightRequest(request);
@@ -379,7 +382,7 @@ export class PublicClientApplication {
379382
* Helper which acquires an authorization code with a popup from given url, and exchanges the code for a set of OAuth tokens.
380383
* @param navigateUrl
381384
*/
382-
private async popupTokenHelper(navigateUrl: string, authCodeRequest: AuthorizationCodeRequest): Promise<TokenResponse> {
385+
private async popupTokenHelper(navigateUrl: string, authCodeRequest: AuthorizationCodeRequest): Promise<AuthenticationResult> {
383386
// Create popup interaction handler.
384387
const interactionHandler = new PopupHandler(this.authModule, this.browserStorage);
385388
// Show the UI once the url has been created. Get the window handle for the popup.
@@ -405,12 +408,12 @@ export class PublicClientApplication {
405408
*
406409
* If your refresh token has expired, you can use this function to fetch a new set of tokens silently as long as
407410
* you session on the server still exists.
408-
* @param {@link AuthenticationParameters}
411+
* @param {@link AuthorizationUrlRequest}
409412
*
410413
* To renew idToken, please pass clientId as the only scope in the Authentication Parameters.
411-
* @returns {Promise.<TokenResponse>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthResponse} object
414+
* @returns {Promise.<AuthenticationResult>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthResponse} object
412415
*/
413-
async ssoSilent(request: AuthorizationUrlRequest): Promise<TokenResponse> {
416+
async ssoSilent(request: AuthorizationUrlRequest): Promise<AuthenticationResult> {
414417
// block the reload if it occurred inside a hidden iframe
415418
BrowserUtils.blockReloadInHiddenIframes();
416419

@@ -454,19 +457,18 @@ export class PublicClientApplication {
454457
* @returns {Promise.<TokenResponse>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthResponse} object
455458
*
456459
*/
457-
async acquireTokenSilent(silentRequest: TokenRenewParameters): Promise<TokenResponse> {
460+
async acquireTokenSilent(silentRequest: SilentFlowRequest): Promise<AuthenticationResult> {
458461
// block the reload if it occurred inside a hidden iframe
459462
BrowserUtils.blockReloadInHiddenIframes();
460463

461464
const tokenRequest: AuthorizationUrlRequest = {
462465
...silentRequest,
463466
redirectUri: "",
464-
scopes: silentRequest.scopes || []
465467
};
466468

467469
try {
468470
// Send request to renew token. Auth module will throw errors if token cannot be renewed.
469-
return await this.authModule.getValidToken(tokenRequest, silentRequest.account, silentRequest.forceRefresh);
471+
return await this.authModule.getValidToken(silentRequest);
470472
} catch (e) {
471473
const isServerError = e instanceof ServerError;
472474
const isInteractionRequiredError = e instanceof InteractionRequiredAuthError;
@@ -499,7 +501,7 @@ export class PublicClientApplication {
499501
* @param navigateUrl
500502
* @param userRequestScopes
501503
*/
502-
private async silentTokenHelper(navigateUrl: string, authCodeRequest: AuthorizationCodeRequest, userRequestScopes: string): Promise<TokenResponse> {
504+
private async silentTokenHelper(navigateUrl: string, authCodeRequest: AuthorizationCodeRequest, userRequestScopes: string): Promise<AuthenticationResult> {
503505
try {
504506
// Create silent handler
505507
const silentHandler = new SilentHandler(this.authModule, this.browserStorage, this.config.system.loadFrameTimeout);
@@ -522,9 +524,9 @@ export class PublicClientApplication {
522524
* Use to log out the current user, and redirect the user to the postLogoutRedirectUri.
523525
* Default behaviour is to redirect the user to `window.location.href`.
524526
*/
525-
logout(): void {
527+
logout(accountObj: IAccount): void {
526528
// create logout string and navigate user window to logout. Auth module will clear cache.
527-
this.authModule.logout().then((logoutUri: string) => {
529+
this.authModule.logout(accountObj, this.defaultAuthorityInstance).then((logoutUri: string) => {
528530
BrowserUtils.navigateWindow(logoutUri);
529531
});
530532
}
@@ -560,8 +562,8 @@ export class PublicClientApplication {
560562
* or null when no state is found
561563
* @returns {@link Account} - the account object stored in MSAL
562564
*/
563-
public getAccount(): Account {
564-
return this.authModule.getAccount();
565+
public getAccount(homeAccountId: string): AccountEntity {
566+
return this.authModule.getAccount(homeAccountId);
565567
}
566568

567569
// #endregion
@@ -599,10 +601,9 @@ export class PublicClientApplication {
599601
const validatedRequest: AuthorizationUrlRequest = {
600602
...request
601603
};
602-
603-
const cachedAccount = this.getAccount();
604+
604605
// Check for ADAL SSO
605-
if (StringUtils.isEmpty(validatedRequest.loginHint) && !cachedAccount) {
606+
if (StringUtils.isEmpty(validatedRequest.loginHint)) {
606607
// Only check for adal token if no SSO params are being used
607608
const adalIdTokenString = this.browserStorage.getItem(PersistentCacheKeys.ADAL_ID_TOKEN);
608609
if (!StringUtils.isEmpty(adalIdTokenString)) {

lib/msal-browser/src/cache/BrowserStorage.ts

+3-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License.
44
*/
5-
import { ICacheStorage, Constants, PersistentCacheKeys, InMemoryCache, StringUtils, AuthorizationCodeRequest, ICrypto } from "@azure/msal-common";
5+
import { ICacheStorage, Constants, PersistentCacheKeys, StringUtils, AuthorizationCodeRequest, ICrypto } from "@azure/msal-common";
66
import { CacheOptions } from "../config/Configuration";
77
import { BrowserAuthError } from "../error/BrowserAuthError";
88
import { BrowserConfigurationAuthError } from "../error/BrowserConfigurationAuthError";
@@ -256,14 +256,8 @@ export class BrowserStorage implements ICacheStorage {
256256
/**
257257
* Dummy implementation until browser cache is migrated
258258
*/
259-
getCache(): InMemoryCache {
260-
return {
261-
accounts: {},
262-
idTokens: {},
263-
accessTokens: {},
264-
refreshTokens: {},
265-
appMetadata: {}
266-
};
259+
getCache(): object {
260+
return this.windowStorage;
267261
}
268262

269263
/**

lib/msal-browser/src/interaction_handler/InteractionHandler.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License.
44
*/
5-
import { SPAClient, TokenResponse, StringUtils, AuthorizationCodeRequest, ProtocolUtils } from "@azure/msal-common";
5+
import { SPAClient, TokenResponse, StringUtils, AuthorizationCodeRequest, ProtocolUtils, AuthenticationResult } from "@azure/msal-common";
66
import { BrowserStorage } from "../cache/BrowserStorage";
77
import { BrowserAuthError } from "../error/BrowserAuthError";
88
import { TemporaryCacheKeys } from "../utils/BrowserConstants";
@@ -31,7 +31,7 @@ export abstract class InteractionHandler {
3131
* Function to handle response parameters from hash.
3232
* @param locationHash
3333
*/
34-
async handleCodeResponse(locationHash: string): Promise<TokenResponse> {
34+
async handleCodeResponse(locationHash: string): Promise<AuthenticationResult> {
3535
// Check that location hash isn't empty.
3636
if (StringUtils.isEmpty(locationHash)) {
3737
throw BrowserAuthError.createEmptyHashError(locationHash);

lib/msal-browser/src/interaction_handler/RedirectHandler.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License.
44
*/
5-
import { StringUtils, TokenResponse, AuthorizationCodeRequest, ICrypto, ProtocolUtils } from "@azure/msal-common";
5+
import { StringUtils, TokenResponse, AuthorizationCodeRequest, ICrypto, ProtocolUtils, AuthenticationResult } from "@azure/msal-common";
66
import { InteractionHandler } from "./InteractionHandler";
77
import { BrowserAuthError } from "../error/BrowserAuthError";
88
import { BrowserConstants, TemporaryCacheKeys } from "../utils/BrowserConstants";
@@ -42,7 +42,7 @@ export class RedirectHandler extends InteractionHandler {
4242
* Handle authorization code response in the window.
4343
* @param hash
4444
*/
45-
async handleCodeResponse(locationHash: string, browserCrypto?: ICrypto): Promise<TokenResponse> {
45+
async handleCodeResponse(locationHash: string, browserCrypto?: ICrypto): Promise<AuthenticationResult> {
4646
// Check that location hash isn't empty.
4747
if (StringUtils.isEmpty(locationHash)) {
4848
throw BrowserAuthError.createEmptyHashError(locationHash);

lib/msal-browser/src/types/AuthCallback.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License.
44
*/
5-
import { AuthError, TokenResponse } from "@azure/msal-common";
5+
import { AuthError, AuthenticationResult } from "@azure/msal-common";
66

77
/**
88
* A type alias for an authResponseCallback function.
99
* {@link (authResponseCallback:type)}
1010
* @param authErr error created for failure cases
1111
* @param response response containing token strings in success cases, or just state value in error cases
1212
*/
13-
export type AuthCallback = (authErr: AuthError, response?: TokenResponse) => void;
13+
export type AuthCallback = (authErr: AuthError, response?: AuthenticationResult) => void;

0 commit comments

Comments
 (0)