Skip to content

Commit 7c5b9c5

Browse files
authored
[Bugfix] Ensure the org switch flow works with redirect (#327)
* Ensure the org switch flow works with redirect * Add the changeset
1 parent 232f1ee commit 7c5b9c5

5 files changed

Lines changed: 79 additions & 12 deletions

File tree

.changeset/tricky-gifts-compare.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@slashid/react": patch
3+
---
4+
5+
Fix the issue with HRD and SSO in redirect mode

packages/react/src/context/slash-id-context.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ import {
3030
createEventBuffer,
3131
EventBuffer,
3232
} from "../components/form/event-buffer";
33+
import {
34+
clearOrgSwitchingFlag,
35+
getStorageKeyForOrgSwitchingUser,
36+
LEGACY_STORAGE_TOKEN_KEY,
37+
raiseOrgSwitchingFlag,
38+
shouldResumeOrgSwitchingFlow,
39+
STORAGE_TOKEN_KEY,
40+
} from "../domain/org";
3341

3442
export type StorageOption = "memory" | "localStorage" | "cookie";
3543

@@ -136,11 +144,6 @@ export const SlashIDContext =
136144
createContext<ISlashIDContext>(initialContextValue);
137145
SlashIDContext.displayName = "SlashIDContext";
138146

139-
export const LEGACY_STORAGE_TOKEN_KEY = "@slashid/USER_TOKEN";
140-
141-
export const STORAGE_TOKEN_KEY = (oid: string) =>
142-
`${LEGACY_STORAGE_TOKEN_KEY}/${oid}`;
143-
144147
const createStorage = (storageType: StorageOption) => {
145148
switch (storageType) {
146149
case "memory":
@@ -225,7 +228,11 @@ export const SlashIDProvider = ({
225228
}
226229

227230
setUser(newUser);
228-
storageRef.current?.setItem(currentOrgStorageTokenKey, newUser.token);
231+
232+
storageRef.current?.setItem(
233+
getStorageKeyForOrgSwitchingUser(newUser) || currentOrgStorageTokenKey,
234+
newUser.token
235+
);
229236
},
230237
[state, currentOrgStorageTokenKey]
231238
);
@@ -254,6 +261,7 @@ export const SlashIDProvider = ({
254261
if (isNewOidTokenValid) {
255262
newToken = newOidToken;
256263
} else {
264+
raiseOrgSwitchingFlag();
257265
newToken = await user.getTokenForOrganization(newOid);
258266
}
259267

@@ -264,6 +272,7 @@ export const SlashIDProvider = ({
264272
setToken(newToken);
265273
setOid(newOid);
266274
setOrgSwitchingState({ state: "idle" });
275+
clearOrgSwitchingFlag();
267276

268277
return new User(newToken, sidRef.current);
269278
},
@@ -621,7 +630,11 @@ export const SlashIDProvider = ({
621630
],
622631
{
623632
until: (value) => value !== null,
624-
then: () => {
633+
then: (foundUser) => {
634+
if (foundUser && shouldResumeOrgSwitchingFlow(oid, foundUser)) {
635+
__switchOrganizationInContext({ oid: foundUser.oid });
636+
}
637+
625638
setState("ready");
626639
},
627640
}
@@ -636,6 +649,8 @@ export const SlashIDProvider = ({
636649
storeUser,
637650
token,
638651
validateToken,
652+
oid,
653+
__switchOrganizationInContext,
639654
]);
640655

641656
const contextValue = useMemo<ISlashIDContext>(() => {

packages/react/src/domain/org.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { AnonymousUser, User } from "@slashid/slashid";
2+
3+
export const LEGACY_STORAGE_TOKEN_KEY = "@slashid/USER_TOKEN";
4+
5+
export const STORAGE_TOKEN_KEY = (oid: string) =>
6+
`${LEGACY_STORAGE_TOKEN_KEY}/${oid}`;
7+
8+
export const ORG_SWITCHING_FLAG_KEY = "@slashid/ORG_SWITCHING_FLOW";
9+
10+
export function getStorageKeyForOrgSwitchingUser(user: User | AnonymousUser) {
11+
if (sessionStorage && sessionStorage.getItem(ORG_SWITCHING_FLAG_KEY)) {
12+
return STORAGE_TOKEN_KEY(user.oid);
13+
}
14+
}
15+
16+
/**
17+
* When using SSO in org switching flows with Home Realm Discovery,
18+
* redirect UX mode will cause the SDK not to switch to the proper org upon returning to the redirect URL.
19+
*
20+
* To fix that, we raise a flag in session storage and ensure the flow is done once we load the page again.
21+
*/
22+
export function raiseOrgSwitchingFlag() {
23+
if (sessionStorage) {
24+
sessionStorage.setItem(ORG_SWITCHING_FLAG_KEY, "in_progress");
25+
}
26+
}
27+
28+
export function clearOrgSwitchingFlag() {
29+
if (sessionStorage) {
30+
sessionStorage.removeItem(ORG_SWITCHING_FLAG_KEY);
31+
}
32+
}
33+
34+
export function shouldResumeOrgSwitchingFlow(
35+
oid: string,
36+
user: User | AnonymousUser | undefined | null
37+
) {
38+
if (
39+
sessionStorage &&
40+
sessionStorage.getItem(ORG_SWITCHING_FLAG_KEY) &&
41+
user &&
42+
oid !== user.oid
43+
) {
44+
return true;
45+
}
46+
47+
clearOrgSwitchingFlag();
48+
return false;
49+
}

packages/react/src/tests/anonymous-users.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { renderHook, waitFor } from "@testing-library/react";
44
import { useSlashID, SlashIDProvider } from "../main";
55
import { createAnonymousTestUser } from "../components/test-utils";
66
import { SlashID } from "@slashid/slashid";
7-
import { STORAGE_TOKEN_KEY } from "../context/slash-id-context";
7+
import { STORAGE_TOKEN_KEY } from "../domain/org";
88

99
describe("Anonymous users", () => {
1010
afterEach(() => {

packages/react/src/tests/token-storage.test.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ import {
77
useSlashID,
88
} from "../main";
99
import { createTestUser, TEST_ORG_ID } from "../components/test-utils";
10-
import {
11-
LEGACY_STORAGE_TOKEN_KEY,
12-
STORAGE_TOKEN_KEY,
13-
} from "../context/slash-id-context";
10+
1411
import userEvent from "@testing-library/user-event";
12+
import { STORAGE_TOKEN_KEY, LEGACY_STORAGE_TOKEN_KEY } from "../domain/org";
1513

1614
describe("token storage key with org id suffix", () => {
1715
const getItemSpy = vi.spyOn(Storage.prototype, "getItem");

0 commit comments

Comments
 (0)