@evenicanpm/storefront-core 2.4.0 → 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/package.json +90 -77
- package/src/api-manager/datasources/d365/d365-address.datasource.ts +142 -66
- package/src/api-manager/datasources/d365/d365-user.datasource.ts +109 -37
- package/src/api-manager/datasources/d365/utils/get-context-cookie.ts +44 -10
- package/src/api-manager/lib/get-graphql-client.ts +35 -7
- package/src/api-manager/services/create-query.ts +36 -3
- package/src/api-manager/services/get-query-client.ts +10 -0
- package/src/auth/better-auth.ts +282 -15
- package/src/cms/blocks/components/footer/data/index.ts +0 -0
- package/src/cms/blocks/components/footer/index.tsx +0 -0
- package/src/cms/blocks/components/footer/sections/footer-app-store.tsx +0 -0
- package/src/cms/blocks/components/footer/sections/footer-contact.tsx +0 -0
- package/src/cms/blocks/components/footer/sections/footer-links.tsx +0 -0
- package/src/cms/blocks/components/footer/sections/footer-logo.tsx +0 -0
- package/src/cms/blocks/components/footer/sections/footer-social-links.tsx +0 -0
- package/src/cms/blocks/components/footer/styles/index.ts +0 -0
- package/src/cms/blocks/components/hero-carousel/index.tsx +0 -0
- package/src/cms/blocks/components/product-carousel/index.tsx +0 -0
- package/src/cms/blocks/components/product-section-fullwidth/index.tsx +3 -1
- package/src/cms/blocks/components/shared/featured-product-card.tsx +0 -0
- package/src/cms/blocks/components/shared/product-category-item.tsx +0 -0
- package/src/cms/blocks/components/shared/product-grid.tsx +0 -0
- package/src/cms/blocks/components/shared/top-categories-card.tsx +0 -0
- package/src/cms/blocks/components/shared/top-rating-product-card.tsx +0 -0
- package/src/cms/blocks/icons/components/category.tsx +0 -0
- package/src/cms/blocks/icons/components/dotted-star.tsx +0 -0
- package/src/cms/blocks/icons/components/gift-box.tsx +0 -0
- package/src/cms/blocks/icons/components/light.tsx +0 -0
- package/src/cms/blocks/icons/components/new-arrival.tsx +0 -0
- package/src/cms/blocks/icons/components/rank-badge.tsx +0 -0
- package/src/components/categories/category-list/category-list.tsx +9 -5
- package/src/components/header/__tests__/user.test.tsx +5 -107
- package/src/components/header/components/user.tsx +72 -45
- package/src/hooks/use-nextauth-session.ts +0 -33
- package/src/lib/auth-client.ts +14 -0
- package/src/lib/auth.ts +4 -0
- package/src/lib/entra-native-auth.ts +138 -0
- package/src/lib/graphqlRequestSdk.ts +0 -0
- package/src/lib/native-session.ts +434 -0
- package/src/pages/account/profile/__tests__/profile-form.test.tsx +173 -0
- package/src/pages/account/profile/profile-form.tsx +285 -0
- package/src/pages/account/profile/profile-validation.ts +52 -0
- package/src/pages/auth/auth-activate-page.tsx +509 -0
- package/src/pages/auth/auth-layout.tsx +73 -0
- package/src/pages/auth/auth-login-page.tsx +241 -0
- package/src/pages/auth/auth-reset-password-page.tsx +487 -0
- package/src/pages/auth/compound/auth-form.tsx +182 -0
- package/src/pages/auth/compound/auth-pages.tsx +21 -0
- package/src/pages/auth/lib/friendly-error.ts +70 -0
- package/src/pages/auth/lib/index.ts +2 -0
- package/src/pages/auth/lib/types.ts +5 -0
- package/src/pages/checkout/checkout-alt-form/steps/address/delivery-address.tsx +20 -6
- package/src/pages/checkout/checkout-alt-form/steps/customer-info/customer-information.tsx +1 -1
- package/tsconfig.json +20 -14
- package/src/auth/msal.ts +0 -65
- package/src/pages/account/profile/profile-button.test.tsx +0 -59
- package/src/pages/account/profile/profile-button.tsx +0 -51
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import signOut from "@evenicanpm/storefront-core/src/auth/signout";
|
|
2
2
|
import Header from "@evenicanpm/storefront-core/src/components/header/header";
|
|
3
|
-
import { fireEvent, render, screen
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
4
|
import { NextIntlClientProvider } from "next-intl";
|
|
5
5
|
import { vi } from "vitest";
|
|
6
6
|
|
|
7
|
-
const {
|
|
8
|
-
()
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
mockUseSession: vi.fn(),
|
|
12
|
-
}),
|
|
13
|
-
);
|
|
7
|
+
const { mockUseSession } = vi.hoisted(() => ({
|
|
8
|
+
mockMutate: vi.fn().mockResolvedValue({}),
|
|
9
|
+
mockUseSession: vi.fn(),
|
|
10
|
+
}));
|
|
14
11
|
|
|
15
12
|
vi.mock(
|
|
16
13
|
"@evenicanpm/storefront-core/src/api-manager/services/session/mutations/session-init",
|
|
@@ -19,13 +16,6 @@ vi.mock(
|
|
|
19
16
|
}),
|
|
20
17
|
);
|
|
21
18
|
|
|
22
|
-
vi.mock(
|
|
23
|
-
"@evenicanpm/storefront-core/src/api-manager/services/user/mutations/update-user",
|
|
24
|
-
() => ({
|
|
25
|
-
default: () => ({ mutateAsync: mockMutate }),
|
|
26
|
-
}),
|
|
27
|
-
);
|
|
28
|
-
|
|
29
19
|
vi.mock(
|
|
30
20
|
"@evenicanpm/storefront-core/src/api-manager/services/session/mutations/session-logout",
|
|
31
21
|
() => ({
|
|
@@ -53,13 +43,6 @@ vi.mock("better-auth/client/plugins", () => ({
|
|
|
53
43
|
genericOAuthClient: () => ({}),
|
|
54
44
|
}));
|
|
55
45
|
|
|
56
|
-
vi.mock("@evenicanpm/storefront-core/src/auth/msal", () => ({
|
|
57
|
-
getMsalInstance: () => ({
|
|
58
|
-
handleRedirectPromise: mockHandleRedirectPromise,
|
|
59
|
-
}),
|
|
60
|
-
initializeMsal: vi.fn().mockResolvedValue(undefined),
|
|
61
|
-
}));
|
|
62
|
-
|
|
63
46
|
vi.mock("@evenicanpm/storefront-core/src/auth/signout", () => ({
|
|
64
47
|
default: vi.fn(),
|
|
65
48
|
}));
|
|
@@ -149,89 +132,4 @@ describe.skip("User Component", async () => {
|
|
|
149
132
|
fireEvent.click(logoutButton);
|
|
150
133
|
expect(mockSignOut).toHaveBeenCalled();
|
|
151
134
|
});
|
|
152
|
-
|
|
153
|
-
it("handles MSAL redirect and updates user on success", async () => {
|
|
154
|
-
mockUseSession.mockReturnValue({
|
|
155
|
-
data: {
|
|
156
|
-
user: { email: "test@example.com" },
|
|
157
|
-
session: { accessToken: "mockAccessToken" },
|
|
158
|
-
},
|
|
159
|
-
isPending: false,
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
vi.mocked(mockHandleRedirectPromise).mockResolvedValue({
|
|
163
|
-
authority: "https://login.microsoftonline.com/some_authority",
|
|
164
|
-
uniqueId: "some_unique_id",
|
|
165
|
-
tenantId: "some_tenant_id",
|
|
166
|
-
tokenType: "id_token",
|
|
167
|
-
correlationId: "some_correlation_id",
|
|
168
|
-
idToken: "some_id_token",
|
|
169
|
-
accessToken: "some_access_token",
|
|
170
|
-
fromCache: false,
|
|
171
|
-
expiresOn: new Date(Date.now() + 3600000),
|
|
172
|
-
scopes: ["some_scope"],
|
|
173
|
-
account: {
|
|
174
|
-
homeAccountId: "some_home_account_id",
|
|
175
|
-
username: "some_username",
|
|
176
|
-
localAccountId: "some_local_account_id",
|
|
177
|
-
environment: "some_environment",
|
|
178
|
-
tenantId: "some_tenant_id",
|
|
179
|
-
},
|
|
180
|
-
idTokenClaims: {
|
|
181
|
-
given_name: "John",
|
|
182
|
-
family_name: "Doe",
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
render(
|
|
187
|
-
<NextIntlClientProvider locale="en" messages={messages}>
|
|
188
|
-
<Header>
|
|
189
|
-
<Header.User />
|
|
190
|
-
</Header>
|
|
191
|
-
</NextIntlClientProvider>,
|
|
192
|
-
);
|
|
193
|
-
|
|
194
|
-
await waitFor(() =>
|
|
195
|
-
expect(mockMutate).toHaveBeenCalledWith({
|
|
196
|
-
AccountNumber: "",
|
|
197
|
-
FirstName: "John",
|
|
198
|
-
LastName: "Doe",
|
|
199
|
-
}),
|
|
200
|
-
);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it("handles error in MSAL redirect", async () => {
|
|
204
|
-
const consoleErrorSpy = vi
|
|
205
|
-
.spyOn(console, "error")
|
|
206
|
-
.mockImplementation(vi.fn());
|
|
207
|
-
|
|
208
|
-
mockUseSession.mockReturnValue({
|
|
209
|
-
data: {
|
|
210
|
-
user: { email: "test@example.com" },
|
|
211
|
-
session: { accessToken: "mockAccessToken" },
|
|
212
|
-
},
|
|
213
|
-
isPending: false,
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
vi.mocked(mockHandleRedirectPromise).mockRejectedValue(
|
|
217
|
-
new Error("MSAL Error"),
|
|
218
|
-
);
|
|
219
|
-
|
|
220
|
-
render(
|
|
221
|
-
<NextIntlClientProvider locale="en" messages={messages}>
|
|
222
|
-
<Header>
|
|
223
|
-
<Header.User />
|
|
224
|
-
</Header>
|
|
225
|
-
</NextIntlClientProvider>,
|
|
226
|
-
);
|
|
227
|
-
|
|
228
|
-
await waitFor(() =>
|
|
229
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
230
|
-
"MSAL redirect error:",
|
|
231
|
-
expect.any(Error),
|
|
232
|
-
),
|
|
233
|
-
);
|
|
234
|
-
|
|
235
|
-
consoleErrorSpy.mockRestore();
|
|
236
|
-
});
|
|
237
135
|
});
|
|
@@ -2,13 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import useSessionInit from "@evenicanpm/storefront-core/src/api-manager/services/session/mutations/session-init";
|
|
4
4
|
import useSessionLogout from "@evenicanpm/storefront-core/src/api-manager/services/session/mutations/session-logout";
|
|
5
|
-
// API hooks
|
|
6
5
|
import useUpdateUser from "@evenicanpm/storefront-core/src/api-manager/services/user/mutations/update-user";
|
|
7
6
|
import getUser from "@evenicanpm/storefront-core/src/api-manager/services/user/queries/get-user";
|
|
8
|
-
import {
|
|
9
|
-
getMsalInstance,
|
|
10
|
-
initializeMsal,
|
|
11
|
-
} from "@evenicanpm/storefront-core/src/auth/msal";
|
|
12
7
|
import signOutCustom from "@evenicanpm/storefront-core/src/auth/signout";
|
|
13
8
|
import MobileUserIcon from "@evenicanpm/storefront-core/src/components/icons/user";
|
|
14
9
|
import { NavLink } from "@evenicanpm/storefront-core/src/components/nav-link";
|
|
@@ -27,13 +22,16 @@ import {
|
|
|
27
22
|
ListItemButton,
|
|
28
23
|
Popover,
|
|
29
24
|
} from "@mui/material";
|
|
30
|
-
import {
|
|
25
|
+
import {
|
|
26
|
+
customSessionClient,
|
|
27
|
+
genericOAuthClient,
|
|
28
|
+
} from "better-auth/client/plugins";
|
|
31
29
|
// Auth components
|
|
32
30
|
import { createAuthClient } from "better-auth/react";
|
|
33
31
|
import { useRouter } from "next/navigation";
|
|
34
32
|
|
|
35
33
|
const authClient = createAuthClient({
|
|
36
|
-
plugins: [genericOAuthClient()],
|
|
34
|
+
plugins: [genericOAuthClient(), customSessionClient()],
|
|
37
35
|
});
|
|
38
36
|
const { useSession: useBetterAuthSession } = authClient;
|
|
39
37
|
|
|
@@ -44,15 +42,11 @@ import {
|
|
|
44
42
|
type ReactNode,
|
|
45
43
|
useContext,
|
|
46
44
|
useEffect,
|
|
45
|
+
useRef,
|
|
47
46
|
useState,
|
|
48
47
|
} from "react";
|
|
49
48
|
import { MdPersonOutline as PersonOutline } from "react-icons/md";
|
|
50
49
|
|
|
51
|
-
interface IdTokenClaims {
|
|
52
|
-
given_name?: string;
|
|
53
|
-
family_name?: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
50
|
const routeToMenuItem = (route: AccountRoute) => ({
|
|
57
51
|
href: route.href,
|
|
58
52
|
label: `Account.Menu.${route.titleKey}`,
|
|
@@ -104,47 +98,80 @@ const User = ({ children }: Props) => {
|
|
|
104
98
|
}
|
|
105
99
|
|
|
106
100
|
const isAuthenticated = !!session;
|
|
101
|
+
const isE4Datasource = (process.env.API_MANAGER_PRIMARY ?? "e4") === "e4";
|
|
102
|
+
const isD365Datasource = !isE4Datasource;
|
|
107
103
|
const { mutateAsync: sessionInit } = useSessionInit();
|
|
108
|
-
const { mutateAsync: updateUser } = useUpdateUser();
|
|
109
104
|
const { mutateAsync: sessionLogout } = useSessionLogout();
|
|
105
|
+
const { mutateAsync: updateUser } = useUpdateUser();
|
|
106
|
+
const syncedUserKeyRef = useRef<string>("");
|
|
110
107
|
// Register the "me" query on the client so the hydrated cache entry has a queryFn for refetches
|
|
111
|
-
getUser.useData();
|
|
108
|
+
const { data: currentUser, isPending: isUserPending } = getUser.useData();
|
|
112
109
|
|
|
113
110
|
// session init
|
|
114
111
|
useEffect(() => {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
112
|
+
const accessToken =
|
|
113
|
+
(session?.session as { accessToken?: string } | undefined)?.accessToken ||
|
|
114
|
+
"";
|
|
115
|
+
|
|
116
|
+
if (
|
|
117
|
+
isE4Datasource &&
|
|
118
|
+
isAuthenticated &&
|
|
119
|
+
session?.user?.email &&
|
|
120
|
+
accessToken
|
|
121
|
+
) {
|
|
118
122
|
sessionInit({ accessToken, email: session.user.email }).catch(
|
|
119
123
|
console.error,
|
|
120
124
|
);
|
|
121
125
|
}
|
|
122
|
-
}, [isAuthenticated, session, sessionInit]);
|
|
126
|
+
}, [isE4Datasource, isAuthenticated, session, sessionInit]);
|
|
123
127
|
|
|
124
|
-
//
|
|
128
|
+
// For D365, only seed profile details from the auth session when D365 does not
|
|
129
|
+
// already have a name. This avoids overwriting explicit profile edits with a
|
|
130
|
+
// stale session.user.name snapshot.
|
|
125
131
|
useEffect(() => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
132
|
+
if (!isD365Datasource || !isAuthenticated || isUserPending) return;
|
|
133
|
+
|
|
134
|
+
const existingFirstName =
|
|
135
|
+
typeof currentUser?.FirstName === "string"
|
|
136
|
+
? currentUser.FirstName.trim()
|
|
137
|
+
: "";
|
|
138
|
+
const existingLastName =
|
|
139
|
+
typeof currentUser?.LastName === "string"
|
|
140
|
+
? currentUser.LastName.trim()
|
|
141
|
+
: "";
|
|
142
|
+
if (existingFirstName || existingLastName) return;
|
|
143
|
+
|
|
144
|
+
const fullName =
|
|
145
|
+
typeof session?.user?.name === "string" ? session.user.name.trim() : "";
|
|
146
|
+
const [firstName = "", ...lastParts] = fullName
|
|
147
|
+
.split(/\s+/)
|
|
148
|
+
.filter(Boolean);
|
|
149
|
+
const lastName = lastParts.join(" ");
|
|
150
|
+
|
|
151
|
+
if (!firstName && !lastName) return;
|
|
152
|
+
|
|
153
|
+
const syncKey = `${session?.user?.email || ""}:${firstName}:${lastName}`;
|
|
154
|
+
if (syncedUserKeyRef.current === syncKey) return;
|
|
155
|
+
|
|
156
|
+
syncedUserKeyRef.current = syncKey;
|
|
157
|
+
updateUser({
|
|
158
|
+
AccountNumber: "",
|
|
159
|
+
Email: session?.user?.email || undefined,
|
|
160
|
+
FirstName: firstName || undefined,
|
|
161
|
+
LastName: lastName || undefined,
|
|
162
|
+
}).catch((error) => {
|
|
163
|
+
// Allow retry on next render when sync fails.
|
|
164
|
+
syncedUserKeyRef.current = "";
|
|
165
|
+
console.warn("D365 user sync error:", error);
|
|
166
|
+
});
|
|
167
|
+
}, [
|
|
168
|
+
currentUser,
|
|
169
|
+
isD365Datasource,
|
|
170
|
+
isAuthenticated,
|
|
171
|
+
isUserPending,
|
|
172
|
+
session,
|
|
173
|
+
updateUser,
|
|
174
|
+
]);
|
|
148
175
|
|
|
149
176
|
const handleLogout = async () => {
|
|
150
177
|
try {
|
|
@@ -156,10 +183,10 @@ const User = ({ children }: Props) => {
|
|
|
156
183
|
};
|
|
157
184
|
|
|
158
185
|
const handleSignIn = () => {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
186
|
+
const callbackUrl = encodeURIComponent(
|
|
187
|
+
globalThis.location.pathname + globalThis.location.search,
|
|
188
|
+
);
|
|
189
|
+
globalThis.location.href = `/login?callbackUrl=${callbackUrl}`;
|
|
163
190
|
};
|
|
164
191
|
|
|
165
192
|
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
// hooks/useAppSession.ts
|
|
2
2
|
|
|
3
3
|
import useSessionInit from "@evenicanpm/storefront-core/src/api-manager/services/session/mutations/session-init";
|
|
4
|
-
// API hooks
|
|
5
|
-
import useUpdateUser from "@evenicanpm/storefront-core/src/api-manager/services/user/mutations/update-user";
|
|
6
|
-
import {
|
|
7
|
-
getMsalInstance,
|
|
8
|
-
initializeMsal,
|
|
9
|
-
} from "@evenicanpm/storefront-core/src/auth/msal";
|
|
10
4
|
import { createAuthClient } from "better-auth/react";
|
|
11
5
|
import { useEffect } from "react";
|
|
12
6
|
|
|
@@ -16,7 +10,6 @@ const { useSession: useBetterAuthSession } = authClient;
|
|
|
16
10
|
export function useAppSession() {
|
|
17
11
|
const { data: session, isPending } = useBetterAuthSession();
|
|
18
12
|
const { mutateAsync: sessionInit } = useSessionInit();
|
|
19
|
-
const { mutateAsync: updateUser } = useUpdateUser();
|
|
20
13
|
|
|
21
14
|
// Initialize session in API
|
|
22
15
|
useEffect(() => {
|
|
@@ -30,32 +23,6 @@ export function useAppSession() {
|
|
|
30
23
|
}
|
|
31
24
|
}, [session, sessionInit]);
|
|
32
25
|
|
|
33
|
-
// MSAL redirect handling
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
const handleRedirect = async () => {
|
|
36
|
-
try {
|
|
37
|
-
await initializeMsal();
|
|
38
|
-
const res = await getMsalInstance().handleRedirectPromise();
|
|
39
|
-
if (res) {
|
|
40
|
-
const { given_name, family_name } = res.idTokenClaims as {
|
|
41
|
-
given_name?: string;
|
|
42
|
-
family_name?: string;
|
|
43
|
-
};
|
|
44
|
-
if (given_name && family_name) {
|
|
45
|
-
updateUser({
|
|
46
|
-
AccountNumber: "",
|
|
47
|
-
FirstName: given_name,
|
|
48
|
-
LastName: family_name,
|
|
49
|
-
}).catch(console.error);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
} catch (err) {
|
|
53
|
-
console.error("MSAL redirect error:", err);
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
handleRedirect();
|
|
57
|
-
}, [updateUser]);
|
|
58
|
-
|
|
59
26
|
return {
|
|
60
27
|
session,
|
|
61
28
|
isAuthenticated: !!session,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { auth } from "@evenicanpm/storefront-core/src/lib/auth";
|
|
2
|
+
import {
|
|
3
|
+
customSessionClient,
|
|
4
|
+
genericOAuthClient,
|
|
5
|
+
} from "better-auth/client/plugins";
|
|
6
|
+
import { createAuthClient } from "better-auth/react";
|
|
7
|
+
|
|
8
|
+
const authClient = createAuthClient({
|
|
9
|
+
plugins: [genericOAuthClient(), customSessionClient<typeof auth>()],
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const { signIn, signOut, signUp, useSession, getSession } = authClient;
|
|
13
|
+
|
|
14
|
+
export type Session = typeof auth.$Infer.Session;
|
package/src/lib/auth.ts
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
const CLIENT_ID = process.env.NEXT_PUBLIC_ENTRA_EXTERNAL_ID_CLIENT_ID || "";
|
|
2
|
+
const TENANT = process.env.NEXT_PUBLIC_ENTRA_EXTERNAL_ID_TENANT_NAME || "";
|
|
3
|
+
const CUSTOM_SCOPES =
|
|
4
|
+
process.env.NEXT_PUBLIC_ENTRA_EXTERNAL_ID_CUSTOM_SCOPES ||
|
|
5
|
+
"openid offline_access email profile";
|
|
6
|
+
|
|
7
|
+
function baseUrl() {
|
|
8
|
+
return `https://${TENANT}.ciamlogin.com/${TENANT}.onmicrosoft.com`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function post(path: string, params: Record<string, string>) {
|
|
12
|
+
const res = await fetch(`${baseUrl()}${path}`, {
|
|
13
|
+
method: "POST",
|
|
14
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
15
|
+
body: new URLSearchParams(params).toString(),
|
|
16
|
+
cache: "no-store",
|
|
17
|
+
});
|
|
18
|
+
return res.json() as Promise<Record<string, unknown>>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function nativeLoginInitiate(username: string) {
|
|
22
|
+
return post("/oauth2/v2.0/initiate", {
|
|
23
|
+
client_id: CLIENT_ID,
|
|
24
|
+
challenge_type: "password redirect",
|
|
25
|
+
username,
|
|
26
|
+
capabilities: "mfa_required registration_required",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function nativeLoginChallenge(continuationToken: string) {
|
|
31
|
+
return post("/oauth2/v2.0/challenge", {
|
|
32
|
+
client_id: CLIENT_ID,
|
|
33
|
+
challenge_type: "password redirect",
|
|
34
|
+
continuation_token: continuationToken,
|
|
35
|
+
capabilities: "mfa_required registration_required",
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function nativeLoginToken(continuationToken: string, password: string) {
|
|
40
|
+
return post("/oauth2/v2.0/token", {
|
|
41
|
+
client_id: CLIENT_ID,
|
|
42
|
+
grant_type: "password",
|
|
43
|
+
password,
|
|
44
|
+
scope: CUSTOM_SCOPES,
|
|
45
|
+
continuation_token: continuationToken,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function signupStart(
|
|
50
|
+
username: string,
|
|
51
|
+
password: string,
|
|
52
|
+
givenName?: string,
|
|
53
|
+
surname?: string,
|
|
54
|
+
displayName?: string,
|
|
55
|
+
) {
|
|
56
|
+
const params: Record<string, string> = {
|
|
57
|
+
client_id: CLIENT_ID,
|
|
58
|
+
username,
|
|
59
|
+
password,
|
|
60
|
+
challenge_type: "oob password redirect",
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (givenName || surname || displayName) {
|
|
64
|
+
params.attributes = JSON.stringify({
|
|
65
|
+
...(givenName ? { givenName } : {}),
|
|
66
|
+
...(surname ? { surname } : {}),
|
|
67
|
+
...(displayName ? { displayName } : {}),
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return post("/signup/v1.0/start", params);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function signupChallenge(continuationToken: string) {
|
|
75
|
+
return post("/signup/v1.0/challenge", {
|
|
76
|
+
client_id: CLIENT_ID,
|
|
77
|
+
challenge_type: "oob password redirect",
|
|
78
|
+
continuation_token: continuationToken,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function signupContinueOtp(continuationToken: string, oob: string) {
|
|
83
|
+
return post("/signup/v1.0/continue", {
|
|
84
|
+
client_id: CLIENT_ID,
|
|
85
|
+
continuation_token: continuationToken,
|
|
86
|
+
grant_type: "oob",
|
|
87
|
+
oob,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function getTokenAfterSignup(continuationToken: string) {
|
|
92
|
+
return post("/oauth2/v2.0/token", {
|
|
93
|
+
client_id: CLIENT_ID,
|
|
94
|
+
continuation_token: continuationToken,
|
|
95
|
+
grant_type: "continuation_token",
|
|
96
|
+
scope: CUSTOM_SCOPES,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function ssrpStart(username: string) {
|
|
101
|
+
return post("/resetpassword/v1.0/start", {
|
|
102
|
+
client_id: CLIENT_ID,
|
|
103
|
+
username,
|
|
104
|
+
challenge_type: "oob redirect",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function ssrpChallenge(continuationToken: string) {
|
|
109
|
+
return post("/resetpassword/v1.0/challenge", {
|
|
110
|
+
client_id: CLIENT_ID,
|
|
111
|
+
challenge_type: "oob redirect",
|
|
112
|
+
continuation_token: continuationToken,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function ssrpContinueOtp(continuationToken: string, oob: string) {
|
|
117
|
+
return post("/resetpassword/v1.0/continue", {
|
|
118
|
+
client_id: CLIENT_ID,
|
|
119
|
+
continuation_token: continuationToken,
|
|
120
|
+
grant_type: "oob",
|
|
121
|
+
oob,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function ssrpSubmit(continuationToken: string, newPassword: string) {
|
|
126
|
+
return post("/resetpassword/v1.0/submit", {
|
|
127
|
+
client_id: CLIENT_ID,
|
|
128
|
+
continuation_token: continuationToken,
|
|
129
|
+
new_password: newPassword,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function ssrpPollCompletion(continuationToken: string) {
|
|
134
|
+
return post("/resetpassword/v1.0/poll_completion", {
|
|
135
|
+
client_id: CLIENT_ID,
|
|
136
|
+
continuation_token: continuationToken,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
File without changes
|