@authhero/react-admin 0.10.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.
Files changed (110) hide show
  1. package/.eslintrc.js +21 -0
  2. package/.vercelignore +4 -0
  3. package/CHANGELOG.md +56 -0
  4. package/LICENSE +21 -0
  5. package/README.md +50 -0
  6. package/index.html +125 -0
  7. package/package.json +61 -0
  8. package/prettier.config.js +1 -0
  9. package/public/favicon.ico +0 -0
  10. package/public/manifest.json +15 -0
  11. package/src/App.spec.tsx +42 -0
  12. package/src/App.tsx +232 -0
  13. package/src/AuthCallback.tsx +138 -0
  14. package/src/Layout.tsx +12 -0
  15. package/src/TenantsApp.tsx +115 -0
  16. package/src/auth0DataProvider.ts +1242 -0
  17. package/src/authProvider.ts +521 -0
  18. package/src/components/CertificateErrorDialog.tsx +116 -0
  19. package/src/components/DomainSelector.tsx +401 -0
  20. package/src/components/TenantAppBar.tsx +83 -0
  21. package/src/components/TenantLayout.tsx +25 -0
  22. package/src/components/TenantsAppBar.tsx +21 -0
  23. package/src/components/TenantsLayout.tsx +28 -0
  24. package/src/components/activity/ActivityDashboard.tsx +381 -0
  25. package/src/components/activity/index.ts +1 -0
  26. package/src/components/branding/BrandingList.tsx +0 -0
  27. package/src/components/branding/BrandingShow.tsx +0 -0
  28. package/src/components/branding/ThemesTab.tsx +286 -0
  29. package/src/components/branding/edit.tsx +149 -0
  30. package/src/components/branding/hooks/useThemesData.ts +123 -0
  31. package/src/components/branding/index.ts +2 -0
  32. package/src/components/branding/list.tsx +12 -0
  33. package/src/components/clients/create.tsx +12 -0
  34. package/src/components/clients/edit.tsx +1285 -0
  35. package/src/components/clients/index.ts +3 -0
  36. package/src/components/clients/list.tsx +37 -0
  37. package/src/components/common/DateAgo.tsx +6 -0
  38. package/src/components/common/JsonOutput.tsx +26 -0
  39. package/src/components/common/index.ts +1 -0
  40. package/src/components/connections/create.tsx +35 -0
  41. package/src/components/connections/edit.tsx +212 -0
  42. package/src/components/connections/index.ts +3 -0
  43. package/src/components/connections/list.tsx +15 -0
  44. package/src/components/custom-domains/create.tsx +26 -0
  45. package/src/components/custom-domains/edit.tsx +101 -0
  46. package/src/components/custom-domains/index.ts +3 -0
  47. package/src/components/custom-domains/list.tsx +16 -0
  48. package/src/components/flows/create.tsx +30 -0
  49. package/src/components/flows/edit.tsx +238 -0
  50. package/src/components/flows/index.ts +3 -0
  51. package/src/components/flows/list.tsx +15 -0
  52. package/src/components/forms/FlowEditor.tsx +1363 -0
  53. package/src/components/forms/NodeEditor.tsx +1119 -0
  54. package/src/components/forms/RichTextEditor.tsx +145 -0
  55. package/src/components/forms/create.tsx +30 -0
  56. package/src/components/forms/edit.tsx +256 -0
  57. package/src/components/forms/index.ts +3 -0
  58. package/src/components/forms/list.tsx +16 -0
  59. package/src/components/hooks/create.tsx +96 -0
  60. package/src/components/hooks/edit.tsx +114 -0
  61. package/src/components/hooks/index.ts +3 -0
  62. package/src/components/hooks/list.tsx +17 -0
  63. package/src/components/listActions/PostListActions.tsx +10 -0
  64. package/src/components/logs/LogIcon.tsx +32 -0
  65. package/src/components/logs/LogShow.tsx +82 -0
  66. package/src/components/logs/LogType.tsx +38 -0
  67. package/src/components/logs/index.ts +4 -0
  68. package/src/components/logs/list.tsx +41 -0
  69. package/src/components/organizations/create.tsx +13 -0
  70. package/src/components/organizations/edit.tsx +682 -0
  71. package/src/components/organizations/index.ts +3 -0
  72. package/src/components/organizations/list.tsx +21 -0
  73. package/src/components/resource-servers/create.tsx +87 -0
  74. package/src/components/resource-servers/edit.tsx +121 -0
  75. package/src/components/resource-servers/index.ts +3 -0
  76. package/src/components/resource-servers/list.tsx +47 -0
  77. package/src/components/roles/create.tsx +12 -0
  78. package/src/components/roles/edit.tsx +426 -0
  79. package/src/components/roles/index.ts +3 -0
  80. package/src/components/roles/list.tsx +24 -0
  81. package/src/components/sessions/edit.tsx +101 -0
  82. package/src/components/sessions/index.ts +3 -0
  83. package/src/components/sessions/list.tsx +20 -0
  84. package/src/components/sessions/show.tsx +113 -0
  85. package/src/components/settings/edit.tsx +236 -0
  86. package/src/components/settings/index.ts +2 -0
  87. package/src/components/settings/list.tsx +14 -0
  88. package/src/components/tenants/create.tsx +20 -0
  89. package/src/components/tenants/edit.tsx +54 -0
  90. package/src/components/tenants/index.ts +2 -0
  91. package/src/components/tenants/list.tsx +67 -0
  92. package/src/components/themes/edit.tsx +200 -0
  93. package/src/components/themes/index.ts +2 -0
  94. package/src/components/themes/list.tsx +12 -0
  95. package/src/components/users/create.tsx +144 -0
  96. package/src/components/users/edit.tsx +1711 -0
  97. package/src/components/users/index.ts +3 -0
  98. package/src/components/users/list.tsx +35 -0
  99. package/src/data.json +121 -0
  100. package/src/dataProvider.ts +97 -0
  101. package/src/index.tsx +106 -0
  102. package/src/lib/logs.ts +21 -0
  103. package/src/types/reactflow.d.ts +86 -0
  104. package/src/utils/domainUtils.ts +169 -0
  105. package/src/utils/tokenUtils.ts +75 -0
  106. package/src/vite-env.d.ts +1 -0
  107. package/tsconfig.json +37 -0
  108. package/tsconfig.node.json +10 -0
  109. package/vercel.json +17 -0
  110. package/vite.config.ts +30 -0
@@ -0,0 +1,3 @@
1
+ export * from "./create";
2
+ export * from "./list";
3
+ export * from "./edit";
@@ -0,0 +1,37 @@
1
+ import {
2
+ List,
3
+ Datagrid,
4
+ TextField,
5
+ DateField,
6
+ FunctionField,
7
+ } from "react-admin";
8
+ import { PostListActions } from "../listActions/PostListActions";
9
+
10
+ export function ClientList() {
11
+ return (
12
+ <List actions={<PostListActions />}>
13
+ <Datagrid rowClick="edit" bulkActionButtons={false}>
14
+ <TextField source="id" />
15
+ <TextField source="name" />
16
+ <FunctionField
17
+ label="Login"
18
+ render={(record: any) => (
19
+ <a
20
+ href={`${
21
+ import.meta.env.VITE_SIMPLE_REST_URL
22
+ }/authorize?client_id=${record.id}&redirect_uri=${
23
+ import.meta.env.VITE_SIMPLE_REST_URL
24
+ }/u/info&scope=profile%20email%20openid&state=1234&response_type=code`}
25
+ target="_blank"
26
+ rel="noopener noreferrer"
27
+ >
28
+ Login
29
+ </a>
30
+ )}
31
+ />
32
+ <DateField source="created_at" showTime={true} />
33
+ <DateField source="updated_at" showTime={true} />
34
+ </Datagrid>
35
+ </List>
36
+ );
37
+ }
@@ -0,0 +1,6 @@
1
+ import { formatDistance } from "date-fns";
2
+
3
+ export function DateAgo({ date }: { date?: string }) {
4
+ if (!date) return "N/A";
5
+ return `${formatDistance(new Date(date), new Date())} ago`;
6
+ }
@@ -0,0 +1,26 @@
1
+ import { Box } from "@mui/material";
2
+ import { useTheme } from "@mui/material/styles";
3
+
4
+ export function JsonOutput({ data }: { data: any }) {
5
+ const theme = useTheme();
6
+ const isDark = theme.palette.mode === "dark";
7
+
8
+ return (
9
+ <Box
10
+ component="pre"
11
+ sx={{
12
+ backgroundColor: isDark ? theme.palette.background.paper : "#f5f5f5",
13
+ color: theme.palette.text.primary,
14
+ border: `1px solid ${theme.palette.divider}`,
15
+ borderRadius: "4px",
16
+ padding: 2,
17
+ overflow: "auto",
18
+ fontSize: "0.9rem",
19
+ fontFamily: "monospace",
20
+ margin: 0,
21
+ }}
22
+ >
23
+ {JSON.stringify(data, null, 2)}
24
+ </Box>
25
+ );
26
+ }
@@ -0,0 +1 @@
1
+ export * from "./DateAgo";
@@ -0,0 +1,35 @@
1
+ import {
2
+ Create,
3
+ SelectInput,
4
+ SimpleForm,
5
+ TextInput,
6
+ required,
7
+ } from "react-admin";
8
+
9
+ export function ConnectionCreate() {
10
+ return (
11
+ <Create>
12
+ <SimpleForm>
13
+ <TextInput source="name" validate={[required()]} />
14
+ <SelectInput
15
+ source="strategy"
16
+ label="Strategy"
17
+ choices={[
18
+ { id: "email", name: "Email" },
19
+ { id: "google-oauth2", name: "Google" },
20
+ { id: "facebook", name: "Facebook" },
21
+ { id: "apple", name: "Apple" },
22
+ { id: "github", name: "GitHub" },
23
+ { id: "microsoft", name: "Microsoft" },
24
+ { id: "vipps", name: "Vipps" },
25
+ { id: "oauth2", name: "OAuth2" },
26
+ { id: "oidc", name: "OpenID Connect" },
27
+ { id: "Username-Password-Authentication", name: "Password" },
28
+ { id: "sms", name: "SMS" },
29
+ { id: "samlp", name: "SAML" },
30
+ ]}
31
+ />
32
+ </SimpleForm>
33
+ </Create>
34
+ );
35
+ }
@@ -0,0 +1,212 @@
1
+ import {
2
+ ArrayInput,
3
+ BooleanInput,
4
+ ChipField,
5
+ Edit,
6
+ FunctionField,
7
+ NumberInput,
8
+ ReferenceManyField,
9
+ SelectInput,
10
+ SimpleFormIterator,
11
+ SimpleShowLayout,
12
+ SingleFieldList,
13
+ TabbedForm,
14
+ TextField,
15
+ TextInput,
16
+ useRecordContext,
17
+ } from "react-admin";
18
+ import { JsonOutput } from "../common/JsonOutput";
19
+
20
+ export function ConnectionEdit(props: any) {
21
+ return (
22
+ <Edit {...props}>
23
+ <ConnectionTabbedFrom />
24
+ </Edit>
25
+ );
26
+ }
27
+
28
+ function ConnectionTabbedFrom() {
29
+ const record = useRecordContext();
30
+
31
+ return (
32
+ <Edit>
33
+ <SimpleShowLayout>
34
+ <TextField source="name" />
35
+ <TextField source="id" />
36
+ </SimpleShowLayout>
37
+ <TabbedForm>
38
+ <TabbedForm.Tab label="details">
39
+ <TextInput source="id" label="Client ID" style={{ width: "800px" }} />
40
+ <TextInput disabled source="strategy" />
41
+ <TextInput source="options.client_id" label="Client Id" />
42
+ <TextInput
43
+ source="options.client_secret"
44
+ label="Client Secret"
45
+ style={{ width: "800px" }}
46
+ />
47
+
48
+ {record?.strategy === "apple" && (
49
+ <>
50
+ <TextInput source="options.kid" label="Key ID" />
51
+ <TextInput source="options.team_id" label="Team ID" />
52
+ <TextInput source="options.realms" label="Realms" />
53
+ <TextInput source="options.app_secret" label="App Secret" />
54
+ <TextInput source="options.scope" fullWidth />
55
+ </>
56
+ )}
57
+
58
+ {record?.strategy === "github" && (
59
+ <>
60
+ <TextInput
61
+ source="options.scope"
62
+ label="Scope"
63
+ placeholder="user:email"
64
+ helperText="Space-separated scopes (e.g., user:email read:user)"
65
+ fullWidth
66
+ />
67
+ </>
68
+ )}
69
+
70
+ {record?.strategy === "microsoft" && (
71
+ <>
72
+ <TextInput
73
+ source="options.realms"
74
+ label="Tenant ID"
75
+ placeholder="common"
76
+ helperText="Use 'common', 'organizations', 'consumers', or your tenant ID"
77
+ />
78
+ <TextInput
79
+ source="options.scope"
80
+ label="Scope"
81
+ placeholder="openid profile email"
82
+ helperText="Space-separated scopes"
83
+ fullWidth
84
+ />
85
+ </>
86
+ )}
87
+
88
+ {["oauth2", "oidc"].includes(record?.strategy) && (
89
+ <>
90
+ <TextInput
91
+ source="display_name"
92
+ label="Display Name"
93
+ fullWidth
94
+ />
95
+ <SelectInput
96
+ source="response_type"
97
+ label="Response Type"
98
+ choices={[
99
+ { id: "code", name: "Code" },
100
+ { id: "code id_token", name: "Code ID-token" },
101
+ ]}
102
+ />
103
+ <SelectInput
104
+ source="response_mode"
105
+ label="Response Mode"
106
+ choices={[
107
+ { id: "query", name: "Query" },
108
+ { id: "fragment", name: "Fragment" },
109
+ { id: "web_message", name: "Web Message" },
110
+ { id: "form_post", name: "Form Post" },
111
+ ]}
112
+ />
113
+ <TextInput source="options.scope" fullWidth />
114
+ <TextInput
115
+ source="options.authorization_endpoint"
116
+ label="Authorization Endpoint"
117
+ fullWidth
118
+ />
119
+ <TextInput
120
+ source="options.userinfo_endpoint"
121
+ label="Userinfo Endpoint"
122
+ fullWidth
123
+ />
124
+ <TextInput
125
+ source="options.token_endpoint"
126
+ label="Token Endpoint"
127
+ fullWidth
128
+ />
129
+ <TextInput source="options.icon_url" label="Icon URL" fullWidth />
130
+ </>
131
+ )}
132
+
133
+ {record?.strategy === "sms" && (
134
+ <>
135
+ <TextInput
136
+ source="options.twilio_sid"
137
+ label="Twillio Account ID"
138
+ />
139
+ <TextInput source="options.twilio_token" label="Twilio Token" />
140
+ <TextInput source="options.from" label="From" />
141
+ </>
142
+ )}
143
+
144
+ {record?.strategy === "Username-Password-Authentication" && (
145
+ <>
146
+ <SelectInput
147
+ source="options.passwordPolicy"
148
+ label="Password Policy"
149
+ choices={[
150
+ { id: "none", name: "None" },
151
+ { id: "low", name: "Low" },
152
+ { id: "fair", name: "Fair" },
153
+ { id: "good", name: "Good" },
154
+ { id: "excellent", name: "Excellent" },
155
+ { id: null, name: "Null" },
156
+ ]}
157
+ />
158
+ <NumberInput
159
+ source="options.password_complexity_options.min_length"
160
+ label="Minimum Password Length"
161
+ />
162
+ <BooleanInput
163
+ source="options.password_history.enable"
164
+ label="Enable Password History"
165
+ />
166
+ <NumberInput
167
+ source="options.password_history.size"
168
+ label="Password History Size"
169
+ />
170
+ <BooleanInput
171
+ source="options.password_no_personal_info.enable"
172
+ label="Enable No Personal Info in Passwords"
173
+ />
174
+ <BooleanInput
175
+ source="options.password_dictionary.enable"
176
+ label="Enable Password Dictionary"
177
+ />
178
+ <ArrayInput
179
+ source="options.password_dictionary.dictionary"
180
+ label="Custom Password Dictionary"
181
+ >
182
+ <SimpleFormIterator>
183
+ <TextInput
184
+ source=""
185
+ label="Dictionary Entry"
186
+ validate={(value) =>
187
+ value && value.length > 50
188
+ ? "Entry must be 50 characters or less"
189
+ : undefined
190
+ }
191
+ />
192
+ </SimpleFormIterator>
193
+ </ArrayInput>
194
+ </>
195
+ )}
196
+
197
+ <ReferenceManyField reference="clients" target="id">
198
+ <SingleFieldList>
199
+ <ChipField source="name" size="small" />
200
+ </SingleFieldList>
201
+ </ReferenceManyField>
202
+ </TabbedForm.Tab>
203
+ <TabbedForm.Tab label="Raw JSON">
204
+ <FunctionField
205
+ source="date"
206
+ render={(record: any) => <JsonOutput data={record} />}
207
+ />
208
+ </TabbedForm.Tab>
209
+ </TabbedForm>
210
+ </Edit>
211
+ );
212
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./create";
2
+ export * from "./list";
3
+ export * from "./edit";
@@ -0,0 +1,15 @@
1
+ import { List, Datagrid, TextField, DateField } from "react-admin";
2
+ import { PostListActions } from "../listActions/PostListActions";
3
+
4
+ export function ConnectionsList() {
5
+ return (
6
+ <List actions={<PostListActions />}>
7
+ <Datagrid rowClick="edit" bulkActionButtons={false}>
8
+ <TextField source="id" />
9
+ <TextField source="name" />
10
+ <DateField source="created_at" showTime={true} />
11
+ <DateField source="updated_at" showTime={true} />
12
+ </Datagrid>
13
+ </List>
14
+ );
15
+ }
@@ -0,0 +1,26 @@
1
+ import {
2
+ Create,
3
+ SimpleForm,
4
+ TextInput,
5
+ SelectInput,
6
+ required,
7
+ } from "react-admin";
8
+
9
+ export function DomainCreate() {
10
+ return (
11
+ <Create>
12
+ <SimpleForm>
13
+ <TextInput source="domain" validate={[required()]} />
14
+ <SelectInput
15
+ source="type"
16
+ validate={[required()]}
17
+ defaultValue="auth0_managed_certs"
18
+ choices={[
19
+ { id: "auth0_managed_certs", name: "Auth0 Managed Certificates" },
20
+ { id: "self_managed_certs", name: "Self Managed Certificates" },
21
+ ]}
22
+ />
23
+ </SimpleForm>
24
+ </Create>
25
+ );
26
+ }
@@ -0,0 +1,101 @@
1
+ import {
2
+ ArrayField,
3
+ DateField,
4
+ Datagrid,
5
+ Edit,
6
+ FieldTitle,
7
+ Labeled,
8
+ SelectInput,
9
+ SimpleForm,
10
+ TextField,
11
+ TextInput,
12
+ useRecordContext,
13
+ } from "react-admin";
14
+ import CheckCircleIcon from "@mui/icons-material/CheckCircle";
15
+ import HourglassEmptyIcon from "@mui/icons-material/HourglassEmpty";
16
+ import { Typography, Box } from "@mui/material";
17
+
18
+ const StatusField = () => {
19
+ const record = useRecordContext();
20
+ if (!record) return null;
21
+
22
+ const isActive = record.status === "active";
23
+
24
+ return (
25
+ <Box
26
+ sx={{
27
+ display: "flex",
28
+ alignItems: "center",
29
+ color: isActive ? "success.main" : "warning.main",
30
+ }}
31
+ >
32
+ {isActive ? (
33
+ <CheckCircleIcon sx={{ mr: 1 }} fontSize="small" />
34
+ ) : (
35
+ <HourglassEmptyIcon sx={{ mr: 1 }} fontSize="small" />
36
+ )}
37
+ <Typography
38
+ component="span"
39
+ variant="body2"
40
+ sx={{
41
+ fontWeight: "medium",
42
+ textTransform: "capitalize",
43
+ }}
44
+ >
45
+ {record.status}
46
+ </Typography>
47
+ </Box>
48
+ );
49
+ };
50
+
51
+ export function DomainEdit() {
52
+ return (
53
+ <Edit>
54
+ <SimpleForm>
55
+ <TextInput source="domain" />
56
+ <Labeled label="Status">
57
+ <StatusField />
58
+ </Labeled>
59
+ <SelectInput
60
+ source="email_service"
61
+ choices={[
62
+ { id: "mailchannels", name: "Mailchannels" },
63
+ { id: "mailgun", name: "Mailgun" },
64
+ ]}
65
+ />
66
+ <TextInput
67
+ label="PEM Private Key"
68
+ source="dkim_private_key"
69
+ style={{ width: "800px" }}
70
+ multiline={true}
71
+ />
72
+ <TextInput
73
+ label="PEM Public Key"
74
+ source="dkim_public_key"
75
+ style={{ width: "800px" }}
76
+ multiline={true}
77
+ />
78
+ <TextInput
79
+ label="Api Key"
80
+ source="email_api_key"
81
+ style={{ width: "800px" }}
82
+ />
83
+ <Labeled label="Verification Methods">
84
+ <ArrayField source="verification.methods">
85
+ <Datagrid bulkActionButtons={false}>
86
+ <TextField source="name" />
87
+ <TextField source="record" style={{ fontFamily: "monospace" }} />
88
+ <TextField source="domain" />
89
+ </Datagrid>
90
+ </ArrayField>
91
+ </Labeled>
92
+ <Labeled label={<FieldTitle source="created_at" />}>
93
+ <DateField source="created_at" showTime={true} />
94
+ </Labeled>
95
+ <Labeled label={<FieldTitle source="updated_at" />}>
96
+ <DateField source="updated_at" showTime={true} />
97
+ </Labeled>
98
+ </SimpleForm>
99
+ </Edit>
100
+ );
101
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./create";
2
+ export * from "./list";
3
+ export * from "./edit";
@@ -0,0 +1,16 @@
1
+ import { List, Datagrid, TextField, BooleanField } from "react-admin";
2
+ import { PostListActions } from "../listActions/PostListActions";
3
+
4
+ export function DomainList() {
5
+ return (
6
+ <List actions={<PostListActions />}>
7
+ <Datagrid rowClick="edit" bulkActionButtons={false}>
8
+ <TextField source="custom_domain_id" label="ID" />
9
+ <TextField source="domain" />
10
+ <TextField source="status" />
11
+ <BooleanField source="primary" />
12
+ <TextField source="type" />
13
+ </Datagrid>
14
+ </List>
15
+ );
16
+ }
@@ -0,0 +1,30 @@
1
+ import { Create, TextInput, required, SimpleForm } from "react-admin";
2
+ import { Box, Typography } from "@mui/material";
3
+
4
+ export const FlowCreate = () => {
5
+ return (
6
+ <Create>
7
+ <SimpleForm>
8
+ <TextInput source="name" validate={[required()]} fullWidth />
9
+
10
+ <Box
11
+ sx={{
12
+ mt: 3,
13
+ p: 2,
14
+ bgcolor: "#f5f5f5",
15
+ borderRadius: 1,
16
+ color: "text.secondary",
17
+ }}
18
+ >
19
+ <Typography variant="body1">
20
+ Actions can be added after creating the flow.
21
+ </Typography>
22
+ <Typography variant="body2" sx={{ mt: 1 }}>
23
+ Flows define sequences of actions to execute, such as verifying
24
+ emails or updating user data.
25
+ </Typography>
26
+ </Box>
27
+ </SimpleForm>
28
+ </Create>
29
+ );
30
+ };