Skip to content

Commit af2e859

Browse files
committed
fix(oidc-client): address PR feedback
1 parent 98f1e5c commit af2e859

12 files changed

Lines changed: 167 additions & 248 deletions

File tree

.changeset/brave-foxes-dance.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
'@forgerock/oidc-client': minor
44
---
55

6-
Add `session.check()` method to oidc client for OIDC prompt=none session verification, with `response_type=none` and `response_type=id_token` support.
6+
Add `user.session()` method to oidc client for OIDC prompt=none session verification, with `response_type=none` and `response_type=id_token` support.

e2e/oidc-app/src/utils/oidc-app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ export async function oidcApp({
215215
});
216216

217217
document.getElementById('session-check-btn')?.addEventListener('click', async () => {
218-
const result = await oidcClient.session?.check();
218+
const result = await oidcClient.user?.session();
219219
const appEl = document.getElementById('app');
220220
const el = document.createElement('div');
221221
el.innerHTML = `<p><strong>Session Check (none):</strong></p><pre id="session-check-result">${JSON.stringify(result, null, 2)}</pre>`;
@@ -224,7 +224,7 @@ export async function oidcApp({
224224

225225
document.getElementById('session-check-id-token-btn')?.addEventListener('click', async () => {
226226
const options: SessionCheckOptions = { responseType: 'id_token' };
227-
const result = await oidcClient.session?.check(options);
227+
const result = await oidcClient.user?.session(options);
228228
const appEl = document.getElementById('app');
229229
const el = document.createElement('div');
230230
el.innerHTML = `<p><strong>Session Check (id_token):</strong></p><pre id="session-check-id-token-result">${JSON.stringify(result, null, 2)}</pre>`;

e2e/oidc-suites/src/session.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function makeFakeJwt(payload: Record<string, unknown>): string {
2929
return `${header}.${body}.fakesignature`;
3030
}
3131

32-
test.describe('session.check() tests', () => {
32+
test.describe('user.session() tests', () => {
3333
test('session check (none) succeeds after login', async ({ page }) => {
3434
const { navigate } = asyncEvents(page);
3535
await navigate('/ping-am/');
@@ -126,6 +126,7 @@ test.describe('session.check() tests', () => {
126126
await page.getByRole('button', { name: 'Session Check (id_token)' }).click();
127127
await expect(page.locator('#session-check-id-token-result')).not.toBeEmpty();
128128
const resultText = await page.locator('#session-check-id-token-result').textContent();
129+
expect(resultText).toContain('"mode"');
129130
expect(resultText).toContain('"claims"');
130131
expect(resultText).not.toContain('"error"');
131132
});

packages/oidc-client/api-report/oidc-client.api.md

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type { FetchBaseQueryError } from '@reduxjs/toolkit/query';
1515
import { FetchBaseQueryMeta } from '@reduxjs/toolkit/query';
1616
import { GenericError } from '@forgerock/sdk-types';
1717
import { GetAuthorizationUrlOptions } from '@forgerock/sdk-types';
18+
import type { JWTPayload } from 'jose';
1819
import { logger } from '@forgerock/sdk-logger';
1920
import { LogLevel } from '@forgerock/sdk-logger';
2021
import { LogMessage } from '@forgerock/sdk-logger';
@@ -277,7 +278,6 @@ export function oidc<ActionType extends ActionTypes = ActionTypes>(input: {
277278
authorize?: undefined;
278279
token?: undefined;
279280
user?: undefined;
280-
session?: undefined;
281281
} | {
282282
subscribe: (listener: () => void) => Unsubscribe;
283283
authorize: {
@@ -292,9 +292,7 @@ export function oidc<ActionType extends ActionTypes = ActionTypes>(input: {
292292
user: {
293293
info: () => Promise<GenericError | UserInfoResponse>;
294294
logout: () => Promise<GenericError | LogoutSuccessResult | LogoutErrorResult>;
295-
};
296-
session: {
297-
check: (options?: SessionCheckOptions) => Promise<SessionCheckSuccess | GenericError>;
295+
session: (options?: SessionCheckOptions) => Promise<SessionCheckSuccess | GenericError>;
298296
};
299297
error?: undefined;
300298
type?: undefined;
@@ -362,18 +360,15 @@ export interface SessionCheckOptions {
362360
}
363361

364362
// @public (undocumented)
365-
export const SessionCheckResponseType: {
366-
readonly IdToken: "id_token";
367-
readonly None: "none";
368-
};
369-
370-
// @public (undocumented)
371-
export type SessionCheckResponseType = (typeof SessionCheckResponseType)[keyof typeof SessionCheckResponseType];
363+
export type SessionCheckResponseType = 'id_token' | 'none';
372364

373365
// @public (undocumented)
374-
export interface SessionCheckSuccess {
375-
claims?: Record<string, unknown>;
376-
}
366+
export type SessionCheckSuccess = {
367+
mode: 'none';
368+
} | {
369+
mode: 'id_token';
370+
claims: JWTPayload;
371+
};
377372

378373
export { StorageConfig }
379374

packages/oidc-client/api-report/oidc-client.types.api.md

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type { FetchBaseQueryError } from '@reduxjs/toolkit/query';
1515
import { FetchBaseQueryMeta } from '@reduxjs/toolkit/query';
1616
import { GenericError } from '@forgerock/sdk-types';
1717
import { GetAuthorizationUrlOptions } from '@forgerock/sdk-types';
18+
import type { JWTPayload } from 'jose';
1819
import { logger } from '@forgerock/sdk-logger';
1920
import { LogLevel } from '@forgerock/sdk-logger';
2021
import { LogMessage } from '@forgerock/sdk-logger';
@@ -277,7 +278,6 @@ export function oidc<ActionType extends ActionTypes = ActionTypes>(input: {
277278
authorize?: undefined;
278279
token?: undefined;
279280
user?: undefined;
280-
session?: undefined;
281281
} | {
282282
subscribe: (listener: () => void) => Unsubscribe;
283283
authorize: {
@@ -292,9 +292,7 @@ export function oidc<ActionType extends ActionTypes = ActionTypes>(input: {
292292
user: {
293293
info: () => Promise<GenericError | UserInfoResponse>;
294294
logout: () => Promise<GenericError | LogoutSuccessResult | LogoutErrorResult>;
295-
};
296-
session: {
297-
check: (options?: SessionCheckOptions) => Promise<SessionCheckSuccess | GenericError>;
295+
session: (options?: SessionCheckOptions) => Promise<SessionCheckSuccess | GenericError>;
298296
};
299297
error?: undefined;
300298
type?: undefined;
@@ -362,18 +360,15 @@ export interface SessionCheckOptions {
362360
}
363361

364362
// @public (undocumented)
365-
export const SessionCheckResponseType: {
366-
readonly IdToken: "id_token";
367-
readonly None: "none";
368-
};
369-
370-
// @public (undocumented)
371-
export type SessionCheckResponseType = (typeof SessionCheckResponseType)[keyof typeof SessionCheckResponseType];
363+
export type SessionCheckResponseType = 'id_token' | 'none';
372364

373365
// @public (undocumented)
374-
export interface SessionCheckSuccess {
375-
claims?: Record<string, unknown>;
376-
}
366+
export type SessionCheckSuccess = {
367+
mode: 'none';
368+
} | {
369+
mode: 'id_token';
370+
claims: JWTPayload;
371+
};
377372

378373
export { StorageConfig }
379374

packages/oidc-client/src/lib/client.store.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,7 @@ describe('authorize.url() with PAR enabled on non-pi.flow server', async () => {
719719
});
720720
});
721721

722-
describe('session.check()', async () => {
722+
describe('user.session()', async () => {
723723
const config: OidcConfig = {
724724
clientId: '123456789',
725725
redirectUri: 'https://example.com/callback.html',
@@ -740,7 +740,7 @@ describe('session.check()', async () => {
740740
const oidcClient = await oidc({ config, storage: customStorageConfig });
741741
if ('error' in oidcClient) throw new Error('Error creating OIDC Client');
742742

743-
const result = await oidcClient.session.check();
743+
const result = await oidcClient.user.session();
744744

745745
if (!('error' in result)) {
746746
expect.fail('Expected SessionCheckError, got success');

packages/oidc-client/src/lib/client.store.ts

Lines changed: 13 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { causeIsDie, exitIsFail, exitIsSuccess } from 'effect/Micro';
1212

1313
import { authorizeµ, createParAuthorizeUrlµ } from './authorize.request.js';
1414
import { buildTokenExchangeµ } from './exchange.request.js';
15-
import { createClientStore, createTokenError } from './client.store.utils.js';
15+
import { createClientStore, createTokenError, runMicroExit } from './client.store.utils.js';
1616
import { isExpiryWithinThreshold } from './token.utils.js';
1717
import { logoutµ } from './logout.request.js';
1818
import { oidcApi } from './oidc.api.js';
@@ -35,7 +35,6 @@ import type {
3535
import type { OauthTokens, OidcConfig } from './config.types.js';
3636
import type { AuthorizationError, AuthorizationSuccess } from './authorize.request.types.js';
3737
import type { TokenExchangeErrorResponse } from './exchange.types.js';
38-
import { SessionCheckResponseType } from './session.types.js';
3938
import type { SessionCheckOptions, SessionCheckSuccess } from './session.types.js';
4039

4140
/**
@@ -258,20 +257,7 @@ export async function oidc<ActionType extends ActionTypes = ActionTypes>({
258257
}),
259258
);
260259

261-
const result = await Micro.runPromiseExit(getTokensµ);
262-
263-
if (exitIsSuccess(result)) {
264-
return result.value;
265-
} else if (exitIsFail(result)) {
266-
return result.cause.error;
267-
} else {
268-
const defect = causeIsDie(result.cause) ? result.cause.defect : undefined;
269-
return {
270-
error: 'Token Exchange failure',
271-
message: defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'),
272-
type: 'exchange_error',
273-
};
274-
}
260+
return runMicroExit(getTokensµ, 'Token Exchange failure', 'exchange_error');
275261
},
276262

277263
/**
@@ -457,20 +443,7 @@ export async function oidc<ActionType extends ActionTypes = ActionTypes>({
457443
),
458444
);
459445

460-
const result = await Micro.runPromiseExit(revokeµ);
461-
462-
if (exitIsSuccess(result)) {
463-
return result.value;
464-
} else if (exitIsFail(result)) {
465-
return result.cause.error;
466-
} else {
467-
const defect = causeIsDie(result.cause) ? result.cause.defect : undefined;
468-
return {
469-
error: 'Token revocation failure',
470-
message: defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'),
471-
type: 'auth_error',
472-
};
473-
}
446+
return runMicroExit(revokeµ, 'Token revocation failure', 'auth_error');
474447
},
475448
},
476449

@@ -533,20 +506,7 @@ export async function oidc<ActionType extends ActionTypes = ActionTypes>({
533506
}),
534507
);
535508

536-
const result = await Micro.runPromiseExit(info);
537-
538-
if (exitIsSuccess(result)) {
539-
return result.value;
540-
} else if (exitIsFail(result)) {
541-
return result.cause.error;
542-
} else {
543-
const defect = causeIsDie(result.cause) ? result.cause.defect : undefined;
544-
return {
545-
error: 'User Info retrieval failure',
546-
message: defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'),
547-
type: 'auth_error',
548-
};
549-
}
509+
return runMicroExit(info, 'User Info retrieval failure', 'auth_error');
550510
},
551511

552512
/**
@@ -587,38 +547,24 @@ export async function oidc<ActionType extends ActionTypes = ActionTypes>({
587547
return createTokenError('no_id_token');
588548
}
589549

590-
const result = await Micro.runPromiseExit(
550+
return runMicroExit(
591551
logoutµ({ tokens, config, wellknown, store, storageClient }),
552+
'Logout_Failure',
553+
'auth_error',
592554
);
593-
594-
if (exitIsSuccess(result)) {
595-
return result.value;
596-
} else if (exitIsFail(result)) {
597-
return result.cause.error;
598-
} else {
599-
const defect = causeIsDie(result.cause) ? result.cause.defect : undefined;
600-
return {
601-
error: 'Logout_Failure',
602-
message: defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'),
603-
type: 'auth_error',
604-
};
605-
}
606555
},
607-
},
608556

609-
/**
610-
* An object containing methods for OIDC session management
611-
*/
612-
session: {
613557
/**
614-
* @method check
558+
* @method session
615559
* @description Checks whether the user has an active session at the authorization server
616560
* using a hidden iframe with prompt=none. Supports response_type=none (default)
617561
* and response_type=id_token.
618562
* @param {SessionCheckOptions} options - Optional parameters for the session check.
619563
* @returns {Promise<SessionCheckSuccess | GenericError>} - Never throws; returns a typed result.
620564
*/
621-
check: async (options?: SessionCheckOptions): Promise<SessionCheckSuccess | GenericError> => {
565+
session: async (
566+
options?: SessionCheckOptions,
567+
): Promise<SessionCheckSuccess | GenericError> => {
622568
const state = store.getState();
623569
const wellknown = wellknownSelector(wellknownUrl, state);
624570

@@ -631,24 +577,11 @@ export async function oidc<ActionType extends ActionTypes = ActionTypes>({
631577
}
632578

633579
const micro =
634-
options?.responseType === SessionCheckResponseType.IdToken
580+
options?.responseType === 'id_token'
635581
? sessionCheckIdTokenµ(wellknown, config, store, storageClient, log, options)
636582
: sessionCheckNoneµ(wellknown, config, store, storageClient, log, options);
637583

638-
const result = await Micro.runPromiseExit(micro);
639-
640-
if (exitIsSuccess(result)) {
641-
return result.value;
642-
} else if (exitIsFail(result)) {
643-
return result.cause.error;
644-
} else {
645-
const defect = causeIsDie(result.cause) ? result.cause.defect : undefined;
646-
return {
647-
error: 'Session check failure',
648-
message: defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'),
649-
type: 'unknown_error',
650-
};
651-
}
584+
return runMicroExit(micro, 'Session check failure', 'unknown_error');
652585
},
653586
},
654587
};

packages/oidc-client/src/lib/client.store.utils.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import type { ActionTypes, RequestMiddleware } from '@forgerock/sdk-request-midd
88
import { logger as loggerFn } from '@forgerock/sdk-logger';
99

1010
import { configureStore, type SerializedError } from '@reduxjs/toolkit';
11+
import { Micro } from 'effect';
12+
import { causeIsDie, exitIsFail, exitIsSuccess } from 'effect/Micro';
1113
import { oidcApi } from './oidc.api.js';
1214
import { wellknownApi } from './wellknown.api.js';
1315

@@ -82,6 +84,26 @@ export function createLogoutError(
8284
return null;
8385
}
8486

87+
export async function runMicroExit<T, E>(
88+
micro: Micro.Micro<T, E>,
89+
defectError: string,
90+
defectType: GenericError['type'],
91+
): Promise<T | E | GenericError> {
92+
const result = await Micro.runPromiseExit(micro);
93+
if (exitIsSuccess(result)) {
94+
return result.value;
95+
}
96+
if (exitIsFail(result)) {
97+
return result.cause.error;
98+
}
99+
const defect = causeIsDie(result.cause) ? result.cause.defect : undefined;
100+
return {
101+
error: defectError,
102+
message: defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'),
103+
type: defectType,
104+
};
105+
}
106+
85107
export function createTokenError(type: 'no_tokens' | 'no_access_token' | 'no_id_token') {
86108
let error: GenericError;
87109

0 commit comments

Comments
 (0)