@rebasepro/auth 0.3.0 → 0.5.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/README.md +76 -0
- package/dist/hooks/useBackendUserManagement.d.ts +2 -6
- package/dist/index.es.js +6 -71
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +6 -71
- package/dist/index.umd.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/package.json +4 -4
- package/src/hooks/useBackendUserManagement.ts +8 -108
- package/src/hooks/useRebaseAuthController.ts +4 -4
- package/src/types.ts +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# @rebasepro/auth
|
|
2
|
+
|
|
3
|
+
Custom JWT authentication adapter for the Rebase backend — React hooks and API utilities for email/password, OAuth, and session management.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @rebasepro/auth
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**Peer dependencies:** `react >= 19`, `react-dom >= 19`
|
|
12
|
+
|
|
13
|
+
## What This Package Does
|
|
14
|
+
|
|
15
|
+
`@rebasepro/auth` connects the Rebase CMS frontend to the backend's JWT authentication system. It provides a React hook (`useRebaseAuthController`) that manages login, registration, token refresh, session persistence, and user profile updates, plus a lower-level API module for direct HTTP calls to auth endpoints. For the generic `LoginView` and `RebaseAuth` UI components, see `@rebasepro/core`.
|
|
16
|
+
|
|
17
|
+
## Key Exports
|
|
18
|
+
|
|
19
|
+
### Hooks
|
|
20
|
+
|
|
21
|
+
| Export | Description |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `useRebaseAuthController` | Main auth hook — returns a `RebaseAuthController` with login, register, logout, token refresh, session management, and profile methods. Accepts `RebaseAuthControllerProps`. |
|
|
24
|
+
| `useBackendUserManagement` | Hook for admin-level user CRUD (list, create, update, delete users). Returns a `UserManagement` interface. Accepts `BackendUserManagementConfig`. |
|
|
25
|
+
|
|
26
|
+
### Types
|
|
27
|
+
|
|
28
|
+
| Export | Description |
|
|
29
|
+
|---|---|
|
|
30
|
+
| `RebaseAuthController` | Extends the base `AuthController` with email/password login, Google login, generic OAuth, registration, password reset/change, session management, and profile updates. |
|
|
31
|
+
| `RebaseAuthControllerProps` | Config for `useRebaseAuthController` — `client`, `apiUrl`, `googleClientId`, `onSignOut`, `defineRolesFor`. |
|
|
32
|
+
| `AuthTokens` | `{ accessToken, refreshToken, accessTokenExpiresAt }` |
|
|
33
|
+
| `UserInfo` | `{ uid, email, displayName, photoURL, emailVerified, roles, metadata }` |
|
|
34
|
+
| `AuthResponse` | `{ user: UserInfo, tokens: AuthTokens }` |
|
|
35
|
+
| `RefreshResponse` | `{ tokens: AuthTokens }` |
|
|
36
|
+
| `BackendUserManagementConfig` | Config for `useBackendUserManagement`. |
|
|
37
|
+
| `UserManagement` | Interface returned by `useBackendUserManagement`. |
|
|
38
|
+
|
|
39
|
+
### API Utilities
|
|
40
|
+
|
|
41
|
+
| Export | Description |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `setApiUrl(url)` | Set the base API URL for all auth requests |
|
|
44
|
+
| `getApiUrl()` | Get the current base API URL |
|
|
45
|
+
| `fetchAuthConfig()` | Fetch auth config from `/api/auth/config` (cached, deduplicated) |
|
|
46
|
+
| `AuthApiError` | Error class with `message` and `code` fields |
|
|
47
|
+
| `AuthConfigResponse` | Type — `{ needsSetup, registrationEnabled, emailServiceEnabled, passwordReset, emailVerification, enabledProviders }` |
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { useRebaseAuthController } from "@rebasepro/auth";
|
|
53
|
+
import { createRebaseClient } from "@rebasepro/client";
|
|
54
|
+
|
|
55
|
+
const client = createRebaseClient({ baseUrl: "http://localhost:3001" });
|
|
56
|
+
|
|
57
|
+
function App() {
|
|
58
|
+
const authController = useRebaseAuthController({
|
|
59
|
+
client,
|
|
60
|
+
apiUrl: "http://localhost:3001",
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// authController.emailPasswordLogin(email, password)
|
|
64
|
+
// authController.googleLogin({ idToken })
|
|
65
|
+
// authController.register(email, password, displayName)
|
|
66
|
+
// authController.signOut()
|
|
67
|
+
// authController.user — current logged-in user or null
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Related Packages
|
|
72
|
+
|
|
73
|
+
- [`@rebasepro/core`](../core) — `LoginView`, `RebaseAuth` UI components, `AuthController` base type
|
|
74
|
+
- [`@rebasepro/client`](../client) — HTTP client with its own `auth` module for direct API calls
|
|
75
|
+
- [`@rebasepro/types`](../types) — Base `AuthController` and `User` types
|
|
76
|
+
- [`@rebasepro/ui`](../ui) — UI components used by auth views
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { User } from "@rebasepro/types";
|
|
2
2
|
/**
|
|
3
3
|
* UserManagement interface - compatible with @rebasepro/user_management
|
|
4
4
|
* Defined inline to avoid dependency on that package
|
|
@@ -19,12 +19,9 @@ export interface UserManagement<USER extends User = User> {
|
|
|
19
19
|
temporaryPassword?: string;
|
|
20
20
|
}>;
|
|
21
21
|
deleteUser: (user: USER) => Promise<void>;
|
|
22
|
-
roles: Role[];
|
|
23
|
-
saveRole: (role: Role) => Promise<void>;
|
|
24
|
-
deleteRole: (role: Role) => Promise<void>;
|
|
25
22
|
isAdmin?: boolean;
|
|
26
23
|
allowDefaultRolesCreation?: boolean;
|
|
27
|
-
defineRolesFor: (user: User) => Promise<
|
|
24
|
+
defineRolesFor: (user: User) => Promise<string[] | undefined> | string[] | undefined;
|
|
28
25
|
getUser: (uid: string) => User | null;
|
|
29
26
|
/**
|
|
30
27
|
* Search users with server-side pagination.
|
|
@@ -43,7 +40,6 @@ export interface UserManagement<USER extends User = User> {
|
|
|
43
40
|
total: number;
|
|
44
41
|
}>;
|
|
45
42
|
usersError?: Error;
|
|
46
|
-
rolesError?: Error;
|
|
47
43
|
bootstrapAdmin?: () => Promise<void>;
|
|
48
44
|
}
|
|
49
45
|
export interface BackendUserManagementConfig {
|
package/dist/index.es.js
CHANGED
|
@@ -425,7 +425,7 @@ function useRebaseAuthController(props = {}) {
|
|
|
425
425
|
if (defineRolesFor) {
|
|
426
426
|
const customRoles = await defineRolesFor(convertedUser);
|
|
427
427
|
if (customRoles) {
|
|
428
|
-
convertedUser = { ...convertedUser, roles: customRoles
|
|
428
|
+
convertedUser = { ...convertedUser, roles: customRoles };
|
|
429
429
|
}
|
|
430
430
|
}
|
|
431
431
|
saveAuthToStorage(tokens, userInfo);
|
|
@@ -556,7 +556,7 @@ function useRebaseAuthController(props = {}) {
|
|
|
556
556
|
if (customRoles) {
|
|
557
557
|
convertedUser = {
|
|
558
558
|
...convertedUser,
|
|
559
|
-
roles: customRoles
|
|
559
|
+
roles: customRoles
|
|
560
560
|
};
|
|
561
561
|
}
|
|
562
562
|
}
|
|
@@ -630,7 +630,7 @@ function useRebaseAuthController(props = {}) {
|
|
|
630
630
|
if (customRoles) {
|
|
631
631
|
userToSet = {
|
|
632
632
|
...userToSet,
|
|
633
|
-
roles: customRoles
|
|
633
|
+
roles: customRoles
|
|
634
634
|
};
|
|
635
635
|
}
|
|
636
636
|
}
|
|
@@ -662,7 +662,7 @@ function useRebaseAuthController(props = {}) {
|
|
|
662
662
|
if (customRoles) {
|
|
663
663
|
userToSet = {
|
|
664
664
|
...userToSet,
|
|
665
|
-
roles: customRoles
|
|
665
|
+
roles: customRoles
|
|
666
666
|
};
|
|
667
667
|
}
|
|
668
668
|
}
|
|
@@ -791,18 +791,10 @@ function convertUser(apiUser) {
|
|
|
791
791
|
createdAt: apiUser.createdAt ? new Date(apiUser.createdAt) : null
|
|
792
792
|
};
|
|
793
793
|
}
|
|
794
|
-
function convertRole(apiRole) {
|
|
795
|
-
return {
|
|
796
|
-
id: apiRole.id,
|
|
797
|
-
name: apiRole.name,
|
|
798
|
-
isAdmin: apiRole.isAdmin ?? false
|
|
799
|
-
};
|
|
800
|
-
}
|
|
801
794
|
function useBackendUserManagement(config) {
|
|
802
795
|
const { client, apiUrl, getAuthToken, currentUser } = config;
|
|
803
796
|
const [userCache, setUserCache] = useState(/* @__PURE__ */ new Map());
|
|
804
797
|
const [hasAdminUsers, setHasAdminUsers] = useState(false);
|
|
805
|
-
const [roles, setRoles] = useState([]);
|
|
806
798
|
const userRoles = currentUser?.roles ?? [];
|
|
807
799
|
const isUserAdmin = userRoles.some((r) => r === "admin" || r === "schema-admin");
|
|
808
800
|
const [loading, setLoading] = useState(() => {
|
|
@@ -811,7 +803,6 @@ function useBackendUserManagement(config) {
|
|
|
811
803
|
return true;
|
|
812
804
|
});
|
|
813
805
|
const [usersError, setUsersError] = useState();
|
|
814
|
-
const [rolesError, setRolesError] = useState();
|
|
815
806
|
const lastLoadedUidRef = useRef(null);
|
|
816
807
|
const effectiveLoading = loading || !!(currentUser && isUserAdmin && lastLoadedUidRef.current !== currentUser.uid);
|
|
817
808
|
const mergeIntoCache = useCallback((incoming) => {
|
|
@@ -892,17 +883,6 @@ function useBackendUserManagement(config) {
|
|
|
892
883
|
throw lastError;
|
|
893
884
|
}, [apiUrl, getAuthToken]);
|
|
894
885
|
apiRequestRef.current = apiRequest;
|
|
895
|
-
useCallback(async (signal) => {
|
|
896
|
-
try {
|
|
897
|
-
const data = await apiRequest("/roles", "GET", void 0, 6, signal);
|
|
898
|
-
setRoles(data.roles.map(convertRole));
|
|
899
|
-
setRolesError(void 0);
|
|
900
|
-
} catch (error) {
|
|
901
|
-
if (error instanceof Error && error.name === "AbortError") return;
|
|
902
|
-
console.error("Failed to load roles:", error);
|
|
903
|
-
setRolesError(error instanceof Error ? error : new Error(String(error)));
|
|
904
|
-
}
|
|
905
|
-
}, [apiRequest]);
|
|
906
886
|
const checkAdminExists = useCallback(async (signal) => {
|
|
907
887
|
try {
|
|
908
888
|
const data = await apiRequest("/users?role=admin&limit=1", "GET", void 0, 6, signal);
|
|
@@ -937,21 +917,6 @@ function useBackendUserManagement(config) {
|
|
|
937
917
|
const load = async () => {
|
|
938
918
|
setLoading(true);
|
|
939
919
|
const request = apiRequestRef.current;
|
|
940
|
-
try {
|
|
941
|
-
const data = await request("/roles", "GET", void 0, 6, abortController.signal);
|
|
942
|
-
setRoles(data.roles.map(convertRole));
|
|
943
|
-
setRolesError(void 0);
|
|
944
|
-
} catch (error) {
|
|
945
|
-
if (error instanceof Error && error.name === "AbortError") return;
|
|
946
|
-
console.error("Failed to load roles:", error);
|
|
947
|
-
setRolesError(error instanceof Error ? error : new Error(String(error)));
|
|
948
|
-
const status = error.status;
|
|
949
|
-
if (status === 403 || status === 401) {
|
|
950
|
-
setUsersError(error instanceof Error ? error : new Error(String(error)));
|
|
951
|
-
setLoading(false);
|
|
952
|
-
return;
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
920
|
if (!abortController.signal.aborted) {
|
|
956
921
|
try {
|
|
957
922
|
const data = await request("/users?role=admin&limit=1", "GET", void 0, 6, abortController.signal);
|
|
@@ -1038,29 +1003,6 @@ function useBackendUserManagement(config) {
|
|
|
1038
1003
|
return next;
|
|
1039
1004
|
});
|
|
1040
1005
|
}, [apiRequest]);
|
|
1041
|
-
const saveRole = useCallback(async (role) => {
|
|
1042
|
-
const existingRole = roles.find((r) => r.id === role.id);
|
|
1043
|
-
if (existingRole) {
|
|
1044
|
-
const data = await apiRequest(`/roles/${role.id}`, "PUT", {
|
|
1045
|
-
name: role.name,
|
|
1046
|
-
isAdmin: role.isAdmin
|
|
1047
|
-
});
|
|
1048
|
-
const updated = convertRole(data.role);
|
|
1049
|
-
setRoles((prev) => prev.map((r) => r.id === updated.id ? updated : r));
|
|
1050
|
-
} else {
|
|
1051
|
-
const data = await apiRequest("/roles", "POST", {
|
|
1052
|
-
id: role.id,
|
|
1053
|
-
name: role.name,
|
|
1054
|
-
isAdmin: role.isAdmin ?? false
|
|
1055
|
-
});
|
|
1056
|
-
const created = convertRole(data.role);
|
|
1057
|
-
setRoles((prev) => [...prev, created]);
|
|
1058
|
-
}
|
|
1059
|
-
}, [apiRequest, roles]);
|
|
1060
|
-
const deleteRole = useCallback(async (role) => {
|
|
1061
|
-
await apiRequest(`/roles/${role.id}`, "DELETE");
|
|
1062
|
-
setRoles((prev) => prev.filter((r) => r.id !== role.id));
|
|
1063
|
-
}, [apiRequest]);
|
|
1064
1006
|
const getUser = useCallback((uid) => {
|
|
1065
1007
|
return userCache.get(uid) ?? null;
|
|
1066
1008
|
}, [userCache]);
|
|
@@ -1076,15 +1018,12 @@ function useBackendUserManagement(config) {
|
|
|
1076
1018
|
}
|
|
1077
1019
|
}
|
|
1078
1020
|
const userRoleIds = existingUser.roles ?? [];
|
|
1079
|
-
return
|
|
1080
|
-
}, [userCache,
|
|
1021
|
+
return userRoleIds;
|
|
1022
|
+
}, [userCache, apiRequest, mergeIntoCache]);
|
|
1081
1023
|
const isAdmin = currentUser?.roles?.includes("admin") ?? false;
|
|
1082
1024
|
const bootstrapAdmin = useCallback(async () => {
|
|
1083
1025
|
try {
|
|
1084
1026
|
await apiRequest("/bootstrap", "POST");
|
|
1085
|
-
const data = await apiRequest("/roles");
|
|
1086
|
-
const loadedRoles = data.roles.map(convertRole);
|
|
1087
|
-
setRoles(loadedRoles);
|
|
1088
1027
|
await checkAdminExists();
|
|
1089
1028
|
} catch (error) {
|
|
1090
1029
|
console.error("Failed to bootstrap admin:", error);
|
|
@@ -1100,16 +1039,12 @@ function useBackendUserManagement(config) {
|
|
|
1100
1039
|
createUser,
|
|
1101
1040
|
resetPassword: resetPassword2,
|
|
1102
1041
|
deleteUser,
|
|
1103
|
-
roles,
|
|
1104
|
-
saveRole,
|
|
1105
|
-
deleteRole,
|
|
1106
1042
|
isAdmin,
|
|
1107
1043
|
allowDefaultRolesCreation: isAdmin,
|
|
1108
1044
|
defineRolesFor,
|
|
1109
1045
|
getUser,
|
|
1110
1046
|
searchUsers,
|
|
1111
1047
|
usersError,
|
|
1112
|
-
rolesError,
|
|
1113
1048
|
bootstrapAdmin
|
|
1114
1049
|
};
|
|
1115
1050
|
}
|