Skip to content

Commit

Permalink
update to include any params available in oauth authorize
Browse files Browse the repository at this point in the history
  • Loading branch information
codercatdev committed Nov 8, 2024
1 parent 1b5643c commit 2b71e23
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 7 deletions.
5 changes: 5 additions & 0 deletions packages/core/src/SDKConfig/SDKConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export interface SDKConfig {
*/
scope?: string;

/**
* Additional params passed to loginPath typically `/app/login/`, which redirects to `/oauth2/authorize`. Example of this might be loginParams = [{idp_hint:'44449786-3dff-42a6-aac6-1f1ceecb6c46'}] or any params found at https://fusionauth.io/docs/lifecycle/authenticate-users/oauth/endpoints
*/
authParams?: { [key: string]: any }[];

/**
* The redirect URI for post-logout. Defaults the provided `redirectUri`.
*/
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/SDKCore/SDKCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class SDKCore {
clientId: config.clientId,
redirectUri: config.redirectUri,
scope: config.scope,
authParams: config.authParams,
mePath: config.mePath,
loginPath: config.loginPath,
registerPath: config.registerPath,
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/UrlHelper/UrlHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('UrlHelper', () => {
clientId: 'abc123',
redirectUri: 'http://my-client',
scope: 'openid email profile offline_access',
authParams: [{ idp_hint: '44449786-3dff-42a6-aac6-1f1ceecb6c46' }],
postLogoutRedirectUri: 'http://example.com',
};

Expand All @@ -31,6 +32,16 @@ describe('UrlHelper', () => {
expect(loginUrl.searchParams.get('state')).toBe(stateValue);
});

it('login url authParams', () => {
const stateValue = 'login-state-value';
const loginUrl = urlHelper.getLoginUrl(stateValue);
expect(loginUrl.origin).toBe(config.serverUrl);
expect(loginUrl.pathname).toBe('/app/login/');
expect(loginUrl.searchParams.get('idp_hint')).toBe(
config.authParams?.at(0)?.idp_hint,
);
});

it('register url', () => {
const stateValue = 'register-state-value';
const registerUrl = urlHelper.getRegisterUrl(stateValue);
Expand Down
21 changes: 17 additions & 4 deletions packages/core/src/UrlHelper/UrlHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export class UrlHelper {
clientId: string;
redirectUri: string;
scope?: string;
authParams?: { [key: string]: any }[];

mePath: string;
loginPath: string;
Expand All @@ -19,6 +20,7 @@ export class UrlHelper {
this.clientId = config.clientId;
this.redirectUri = config.redirectUri;
this.scope = config.scope;
this.authParams = config.authParams;
this.postLogoutRedirectUri = config.postLogoutRedirectUri;

this.mePath = config.mePath ?? '/app/me/';
Expand All @@ -37,6 +39,7 @@ export class UrlHelper {
client_id: this.clientId,
redirect_uri: this.redirectUri,
scope: this.scope,
authParams: this.authParams,
state,
});
}
Expand All @@ -46,6 +49,7 @@ export class UrlHelper {
client_id: this.clientId,
redirect_uri: this.redirectUri,
scope: this.scope,
authParams: this.authParams,
state,
});
}
Expand Down Expand Up @@ -85,13 +89,22 @@ export class UrlHelper {
params: UrlHelperQueryParams,
): URLSearchParams {
const urlSearchParams = new URLSearchParams();
this.appendParams(params, urlSearchParams);
return urlSearchParams;
}

private appendParams(
params: Record<string, any>, // or a more specific type if known
urlSearchParams: URLSearchParams,
): void {
Object.entries(params).forEach(([key, value]) => {
if (value) {
urlSearchParams.append(key, value);
if ((value && typeof value === 'object') || Array.isArray(value)) {
// Recursively handle nested objects
this.appendParams(value, urlSearchParams);
} else if (value !== undefined && value !== null) {
// Append primitive values
urlSearchParams.append(key, String(value));
}
});

return urlSearchParams;
}
}
2 changes: 2 additions & 0 deletions packages/core/src/UrlHelper/UrlHelperTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type UrlHelperConfig = Pick<
| 'logoutPath'
| 'tokenRefreshPath'
| 'scope'
| 'authParams'
| 'postLogoutRedirectUri'
>;

Expand All @@ -21,5 +22,6 @@ export type UrlHelperQueryParams = {
redirect_uri?: string;
post_logout_redirect_uri?: string;
scope?: string;
authParams?: { [key: string]: any }[];
state?: string;
};
4 changes: 4 additions & 0 deletions packages/sdk-react/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
fusionauth-react-sdk Changes

Changes in 2.5.0

- Allows for available paramaters to be passed for the `/oauth2/authorize` redirect that occurs after the hosted backend login from `/app/login`. Addresses issue [164](https://github.com/FusionAuth/fusionauth-javascript-sdk/issues/164)

Changes in 2.4.3

- Correctly address issues with config and `isLoggedIn` in [169](https://github.com/FusionAuth/fusionauth-javascript-sdk/pull/169)
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fusionauth/react-sdk",
"version": "2.4.3",
"version": "2.5.0",
"private": false,
"description": "FusionAuth solves the problem of building essential security without adding risk or distracting from your primary application",
"type": "module",
Expand Down Expand Up @@ -63,4 +63,4 @@
"vite-plugin-dts": "^3.7.3",
"vitest": "^1.3.1"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import {
removeAt_expCookie,
mockWindowLocation,
} from '@fusionauth-sdk/core';
import { TEST_CONFIG } from '#testing-tools/mocks/testConfig';
import {
TEST_CONFIG,
TEST_AUTHPARAM_CONFIG,
} from '#testing-tools/mocks/testConfig';

function renderWithWrapper<T = UserInfo>(config: FusionAuthProviderConfig) {
return renderHook(() => useFusionAuth<T>(), {
Expand Down Expand Up @@ -49,6 +52,31 @@ describe('FusionAuthProvider', () => {
expect(mockedLocation.assign).toHaveBeenCalledWith(expectedUrl);
});

test('Redirects to the correct login url with idp_hint', () => {
const mockedLocation = mockWindowLocation(vi);

const { result } = renderWithWrapper(TEST_AUTHPARAM_CONFIG);

const stateValue = 'state-value';
result.current.startLogin(stateValue);

const expectedUrl = new URL(TEST_AUTHPARAM_CONFIG.serverUrl);
expectedUrl.pathname = '/app/login/';
expectedUrl.searchParams.set('client_id', TEST_AUTHPARAM_CONFIG.clientId);
expectedUrl.searchParams.set(
'redirect_uri',
TEST_AUTHPARAM_CONFIG.redirectUri,
);
expectedUrl.searchParams.set('scope', TEST_AUTHPARAM_CONFIG.scope!);
expectedUrl.searchParams.set(
'idp_hint',
TEST_AUTHPARAM_CONFIG?.authParams?.at(0)?.idp_hint,
);
expectedUrl.searchParams.set('state', stateValue);

expect(mockedLocation.assign).toHaveBeenCalledWith(expectedUrl);
});

test('Redirects to the correct logout url', () => {
const mockedLocation = mockWindowLocation(vi);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function FusionAuthProvider<T = DefaultUserInfo>(
clientId: props.clientId,
redirectUri: props.redirectUri,
scope: props.scope,
authParams: props.authParams,
postLogoutRedirectUri: props.postLogoutRedirectUri,
shouldAutoRefresh: props.shouldAutoRefresh,
shouldAutoFetchUserInfo: props.shouldAutoFetchUserInfo,
Expand All @@ -46,6 +47,7 @@ function FusionAuthProvider<T = DefaultUserInfo>(
props.clientId,
props.redirectUri,
props.scope,
props.authParams,
props.postLogoutRedirectUri,
props.shouldAutoRefresh,
props.shouldAutoFetchUserInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ export interface FusionAuthProviderConfig {
*/
scope?: string;

/**
* Additional params passed to loginPath typically `/app/login/`, which redirects to `/oauth2/authorize`. Example of this might be loginParams = [{idp_hint:'44449786-3dff-42a6-aac6-1f1ceecb6c46'}] or any params found at https://fusionauth.io/docs/lifecycle/authenticate-users/oauth/endpoints
*/
authParams?: { [key: string]: any }[];

/**
* The redirect URI for post-logout. Defaults the provided `redirectUri`.
*/
Expand Down
9 changes: 9 additions & 0 deletions packages/sdk-react/src/testing-tools/mocks/testConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,12 @@ export const TEST_CONFIG: FusionAuthProviderConfig = {
scope: 'openid email profile offline_access',
postLogoutRedirectUri: 'http://localhost',
};

export const TEST_AUTHPARAM_CONFIG: FusionAuthProviderConfig = {
clientId: '85a03867-dccf-4882-adde-1a79aeec50df',
serverUrl: 'http://localhost:9000',
redirectUri: 'http://localhost',
scope: 'openid email profile offline_access',
authParams: [{ idp_hint: '44449786-3dff-42a6-aac6-1f1ceecb6c46' }],
postLogoutRedirectUri: 'http://localhost',
};

0 comments on commit 2b71e23

Please sign in to comment.