Skip to content

Commit 472a411

Browse files
committed
initial commit
1 parent d294877 commit 472a411

File tree

9 files changed

+268
-9
lines changed

9 files changed

+268
-9
lines changed

lib/msal-browser/src/config/Configuration.ts

+5
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ export type BrowserAuthOptions = {
108108
* Flag of whether the STS will send back additional parameters to specify where the tokens should be retrieved from.
109109
*/
110110
instanceAware?: boolean;
111+
/**
112+
* Flag of whether to encode query parameters
113+
*/
114+
encodeExtraQueryParams?: boolean;
111115
};
112116

113117
/** @internal */
@@ -296,6 +300,7 @@ export function buildConfiguration(
296300
skipAuthorityMetadataCache: false,
297301
supportsNestedAppAuth: false,
298302
instanceAware: false,
303+
encodeExtraQueryParams: true,
299304
};
300305

301306
// Default cache options for browser

lib/msal-browser/src/protocol/Authorize.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,12 @@ export async function getAuthCodeRequestUrl(
158158
request.extraQueryParameters || {}
159159
);
160160

161-
return AuthorizeProtocol.getAuthorizeUrl(authority, parameters);
161+
return AuthorizeProtocol.getAuthorizeUrl(
162+
authority,
163+
parameters,
164+
config.auth.encodeExtraQueryParams,
165+
request.extraQueryParameters
166+
);
162167
}
163168

164169
/**
@@ -195,7 +200,12 @@ export async function getEARForm(
195200
queryParams,
196201
request.extraQueryParameters || {}
197202
);
198-
const url = AuthorizeProtocol.getAuthorizeUrl(authority, queryParams);
203+
const url = AuthorizeProtocol.getAuthorizeUrl(
204+
authority,
205+
queryParams,
206+
config.auth.encodeExtraQueryParams,
207+
request.extraQueryParameters
208+
);
199209

200210
return createForm(frame, url, parameters);
201211
}

lib/msal-common/src/client/AuthorizationCodeClient.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,10 @@ export class AuthorizationCodeClient extends BaseClient {
507507
RequestParameterBuilder.addInstanceAware(parameters);
508508
}
509509

510-
return UrlUtils.mapToQueryString(parameters);
510+
return UrlUtils.mapToQueryString(
511+
parameters,
512+
this.config.authOptions.encodeExtraQueryParams,
513+
request.extraQueryParameters
514+
);
511515
}
512516
}

lib/msal-common/src/config/ClientConfiguration.ts

+2
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ export type AuthOptions = {
9393
azureCloudOptions?: AzureCloudOptions;
9494
skipAuthorityMetadataCache?: boolean;
9595
instanceAware?: boolean;
96+
encodeExtraQueryParams?: boolean;
9697
};
9798

9899
/**
@@ -276,6 +277,7 @@ function buildAuthOptions(authOptions: AuthOptions): Required<AuthOptions> {
276277
azureCloudOptions: DEFAULT_AZURE_CLOUD_OPTIONS,
277278
skipAuthorityMetadataCache: false,
278279
instanceAware: false,
280+
encodeExtraQueryParams: true,
279281
...authOptions,
280282
};
281283
}

lib/msal-common/src/protocol/Authorize.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import {
2626
isInteractionRequiredError,
2727
} from "../error/InteractionRequiredAuthError.js";
2828
import { ServerError } from "../error/ServerError.js";
29+
import { StringDict } from "../utils/MsalTypes.js";
2930

3031
/**
3132
* Returns map of parameters that are applicable to all calls to /authorize whether using PKCE or EAR
@@ -264,10 +265,15 @@ export function getStandardAuthorizeRequestParameters(
264265
*/
265266
export function getAuthorizeUrl(
266267
authority: Authority,
267-
requestParameters: Map<string, string>
268+
requestParameters: Map<string, string>,
269+
encodeParams?: boolean,
270+
extraQueryParameters?: StringDict | undefined
268271
): string {
269-
const queryString = mapToQueryString(requestParameters);
270-
272+
const queryString = mapToQueryString(
273+
requestParameters,
274+
encodeParams,
275+
extraQueryParameters
276+
);
271277
return UrlString.appendQueryString(
272278
authority.authorizationEndpoint,
273279
queryString

lib/msal-common/src/utils/UrlUtils.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
ClientAuthErrorCodes,
99
createClientAuthError,
1010
} from "../error/ClientAuthError.js";
11+
import { StringDict } from "./MsalTypes.js";
1112

1213
/**
1314
* Parses hash string from given string. Returns empty string if no hash symbol is found.
@@ -64,11 +65,23 @@ export function getDeserializedResponse(
6465
/**
6566
* Utility to create a URL from the params map
6667
*/
67-
export function mapToQueryString(parameters: Map<string, string>): string {
68+
export function mapToQueryString(
69+
parameters: Map<string, string>,
70+
encodeExtraParams: boolean = true,
71+
extraQueryParameters?: StringDict
72+
): string {
6873
const queryParameterArray: Array<string> = new Array<string>();
6974

7075
parameters.forEach((value, key) => {
71-
queryParameterArray.push(`${key}=${encodeURIComponent(value)}`);
76+
if (
77+
!encodeExtraParams &&
78+
extraQueryParameters &&
79+
key in extraQueryParameters
80+
) {
81+
queryParameterArray.push(`${key}=${value}`);
82+
} else {
83+
queryParameterArray.push(`${key}=${encodeURIComponent(value)}`);
84+
}
7285
});
7386

7487
return queryParameterArray.join("&");

lib/msal-common/test/request/RequestParameterBuilder.spec.ts

+212
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,218 @@ describe("RequestParameterBuilder unit tests", () => {
230230
).toBe(true);
231231
});
232232

233+
it("Doesn't encode extra params if encodeParams is false and extra params are passed in", () => {
234+
const parameters = new Map<string, string>();
235+
RequestParameterBuilder.addResponseType(
236+
parameters,
237+
OAuthResponseType.CODE
238+
);
239+
RequestParameterBuilder.addResponseMode(
240+
parameters,
241+
ResponseMode.FORM_POST
242+
);
243+
RequestParameterBuilder.addScopes(
244+
parameters,
245+
TEST_CONFIG.DEFAULT_SCOPES
246+
);
247+
RequestParameterBuilder.addClientId(
248+
parameters,
249+
TEST_CONFIG.MSAL_CLIENT_ID
250+
);
251+
RequestParameterBuilder.addRedirectUri(
252+
parameters,
253+
TEST_URIS.TEST_REDIRECT_URI_LOCALHOST
254+
);
255+
RequestParameterBuilder.addDomainHint(
256+
parameters,
257+
TEST_CONFIG.DOMAIN_HINT
258+
);
259+
RequestParameterBuilder.addLoginHint(
260+
parameters,
261+
TEST_CONFIG.LOGIN_HINT
262+
);
263+
RequestParameterBuilder.addClaims(parameters, TEST_CONFIG.CLAIMS, []);
264+
RequestParameterBuilder.addCorrelationId(
265+
parameters,
266+
TEST_CONFIG.CORRELATION_ID
267+
);
268+
RequestParameterBuilder.addPrompt(
269+
parameters,
270+
PromptValue.SELECT_ACCOUNT
271+
);
272+
RequestParameterBuilder.addState(parameters, TEST_CONFIG.STATE);
273+
RequestParameterBuilder.addNonce(parameters, TEST_CONFIG.NONCE);
274+
RequestParameterBuilder.addCodeChallengeParams(
275+
parameters,
276+
TEST_CONFIG.TEST_CHALLENGE,
277+
TEST_CONFIG.CODE_CHALLENGE_METHOD
278+
);
279+
RequestParameterBuilder.addAuthorizationCode(
280+
parameters,
281+
TEST_TOKENS.AUTHORIZATION_CODE
282+
);
283+
RequestParameterBuilder.addDeviceCode(
284+
parameters,
285+
DEVICE_CODE_RESPONSE.deviceCode
286+
);
287+
RequestParameterBuilder.addCodeVerifier(
288+
parameters,
289+
TEST_CONFIG.TEST_VERIFIER
290+
);
291+
RequestParameterBuilder.addGrantType(
292+
parameters,
293+
GrantType.DEVICE_CODE_GRANT
294+
);
295+
RequestParameterBuilder.addSid(parameters, TEST_CONFIG.SID);
296+
RequestParameterBuilder.addLogoutHint(
297+
parameters,
298+
TEST_CONFIG.LOGIN_HINT
299+
);
300+
RequestParameterBuilder.addExtraQueryParameters(parameters, {
301+
extra_params: "param1,param2",
302+
});
303+
304+
const requestQueryString = UrlUtils.mapToQueryString(
305+
parameters,
306+
false,
307+
{
308+
extra_params: "param1,param2",
309+
}
310+
);
311+
console.log(requestQueryString);
312+
console.log(
313+
`${AADServerParamKeys.REDIRECT_URI}=${TEST_URIS.TEST_REDIRECT_URI_LOCALHOST}`
314+
);
315+
expect(
316+
requestQueryString.includes(
317+
`${AADServerParamKeys.RESPONSE_TYPE}=${OAuthResponseType.CODE}`
318+
)
319+
).toBe(true);
320+
expect(
321+
requestQueryString.includes(
322+
`${AADServerParamKeys.RESPONSE_MODE}=${encodeURIComponent(
323+
ResponseMode.FORM_POST
324+
)}`
325+
)
326+
).toBe(true);
327+
expect(
328+
requestQueryString.includes(
329+
`${AADServerParamKeys.SCOPE}=${Constants.OPENID_SCOPE}%20${Constants.PROFILE_SCOPE}%20${Constants.OFFLINE_ACCESS_SCOPE}`
330+
)
331+
).toBe(true);
332+
expect(
333+
requestQueryString.includes(
334+
`${AADServerParamKeys.CLIENT_ID}=${TEST_CONFIG.MSAL_CLIENT_ID}`
335+
)
336+
).toBe(true);
337+
expect(
338+
requestQueryString.includes(
339+
`${AADServerParamKeys.REDIRECT_URI}=${encodeURIComponent(
340+
TEST_URIS.TEST_REDIRECT_URI_LOCALHOST
341+
)}`
342+
)
343+
).toBe(true);
344+
expect(
345+
requestQueryString.includes(
346+
`${AADServerParamKeys.DOMAIN_HINT}=${encodeURIComponent(
347+
TEST_CONFIG.DOMAIN_HINT
348+
)}`
349+
)
350+
).toBe(true);
351+
expect(
352+
requestQueryString.includes(
353+
`${AADServerParamKeys.LOGIN_HINT}=${encodeURIComponent(
354+
TEST_CONFIG.LOGIN_HINT
355+
)}`
356+
)
357+
).toBe(true);
358+
expect(
359+
requestQueryString.includes(
360+
`${AADServerParamKeys.CLAIMS}=${encodeURIComponent(
361+
TEST_CONFIG.CLAIMS
362+
)}`
363+
)
364+
).toBe(true);
365+
expect(
366+
requestQueryString.includes(
367+
`${AADServerParamKeys.CLIENT_REQUEST_ID}=${encodeURIComponent(
368+
TEST_CONFIG.CORRELATION_ID
369+
)}`
370+
)
371+
).toBe(true);
372+
expect(
373+
requestQueryString.includes(
374+
`${AADServerParamKeys.PROMPT}=${PromptValue.SELECT_ACCOUNT}`
375+
)
376+
).toBe(true);
377+
expect(
378+
requestQueryString.includes(
379+
`${AADServerParamKeys.STATE}=${encodeURIComponent(
380+
TEST_CONFIG.STATE
381+
)}`
382+
)
383+
).toBe(true);
384+
expect(
385+
requestQueryString.includes(
386+
`${AADServerParamKeys.NONCE}=${encodeURIComponent(
387+
TEST_CONFIG.NONCE
388+
)}`
389+
)
390+
).toBe(true);
391+
expect(
392+
requestQueryString.includes(
393+
`${AADServerParamKeys.CODE_CHALLENGE}=${encodeURIComponent(
394+
TEST_CONFIG.TEST_CHALLENGE
395+
)}`
396+
)
397+
).toBe(true);
398+
expect(
399+
requestQueryString.includes(
400+
`${
401+
AADServerParamKeys.CODE_CHALLENGE_METHOD
402+
}=${encodeURIComponent(TEST_CONFIG.CODE_CHALLENGE_METHOD)}`
403+
)
404+
).toBe(true);
405+
expect(
406+
requestQueryString.includes(
407+
`${AADServerParamKeys.CODE}=${encodeURIComponent(
408+
TEST_TOKENS.AUTHORIZATION_CODE
409+
)}`
410+
)
411+
).toBe(true);
412+
expect(
413+
requestQueryString.includes(
414+
`${AADServerParamKeys.DEVICE_CODE}=${encodeURIComponent(
415+
DEVICE_CODE_RESPONSE.deviceCode
416+
)}`
417+
)
418+
).toBe(true);
419+
expect(
420+
requestQueryString.includes(
421+
`${AADServerParamKeys.CODE_VERIFIER}=${encodeURIComponent(
422+
TEST_CONFIG.TEST_VERIFIER
423+
)}`
424+
)
425+
).toBe(true);
426+
expect(
427+
requestQueryString.includes(
428+
`${AADServerParamKeys.SID}=${encodeURIComponent(
429+
TEST_CONFIG.SID
430+
)}`
431+
)
432+
).toBe(true);
433+
expect(
434+
requestQueryString.includes(
435+
`${AADServerParamKeys.LOGOUT_HINT}=${encodeURIComponent(
436+
TEST_CONFIG.LOGIN_HINT
437+
)}`
438+
)
439+
).toBe(true);
440+
expect(requestQueryString.includes(`extra_params=param1,param2`)).toBe(
441+
true
442+
);
443+
});
444+
233445
it("Adds token type and req_cnf correctly for proof-of-possession tokens", () => {
234446
const parameters = new Map<string, string>();
235447
RequestParameterBuilder.addPopToken(

lib/msal-node/src/config/Configuration.ts

+2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export type NodeAuthOptions = {
5555
protocolMode?: ProtocolMode;
5656
azureCloudOptions?: AzureCloudOptions;
5757
skipAuthorityMetadataCache?: boolean;
58+
encodeExtraQueryParams?: boolean;
5859
};
5960

6061
/**
@@ -154,6 +155,7 @@ const DEFAULT_AUTH_OPTIONS: Required<NodeAuthOptions> = {
154155
tenant: Constants.EMPTY_STRING,
155156
},
156157
skipAuthorityMetadataCache: false,
158+
encodeExtraQueryParams: true,
157159
};
158160

159161
const DEFAULT_CACHE_OPTIONS: CacheOptions = {

lib/msal-node/src/protocol/Authorize.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,10 @@ export function getAuthCodeRequestUrl(
6565
request.extraQueryParameters || {}
6666
);
6767

68-
return AuthorizeProtocol.getAuthorizeUrl(authority, parameters);
68+
return AuthorizeProtocol.getAuthorizeUrl(
69+
authority,
70+
parameters,
71+
config.auth.encodeExtraQueryParams,
72+
request.extraQueryParameters
73+
);
6974
}

0 commit comments

Comments
 (0)