Skip to content

Commit ba94c26

Browse files
authored
Merge pull request #471 from ForgeRock/SDKS-4445-oidc-query-params
fix(oidc-client): append query params when provided
2 parents fa3d434 + ef4ab6f commit ba94c26

File tree

6 files changed

+46
-9
lines changed

6 files changed

+46
-9
lines changed

.changeset/vast-dogs-make.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@forgerock/sdk-oidc': patch
3+
'@forgerock/oidc-client': patch
4+
---
5+
6+
Append query params to authorization url when provided

packages/oidc-client/src/lib/authorize.request.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export function authorizeµ(
3737
options?: GetAuthorizationUrlOptions,
3838
) {
3939
return buildAuthorizeOptionsµ(wellknown, config, options).pipe(
40-
Micro.flatMap(([url, config, options]) => createAuthorizeUrlµ(url, config, options)),
40+
Micro.flatMap(([url, options]) => createAuthorizeUrlµ(url, options)),
4141
Micro.tap((url) => log.debug('Authorize URL created', url)),
4242
Micro.tapError((url) => Micro.sync(() => log.error('Error creating authorize URL', url))),
4343
Micro.flatMap(

packages/oidc-client/src/lib/authorize.request.utils.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ it.effect('buildAuthorizeOptionsµ succeeds with BuildAuthorizationData', () =>
3939

4040
expect(result).toStrictEqual([
4141
wellknown.authorization_endpoint,
42-
config,
4342
{
4443
clientId,
4544
redirectUri,
@@ -56,7 +55,6 @@ it.effect('buildAuthorizeOptionsµ with pi.flow succeeds with BuildAuthorization
5655

5756
expect(result).toStrictEqual([
5857
wellknown.authorization_endpoint,
59-
config,
6058
{
6159
clientId,
6260
redirectUri,

packages/oidc-client/src/lib/authorize.request.utils.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@ import type { WellKnownResponse, GetAuthorizationUrlOptions } from '@forgerock/s
1212
import type { AuthorizationError, AuthorizationSuccess } from './authorize.request.types.js';
1313
import type { OidcConfig } from './config.types.js';
1414

15-
type BuildAuthorizationData = [string, OidcConfig, GetAuthorizationUrlOptions];
15+
type BuildAuthorizationData = [string, GetAuthorizationUrlOptions];
1616
export type OptionalAuthorizeOptions = Partial<GetAuthorizationUrlOptions>;
1717

1818
/**
1919
* @function buildAuthorizeOptionsµ
2020
* @description Builds the authorization options for the OIDC client.
2121
* @param {WellKnownResponse} wellknown - The well-known configuration for the OIDC server.
22-
* @param {OidcConfig} config - The OIDC client configuration.
2322
* @param {OptionalAuthorizeOptions} options - Optional parameters for the authorization request.
2423
* @returns {Micro.Micro<BuildAuthorizationData, AuthorizeErrorResponse, never>}
2524
*/
@@ -32,7 +31,6 @@ export function buildAuthorizeOptionsµ(
3231
return Micro.sync(
3332
(): BuildAuthorizationData => [
3433
wellknown.authorization_endpoint,
35-
config,
3634
{
3735
clientId: config.clientId,
3836
redirectUri: config.redirectUri,
@@ -91,13 +89,11 @@ export function createAuthorizeErrorµ(
9189
* @function createAuthorizeUrlµ
9290
* @description Creates an authorization URL and related options/config for the Authorize request.
9391
* @param {string} path - The path to the authorization endpoint.
94-
* @param { OidcConfig } config - The OIDC client configuration.
9592
* @param { GetAuthorizationUrlOptions } options - Optional parameters for the authorization request.
96-
* @returns { Micro.Micro<[string, OidcConfig, GetAuthorizationUrlOptions], AuthorizationError, never> }
93+
* @returns { Micro.Micro<[string, GetAuthorizationUrlOptions], AuthorizationError, never> }
9794
*/
9895
export function createAuthorizeUrlµ(
9996
path: string,
100-
config: OidcConfig,
10197
options: GetAuthorizationUrlOptions,
10298
): Micro.Micro<[string, GetAuthorizationUrlOptions], AuthorizationError, never> {
10399
return Micro.tryPromise({

packages/sdk-effects/oidc/src/lib/authorize.effects.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export async function createAuthorizeUrl(
4040
const challenge = await createChallenge(authorizeUrlOptions.verifier);
4141

4242
const requestParams = new URLSearchParams({
43+
...options.query,
4344
code_challenge: challenge,
4445
code_challenge_method: 'S256',
4546
client_id: options.clientId,

packages/sdk-effects/oidc/src/lib/authorize.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,42 @@ describe('createAuthorizeUrl', () => {
8383
expect(params.get('response_mode')).toBe(responseMode);
8484
});
8585

86+
it('should include query parameters when provided', async () => {
87+
const queryA = 'valueA';
88+
const queryB = 'valueB';
89+
const optionsWithOptionals: GenerateAndStoreAuthUrlValues = {
90+
...mockOptions,
91+
query: {
92+
queryA,
93+
queryB,
94+
},
95+
};
96+
97+
const url = await createAuthorizeUrl(baseUrl, optionsWithOptionals);
98+
const params = new URL(url).searchParams;
99+
100+
expect(params.get('queryA')).toBe(queryA);
101+
expect(params.get('queryB')).toBe(queryB);
102+
});
103+
104+
it('should ensure standard config params override conflicting query params', async () => {
105+
const optionsWithConflict: GenerateAndStoreAuthUrlValues = {
106+
...mockOptions,
107+
query: {
108+
client_id: 'malicious-client',
109+
custom_param: 'value',
110+
},
111+
};
112+
113+
const url = await createAuthorizeUrl(baseUrl, optionsWithConflict);
114+
const params = new URL(url).searchParams;
115+
116+
// Standard param should override query param
117+
expect(params.get('client_id')).toBe(mockOptions.clientId);
118+
// Custom param should be preserved
119+
expect(params.get('custom_param')).toBe('value');
120+
});
121+
86122
it('should store the authorize options in session storage', async () => {
87123
await createAuthorizeUrl(baseUrl, mockOptions);
88124
const storageKey = getStorageKey(mockOptions.clientId);

0 commit comments

Comments
 (0)