Skip to content

Commit

Permalink
fix(oidc): add allowMultiTabLogin flag for configuring multi tab logi…
Browse files Browse the repository at this point in the history
…n behaviour (release)
  • Loading branch information
mkrzempek committed Jul 12, 2024
1 parent 8245239 commit 6f99747
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 10 deletions.
3 changes: 3 additions & 0 deletions examples/react-oidc-demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ const trustedDomains = {
// scenarios which require it. For example, to send it via websocket connection.
trustedDomains.config_show_access_token = { domains : ["https://demo.duendesoftware.com"], showAccessToken: true };

// Setting allowMultiTabLogin to true will enable storing login-specific parameters (state, nonce, code verifier)
// separately for each tab. This will prevent errors when logins are initiated from multiple tabs.
trustedDomains.config_multi_tab_login = { domains : ["https://demo.duendesoftware.com"], allowMultiTabLogin: true };
```

## Run The Demo
Expand Down
5 changes: 5 additions & 0 deletions examples/react-oidc-demo/public/OidcTrustedDomains.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion examples/react-oidc-demo/src/MultiAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const MultiAuth = ({ configurationName, handleConfigurationChange }) => {;
<option value="config_show_access_token">config_show_access_token</option>
<option value="config_separate_oidc_access_token_domains">config_separate_oidc_access_token_domains</option>
<option value="config_with_dpop">config_with_dpop</option>
<option value="config_multi_tab_login">config_multi_tab_login</option>
</select>
{!isAuthenticated && <button type="button" className="btn btn-primary" onClick={() => login()}>Login</button>}
{isAuthenticatedDefault && <button type="button" className="btn btn-primary" onClick={() => login(undefined, { 'test:token_request': 'test', youhou: 'youhou', grant_type: 'tenant', tenantId: '1234' }, true)}>Silent Login</button>}
Expand Down Expand Up @@ -140,7 +141,14 @@ export const MultiAuthContainer = () => {
digestAlgorithm: { name: "SHA-256" },
jwtHeaderAlgorithm: "RS256",
},*/
}
},
config_multi_tab_login: {
...configurationIdentityServer,
redirect_uri: callBack,
silent_redirect_uri,
scope: 'openid profile email api offline_access',
client_id: 'interactive.public.short',
},
};
const handleConfigurationChange = (event) => {
const configurationName = event.target.value;
Expand Down
24 changes: 15 additions & 9 deletions packages/oidc-client-service-worker/src/OidcServiceWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ const handleMessage = async (event: ExtendableMessageEvent) => {
const convertAllRequestsToCorsExceptNavigate = Array.isArray(trustedDomain)
? false
: trustedDomain.convertAllRequestsToCorsExceptNavigate;
const allowMultiTabLogin = Array.isArray(trustedDomain)
? false
: trustedDomain.allowMultiTabLogin;
database[configurationName] = {
tokens: null,
state: {},
Expand All @@ -353,13 +356,16 @@ const handleMessage = async (event: ExtendableMessageEvent) => {
demonstratingProofOfPossessionJwkJson: null,
demonstratingProofOfPossessionConfiguration: null,
demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false,
allowMultiTabLogin: allowMultiTabLogin ?? false
};
currentDatabase = database[configurationName];

if (!trustedDomains[configurationName]) {
trustedDomains[configurationName] = [];
}
}

const tabId = currentDatabase.allowMultiTabLogin ? data.tabId : 'default';

switch (data.type) {
case 'clear':
Expand Down Expand Up @@ -415,16 +421,16 @@ const handleMessage = async (event: ExtendableMessageEvent) => {
...currentDatabase.tokens,
};
if (currentDatabase.hideAccessToken) {
tokens.access_token = TOKEN.ACCESS_TOKEN + '_' + configurationName + '_' + data.tabId;
tokens.access_token = TOKEN.ACCESS_TOKEN + '_' + configurationName + '_' + tabId;
}
if (tokens.refresh_token) {
tokens.refresh_token = TOKEN.REFRESH_TOKEN + '_' + configurationName + '_' + data.tabId;
tokens.refresh_token = TOKEN.REFRESH_TOKEN + '_' + configurationName + '_' + tabId;
}
if (tokens?.idTokenPayload?.nonce &&
currentDatabase.nonce != null
) {
tokens.idTokenPayload.nonce =
TOKEN.NONCE_TOKEN + '_' + configurationName + '_' + data.tabId;
TOKEN.NONCE_TOKEN + '_' + configurationName + '_' + tabId;
}
port.postMessage({
tokens,
Expand All @@ -451,17 +457,17 @@ const handleMessage = async (event: ExtendableMessageEvent) => {
return;
}
case 'setState': {
currentDatabase.state[data.tabId] = data.data.state;
currentDatabase.state[tabId] = data.data.state;
port.postMessage({ configurationName });
return;
}
case 'getState': {
const state = currentDatabase.state[data.tabId];
const state = currentDatabase.state[tabId];
port.postMessage({ configurationName, state });
return;
}
case 'setCodeVerifier': {
currentDatabase.codeVerifier[data.tabId] = data.data.codeVerifier;
currentDatabase.codeVerifier[tabId] = data.data.codeVerifier;
port.postMessage({ configurationName });
return;
}
Expand All @@ -470,7 +476,7 @@ const handleMessage = async (event: ExtendableMessageEvent) => {
configurationName,
codeVerifier:
currentDatabase.codeVerifier != null
? TOKEN.CODE_VERIFIER + '_' + configurationName + '_' + data.tabId
? TOKEN.CODE_VERIFIER + '_' + configurationName + '_' + tabId
: null,
});
return;
Expand All @@ -488,13 +494,13 @@ const handleMessage = async (event: ExtendableMessageEvent) => {
case 'setNonce': {
const nonce = data.data.nonce;
if (nonce) {
currentDatabase.nonce[data.tabId] = nonce;
currentDatabase.nonce[tabId] = nonce;
}
port.postMessage({ configurationName });
return;
}
case 'getNonce': {
const keyNonce = TOKEN.NONCE_TOKEN + '_' + configurationName + '_' + data.tabId;
const keyNonce = TOKEN.NONCE_TOKEN + '_' + configurationName + '_' + tabId
const nonce = currentDatabase.nonce ? keyNonce : null;
port.postMessage({ configurationName, nonce });
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const oidcConfigDefaults = {
demonstratingProofOfPossessionNonce: null,
demonstratingProofOfPossessionJwkJson: null,
demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false,
allowMultiTabLogin: true
}

const oidcServerConfigDefault = {
Expand Down
2 changes: 2 additions & 0 deletions packages/oidc-client-service-worker/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type DomainDetails = {
demonstratingProofOfPossession?:boolean;
demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent?:boolean;
demonstratingProofOfPossessionConfiguration?: DemonstratingProofOfPossessionConfiguration;
allowMultiTabLogin?: boolean;
}

export interface DemonstratingProofOfPossessionConfiguration {
Expand Down Expand Up @@ -87,6 +88,7 @@ export type OidcConfig = {
demonstratingProofOfPossessionNonce: string | null;
demonstratingProofOfPossessionJwkJson: string | null;
demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: boolean;
allowMultiTabLogin: boolean;
}

export type IdTokenPayload = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ describe('domains', () => {
demonstratingProofOfPossessionJwkJson: null,
demonstratingProofOfPossessionConfiguration: null,
demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false,
allowMultiTabLogin: true
},
};
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class OidcConfigBuilder {
demonstratingProofOfPossessionJwkJson: null,
demonstratingProofOfPossessionConfiguration: null,
demonstratingProofOfPossessionOnlyWhenDpopHeaderPresent: false,
allowMultiTabLogin: true
};

public withTestingDefault(): OidcConfigBuilder {
Expand Down

0 comments on commit 6f99747

Please sign in to comment.