Skip to content

Commit d4ded90

Browse files
Add provider_query_params to getAuthorizationUrl method (#1347)
## Summary - Add `provider_query_params` parameter to SSO `getAuthorizationUrl` method - Implement consistent query string serialization with UserManagement module - Add comprehensive tests for the new functionality ## Changes - **Interface**: Added `providerQueryParams` to `SSOAuthorizationURLOptions` - **Implementation**: Updated SSO class to handle provider query params using `qs.stringify` - **Tests**: Added test coverage for both populated and empty provider query params - **Compatibility**: Fixed empty `providerScopes` array handling to maintain backward compatibility ## Test plan - [x] All existing SSO tests pass - [x] New provider query params tests pass - [x] TypeScript compilation succeeds - [x] Linting passes - [x] Implementation matches UserManagement pattern Resolves ENT-3776
1 parent e09d13c commit d4ded90

File tree

4 files changed

+57
-17
lines changed

4 files changed

+57
-17
lines changed

src/sso/__snapshots__/sso.spec.ts.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ exports[`SSO SSO getAuthorizationUrl with no custom api hostname generates an au
1212

1313
exports[`SSO SSO getAuthorizationUrl with no domain or provider throws an error for incomplete arguments 1`] = `"Incomplete arguments. Need to specify either a 'connection', 'organization', 'domain', or 'provider'."`;
1414

15+
exports[`SSO SSO getAuthorizationUrl with providerScopes generates an authorize url with the provided provider scopes 1`] = `"https://api.workos.com/sso/authorize?client_id=proj_123&provider=Google&provider_scopes=profile&provider_scopes=email&provider_scopes=calendar&redirect_uri=example.com%2Fsso%2Fworkos%2Fcallback&response_type=code"`;
16+
1517
exports[`SSO SSO getAuthorizationUrl with state generates an authorize url with the provided state 1`] = `"https://api.workos.com/sso/authorize?client_id=proj_123&domain=lyft.com&redirect_uri=example.com%2Fsso%2Fworkos%2Fcallback&response_type=code&state=custom+state"`;
1618

1719
exports[`SSO SSO getProfileAndToken with all information provided sends a request to the WorkOS api for a profile 1`] = `"client_id=proj_123&client_secret=sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU&grant_type=authorization_code&code=authorization_code"`;

src/sso/interfaces/authorization-url-options.interface.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export interface SSOAuthorizationURLOptions {
1010
domainHint?: string;
1111
loginHint?: string;
1212
provider?: string;
13+
providerQueryParams?: Record<string, string | boolean | number>;
1314
providerScopes?: string[];
1415
redirectUri: string;
1516
state?: string;

src/sso/sso.spec.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,7 @@ describe('SSO', () => {
205205
redirectUri: 'example.com/sso/workos/callback',
206206
});
207207

208-
expect(url).toMatchInlineSnapshot(
209-
`"https://api.workos.com/sso/authorize?client_id=proj_123&provider=Google&provider_scopes=profile+email+calendar&redirect_uri=example.com%2Fsso%2Fworkos%2Fcallback&response_type=code"`,
210-
);
208+
expect(url).toMatchSnapshot();
211209
});
212210

213211
it('handles empty provider scopes array', () => {
@@ -225,6 +223,42 @@ describe('SSO', () => {
225223
);
226224
});
227225
});
226+
227+
describe('with providerQueryParams', () => {
228+
it('generates an authorize url with the provided provider query params', () => {
229+
const workos = new WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
230+
231+
const url = workos.sso.getAuthorizationUrl({
232+
provider: 'Google',
233+
providerQueryParams: {
234+
custom_param: 'custom_value',
235+
another_param: 123,
236+
bool_param: true,
237+
},
238+
clientId: 'proj_123',
239+
redirectUri: 'example.com/sso/workos/callback',
240+
});
241+
242+
expect(url).toMatchInlineSnapshot(
243+
`"https://api.workos.com/sso/authorize?client_id=proj_123&provider=Google&provider_query_params%5Banother_param%5D=123&provider_query_params%5Bbool_param%5D=true&provider_query_params%5Bcustom_param%5D=custom_value&redirect_uri=example.com%2Fsso%2Fworkos%2Fcallback&response_type=code"`,
244+
);
245+
});
246+
247+
it('handles empty provider query params', () => {
248+
const workos = new WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
249+
250+
const url = workos.sso.getAuthorizationUrl({
251+
provider: 'Google',
252+
providerQueryParams: {},
253+
clientId: 'proj_123',
254+
redirectUri: 'example.com/sso/workos/callback',
255+
});
256+
257+
expect(url).toMatchInlineSnapshot(
258+
`"https://api.workos.com/sso/authorize?client_id=proj_123&provider=Google&redirect_uri=example.com%2Fsso%2Fworkos%2Fcallback&response_type=code"`,
259+
);
260+
});
261+
});
228262
});
229263

230264
describe('getProfileAndToken', () => {

src/sso/sso.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import qs from 'qs';
12
import { UnknownRecord } from '../common/interfaces/unknown-record.interface';
23
import { fetchAndDeserialize } from '../common/utils/fetch-and-deserialize';
34
import { AutoPaginatable } from '../common/utils/pagination';
@@ -21,19 +22,19 @@ import {
2122
serializeListConnectionsOptions,
2223
} from './serializers';
2324

24-
const toQueryString = (options: Record<string, string | undefined>): string => {
25-
const searchParams = new URLSearchParams();
26-
const keys = Object.keys(options).sort();
27-
28-
for (const key of keys) {
29-
const value = options[key];
30-
31-
if (value) {
32-
searchParams.append(key, value);
33-
}
34-
}
35-
36-
return searchParams.toString();
25+
const toQueryString = (
26+
options: Record<
27+
string,
28+
string | string[] | Record<string, string | boolean | number> | undefined
29+
>,
30+
): string => {
31+
return qs.stringify(options, {
32+
arrayFormat: 'repeat',
33+
// sorts the keys alphabetically to maintain backwards compatibility
34+
sort: (a, b) => a.localeCompare(b),
35+
// encodes space as + instead of %20 to maintain backwards compatibility
36+
format: 'RFC1738',
37+
});
3738
};
3839

3940
export class SSO {
@@ -71,6 +72,7 @@ export class SSO {
7172
loginHint,
7273
organization,
7374
provider,
75+
providerQueryParams,
7476
providerScopes,
7577
redirectUri,
7678
state,
@@ -94,7 +96,8 @@ export class SSO {
9496
domain_hint: domainHint,
9597
login_hint: loginHint,
9698
provider,
97-
provider_scopes: providerScopes?.join(' '),
99+
provider_query_params: providerQueryParams,
100+
provider_scopes: providerScopes,
98101
client_id: clientId,
99102
redirect_uri: redirectUri,
100103
response_type: 'code',

0 commit comments

Comments
 (0)