Skip to content

Commit

Permalink
fix(oidc): ensure unique tabIds when page is duplicated (beta) (#1448)
Browse files Browse the repository at this point in the history
Co-authored-by: mkrzempek <mkrzempek@guidewire.com>
  • Loading branch information
krzempekk and mkrzempek authored Sep 11, 2024
1 parent ad18d60 commit 4f9ca8e
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 11 deletions.
13 changes: 2 additions & 11 deletions packages/oidc-client/src/initWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,8 @@ export const defaultServiceWorkerUpdateRequireCallback =
location.reload();
};

const getTabId = (configurationName: string) => {
const tabId = sessionStorage.getItem(`oidc.tabId.${configurationName}`);

if (tabId) {
return tabId;
}

const newTabId = globalThis.crypto.randomUUID();
sessionStorage.setItem(`oidc.tabId.${configurationName}`, newTabId);
return newTabId;
};
const getTabId = (configurationName: string) =>
sessionStorage.getItem(`oidc.tabId.${configurationName}`);

const sendMessageAsync =
registration =>
Expand Down
1 change: 1 addition & 0 deletions packages/oidc-client/src/keepSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const tryKeepSessionAsync = async (oidc: Oidc) => {
configuration.authority,
configuration.authority_configuration,
);
await oidc.ensureUniqueTabId();
serviceWorker = await initWorkerAsync(configuration, oidc.configurationName);
if (serviceWorker) {
const { tokens } = await serviceWorker.initAsync(
Expand Down
1 change: 1 addition & 0 deletions packages/oidc-client/src/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ export const loginCallbackAsync =
const href = oidc.location.getCurrentHref();
const queryParams = getParseQueryStringFromLocation(href);
const sessionState = queryParams.session_state;
await oidc.ensureUniqueTabId();
const serviceWorker = await initWorkerAsync(configuration, oidc.configurationName);
let storage;
let nonceData;
Expand Down
1 change: 1 addition & 0 deletions packages/oidc-client/src/logout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const destroyAsync = oidc => async status => {
if (oidc.checkSessionIFrame) {
oidc.checkSessionIFrame.stop();
}
await oidc.ensureUniqueTabId();
const serviceWorker = await initWorkerAsync(oidc.configuration, oidc.configurationName);
if (!serviceWorker) {
const session = initSession(oidc.configurationName, oidc.configuration.storage);
Expand Down
47 changes: 47 additions & 0 deletions packages/oidc-client/src/oidc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ export class Oidc {
public checkSessionIFrame: CheckSessionIFrame;
public getFetch: () => Fetch;
public location: ILOidcLocation;
public tabId: string;
private channel: BroadcastChannel;
constructor(
configuration: OidcConfiguration,
configurationName = 'default',
Expand Down Expand Up @@ -158,9 +160,52 @@ export class Oidc {
this.destroyAsync.bind(this);
this.logoutAsync.bind(this);
this.renewTokensAsync.bind(this);
this.ensureUniqueTabId.bind(this);
this.initAsync(this.configuration.authority, this.configuration.authority_configuration);
}

async ensureUniqueTabId() {
const generateUniqueTabId = () => {
const newTabId = globalThis.crypto.randomUUID();
sessionStorage.setItem(`oidc.tabId.${this.configurationName}`, newTabId);
this.tabId = newTabId;
};

if (!this.channel) {
this.channel = new BroadcastChannel(`oidc.broadcast-channel.${this.configurationName}`);
this.channel.onmessage = msg => {
const type = msg?.data?.type;
const tabId = msg?.data?.tabId;

if (tabId === this.tabId) {
if (type === 'SEARCH') {
this.channel.postMessage({ type: 'FOUND', tabId });
} else if (type === 'FOUND') {
generateUniqueTabId();
}
}
};
}

const tabId = sessionStorage.getItem(`oidc.tabId.${this.configurationName}`);

if (!tabId) {
generateUniqueTabId();
return;
}

this.channel.postMessage({ type: 'SEARCH', tabId });
await new Promise<void>(resolve =>
setTimeout(() => {
// if there is no tabId, it means that duplicate wasn't found
if (!this.tabId) {
this.tabId = tabId;
}
resolve();
}, 500),
);
}

subscribeEvents(func): string {
const id = getRandomInt(9999999999999).toString();
this.events.push({ id, func });
Expand Down Expand Up @@ -252,6 +297,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
});
}

await this.ensureUniqueTabId();
const serviceWorker = await initWorkerAsync(this.configuration, this.configurationName);
const storage = serviceWorker ? window.localStorage : null;
return await fetchFromIssuer(this.getFetch())(
Expand Down Expand Up @@ -320,6 +366,7 @@ Please checkout that you are using OIDC hook inside a <OidcProvider configuratio
this,
)(extras, scope);
}
await this.ensureUniqueTabId();
this.loginPromise = defaultLoginAsync(
this.configurationName,
this.configuration,
Expand Down
6 changes: 6 additions & 0 deletions packages/oidc-client/src/renewTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ async function syncTokens(oidc: Oidc, forceRefresh: boolean, extras: StringMap)
extras,
);

await oidc.ensureUniqueTabId();
const serviceWorker = await initWorkerAsync(oidc.configuration, oidc.configurationName);
if (!serviceWorker) {
const session = initSession(oidc.configurationName, oidc.configuration.storage);
Expand All @@ -36,6 +37,7 @@ const loadLatestTokensAsync = async (
oidc: Oidc,
configuration: OidcConfiguration,
): Promise<Tokens> => {
await oidc.ensureUniqueTabId();
const serviceWorker = await initWorkerAsync(configuration, oidc.configurationName);
if (serviceWorker) {
const oidcServerConfiguration = await oidc.initAsync(
Expand Down Expand Up @@ -66,6 +68,7 @@ export async function renewTokensAndStartTimerAsync(
const lockResourcesName = `${configuration.client_id}_${oidc.configurationName}_${configuration.authority}`;

let tokens: null;
await oidc.ensureUniqueTabId();
const serviceWorker = await initWorkerAsync(oidc.configuration, oidc.configurationName);

if (configuration?.storage === window?.sessionStorage && !serviceWorker) {
Expand Down Expand Up @@ -134,6 +137,7 @@ export const syncTokensInfoAsync =
configuration.authority,
configuration.authority_configuration,
);
await oidc.ensureUniqueTabId();
const serviceWorker = await initWorkerAsync(configuration, configurationName);
if (serviceWorker) {
const { status, tokens } = await serviceWorker.initAsync(
Expand Down Expand Up @@ -228,6 +232,7 @@ const synchroniseTokensAsync =
const localsilentLoginAsync = async () => {
try {
let loginParams;
await oidc.ensureUniqueTabId();
const serviceWorker = await initWorkerAsync(configuration, oidc.configurationName);
if (serviceWorker) {
loginParams = serviceWorker.getLoginParams();
Expand Down Expand Up @@ -390,6 +395,7 @@ const synchroniseTokensAsync =
}
updateTokens(tokenResponse.data);
if (tokenResponse.demonstratingProofOfPossessionNonce) {
await oidc.ensureUniqueTabId();
const serviceWorker = await initWorkerAsync(configuration, oidc.configurationName);
if (serviceWorker) {
await serviceWorker.setDemonstratingProofOfPossessionNonce(
Expand Down

0 comments on commit 4f9ca8e

Please sign in to comment.