@authhero/react-admin 0.13.0 → 0.14.0
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
CHANGED
package/package.json
CHANGED
package/src/auth0DataProvider.ts
CHANGED
|
@@ -205,29 +205,7 @@ export default (
|
|
|
205
205
|
resourceKey: "organizations",
|
|
206
206
|
idKey: "id",
|
|
207
207
|
},
|
|
208
|
-
|
|
209
|
-
fetch: (client) => {
|
|
210
|
-
// Build the query string, combining search query and IP filter
|
|
211
|
-
let query = params.filter?.q || "";
|
|
212
|
-
if (params.filter?.ip) {
|
|
213
|
-
const ipQuery = `ip:${params.filter.ip}`;
|
|
214
|
-
query = query ? `${query} AND ${ipQuery}` : ipQuery;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return client.logs.list({
|
|
218
|
-
page: page - 1,
|
|
219
|
-
per_page: perPage,
|
|
220
|
-
q: query || undefined,
|
|
221
|
-
sort:
|
|
222
|
-
field && order
|
|
223
|
-
? `${field}:${order === "DESC" ? "-1" : "1"}`
|
|
224
|
-
: undefined,
|
|
225
|
-
include_totals: true,
|
|
226
|
-
});
|
|
227
|
-
},
|
|
228
|
-
resourceKey: "logs",
|
|
229
|
-
idKey: "log_id",
|
|
230
|
-
},
|
|
208
|
+
// Logs removed from SDK handlers - using HTTP directly for full control
|
|
231
209
|
rules: {
|
|
232
210
|
fetch: (client) => client.rules.list(),
|
|
233
211
|
resourceKey: "rules",
|
|
@@ -257,9 +235,9 @@ export default (
|
|
|
257
235
|
},
|
|
258
236
|
};
|
|
259
237
|
|
|
260
|
-
// Handle SDK resources
|
|
238
|
+
// Handle SDK resources (only for top-level resources, not nested paths like users/{id}/roles)
|
|
261
239
|
const handler = sdkHandlers[resource];
|
|
262
|
-
if (handler) {
|
|
240
|
+
if (handler && !resourcePath.includes("/")) {
|
|
263
241
|
const result = await handler.fetch(managementClient);
|
|
264
242
|
const { data, total } = normalizeSDKResponse(
|
|
265
243
|
result,
|
|
@@ -285,6 +263,35 @@ export default (
|
|
|
285
263
|
);
|
|
286
264
|
}
|
|
287
265
|
|
|
266
|
+
// Handle logs with direct HTTP for full control over query params
|
|
267
|
+
if (resource === "logs") {
|
|
268
|
+
const headers = createHeaders(tenantId);
|
|
269
|
+
const query: any = {
|
|
270
|
+
include_totals: true,
|
|
271
|
+
page: page - 1,
|
|
272
|
+
per_page: perPage,
|
|
273
|
+
sort:
|
|
274
|
+
field && order
|
|
275
|
+
? `${field}:${order === "DESC" ? "-1" : "1"}`
|
|
276
|
+
: undefined,
|
|
277
|
+
...params.filter, // Pass all filter params directly (q, from, etc.)
|
|
278
|
+
};
|
|
279
|
+
const url = `${apiUrl}/api/v2/logs?${stringify(query)}`;
|
|
280
|
+
|
|
281
|
+
const res = await httpClient(url, { headers });
|
|
282
|
+
const response = res.json;
|
|
283
|
+
const logsData = response.logs || response || [];
|
|
284
|
+
const logsArray = Array.isArray(logsData) ? logsData : [];
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
data: logsArray.map((log: any) => ({
|
|
288
|
+
id: log.log_id || log.id,
|
|
289
|
+
...log,
|
|
290
|
+
})),
|
|
291
|
+
total: response.total || logsArray.length,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
288
295
|
// Handle stats/daily endpoint
|
|
289
296
|
if (resourcePath === "stats/daily") {
|
|
290
297
|
const headers = createHeaders(tenantId);
|
|
@@ -704,9 +711,10 @@ export default (
|
|
|
704
711
|
};
|
|
705
712
|
}
|
|
706
713
|
|
|
707
|
-
// Logs filtered by user_id
|
|
714
|
+
// Logs filtered by user_id - use direct HTTP for full control
|
|
708
715
|
if (resource === "logs" && params.target === "user_id") {
|
|
709
|
-
const
|
|
716
|
+
const headers = createHeaders(tenantId);
|
|
717
|
+
const query = {
|
|
710
718
|
page: page - 1,
|
|
711
719
|
per_page: perPage,
|
|
712
720
|
q: `user_id:${params.id}`,
|
|
@@ -715,12 +723,21 @@ export default (
|
|
|
715
723
|
? `${field}:${order === "DESC" ? "-1" : "1"}`
|
|
716
724
|
: undefined,
|
|
717
725
|
include_totals: true,
|
|
718
|
-
|
|
726
|
+
...params.filter, // Allow additional filters to be passed through
|
|
727
|
+
};
|
|
728
|
+
const url = `${apiUrl}/api/v2/logs?${stringify(query)}`;
|
|
729
|
+
|
|
730
|
+
const res = await httpClient(url, { headers });
|
|
731
|
+
const response = res.json;
|
|
732
|
+
const logsData = response.logs || response || [];
|
|
733
|
+
const logsArray = Array.isArray(logsData) ? logsData : [];
|
|
719
734
|
|
|
720
|
-
const normalized = normalizeSDKResponse(result, "logs");
|
|
721
735
|
return {
|
|
722
|
-
data:
|
|
723
|
-
|
|
736
|
+
data: logsArray.map((log: any) => ({
|
|
737
|
+
id: log.log_id || log.id,
|
|
738
|
+
...log,
|
|
739
|
+
})),
|
|
740
|
+
total: response.total || logsArray.length,
|
|
724
741
|
};
|
|
725
742
|
}
|
|
726
743
|
|
package/src/authProvider.ts
CHANGED
|
@@ -196,12 +196,35 @@ export const createManagementClient = async (
|
|
|
196
196
|
const orgAuth0Client = createAuth0ClientForOrg(domainForAuth, tenantId);
|
|
197
197
|
const audience =
|
|
198
198
|
import.meta.env.VITE_AUTH0_AUDIENCE || "urn:authhero:management";
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
199
|
+
try {
|
|
200
|
+
token = await orgAuth0Client.getTokenSilently({
|
|
201
|
+
authorizationParams: {
|
|
202
|
+
audience,
|
|
203
|
+
organization: tenantId,
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
} catch (error) {
|
|
207
|
+
// If silent token acquisition fails, redirect to login with org
|
|
208
|
+
// Get the base auth0 client to get the user's email for login hint
|
|
209
|
+
const baseClient = createAuth0Client(domainForAuth);
|
|
210
|
+
const user = await baseClient.getUser().catch(() => null);
|
|
211
|
+
|
|
212
|
+
// Redirect to login with organization
|
|
213
|
+
await orgAuth0Client.loginWithRedirect({
|
|
214
|
+
authorizationParams: {
|
|
215
|
+
organization: tenantId,
|
|
216
|
+
login_hint: user?.email,
|
|
217
|
+
},
|
|
218
|
+
appState: {
|
|
219
|
+
returnTo: window.location.pathname,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// This won't be reached as loginWithRedirect redirects the page
|
|
224
|
+
throw new Error(
|
|
225
|
+
`Redirecting to login for organization ${tenantId}`,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
205
228
|
} else {
|
|
206
229
|
// For token/client_credentials, use getOrganizationToken
|
|
207
230
|
token = await getOrganizationToken(domainConfig, tenantId);
|
|
@@ -829,7 +852,7 @@ export const createOrganizationHttpClient = (organizationId: string) => {
|
|
|
829
852
|
organization: organizationId,
|
|
830
853
|
},
|
|
831
854
|
})
|
|
832
|
-
.catch(async (
|
|
855
|
+
.catch(async (_error) => {
|
|
833
856
|
// If silent token acquisition fails, we need to redirect to login with org
|
|
834
857
|
// Get the base auth0 client to get the user's email for login hint
|
|
835
858
|
const baseClient = createAuth0Client(selectedDomain);
|
|
@@ -55,7 +55,7 @@ import EditIcon from "@mui/icons-material/Edit";
|
|
|
55
55
|
import DragIndicatorIcon from "@mui/icons-material/DragIndicator";
|
|
56
56
|
import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
|
|
57
57
|
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
|
|
58
|
-
import {
|
|
58
|
+
import { createOrganizationHttpClient } from "../../authProvider";
|
|
59
59
|
import {
|
|
60
60
|
getDomainFromStorage,
|
|
61
61
|
getSelectedDomainFromStorage,
|
|
@@ -864,8 +864,10 @@ const ConnectionsTab = () => {
|
|
|
864
864
|
setLoading(true);
|
|
865
865
|
try {
|
|
866
866
|
// Fetch enabled connections from the new API endpoint
|
|
867
|
+
// Use organization-scoped HTTP client to ensure proper org_id in token
|
|
867
868
|
const baseUrl = getApiBaseUrl();
|
|
868
|
-
const
|
|
869
|
+
const orgHttpClient = createOrganizationHttpClient(tenantId);
|
|
870
|
+
const response = await orgHttpClient(
|
|
869
871
|
`${baseUrl}/api/v2/clients/${clientId}/connections`,
|
|
870
872
|
{
|
|
871
873
|
method: "GET",
|
|
@@ -926,8 +928,10 @@ const ConnectionsTab = () => {
|
|
|
926
928
|
|
|
927
929
|
setSaving(true);
|
|
928
930
|
try {
|
|
931
|
+
// Use organization-scoped HTTP client to ensure proper org_id in token
|
|
929
932
|
const baseUrl = getApiBaseUrl();
|
|
930
|
-
|
|
933
|
+
const orgHttpClient = createOrganizationHttpClient(tenantId);
|
|
934
|
+
await orgHttpClient(
|
|
931
935
|
`${baseUrl}/api/v2/clients/${clientId}/connections`,
|
|
932
936
|
{
|
|
933
937
|
method: "PATCH",
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
SelectInput,
|
|
7
7
|
useGetList,
|
|
8
8
|
FormDataConsumer,
|
|
9
|
+
BooleanInput,
|
|
9
10
|
} from "react-admin";
|
|
10
11
|
import { useState } from "react";
|
|
11
12
|
|
|
@@ -101,6 +102,11 @@ export function UserCreate() {
|
|
|
101
102
|
validate={[required()]}
|
|
102
103
|
helperText="Password for the user account"
|
|
103
104
|
/>
|
|
105
|
+
<BooleanInput
|
|
106
|
+
source="email_verified"
|
|
107
|
+
label="Email Verified"
|
|
108
|
+
defaultValue={false}
|
|
109
|
+
/>
|
|
104
110
|
</>
|
|
105
111
|
);
|
|
106
112
|
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
TextInput,
|
|
13
13
|
FunctionField,
|
|
14
14
|
BooleanField,
|
|
15
|
+
BooleanInput,
|
|
15
16
|
ArrayField,
|
|
16
17
|
SimpleShowLayout,
|
|
17
18
|
useNotify,
|
|
@@ -1444,6 +1445,7 @@ export function UserEdit() {
|
|
|
1444
1445
|
>
|
|
1445
1446
|
<TextField source="connection" />
|
|
1446
1447
|
</Labeled>
|
|
1448
|
+
<BooleanInput source="email_verified" label="Email Verified" />
|
|
1447
1449
|
</Stack>
|
|
1448
1450
|
<TextInput source="picture" />
|
|
1449
1451
|
<ArrayField source="identities">
|