nextauthz 1.1.9 → 1.2.1

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/dist/index.d.mts CHANGED
@@ -2,9 +2,13 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import React__default from 'react';
4
4
 
5
- type AuthContextType<UserType> = {
5
+ type User$1 = {
6
+ [key: string]: any;
7
+ };
8
+
9
+ type AuthContextType<UserType extends User$1> = {
6
10
  user: UserType | null;
7
- login: (tokens: Record<string, string>, user: UserType) => void;
11
+ login: (tokens: Record<string, string>, userData: UserType) => void;
8
12
  logout: () => void;
9
13
  setUser: (user: UserType) => void;
10
14
  loading: boolean;
@@ -15,27 +19,22 @@ type AuthGuardProps = {
15
19
  children: React__default.ReactNode;
16
20
  redirectTo?: string;
17
21
  tokenKey?: string;
18
- refreshToken?: () => Promise<string | null>;
19
22
  };
20
- declare const AuthGuard: ({ children, redirectTo, tokenKey, refreshToken, }: AuthGuardProps) => react_jsx_runtime.JSX.Element | null;
23
+ declare const AuthGuard: ({ children, redirectTo, tokenKey, }: AuthGuardProps) => react_jsx_runtime.JSX.Element;
21
24
 
22
25
  type RoleGuardProps = {
23
26
  children: React__default.ReactNode;
24
27
  allowedRoles: string[];
25
28
  redirectTo?: string;
26
29
  };
27
- declare const RoleGuard: ({ children, allowedRoles, redirectTo, }: RoleGuardProps) => react_jsx_runtime.JSX.Element;
30
+ declare const RoleGuard: ({ children, allowedRoles, redirectTo, }: RoleGuardProps) => react_jsx_runtime.JSX.Element | null;
28
31
 
29
32
  type User = any;
30
33
  declare function createAppAuth(storage?: 'localStorage' | 'sessionStorage' | 'cookie'): {
31
34
  AuthProvider: ({ children }: {
32
35
  children: React.ReactNode;
33
36
  }) => react_jsx_runtime.JSX.Element;
34
- useAuth: () => AuthContextType<any>;
37
+ useAuth: () => AuthContextType<User$1>;
35
38
  };
36
- declare const AuthProvider: ({ children }: {
37
- children: React.ReactNode;
38
- }) => react_jsx_runtime.JSX.Element;
39
- declare const useAuth: () => AuthContextType<any>;
40
39
 
41
- export { AuthGuard, AuthProvider, RoleGuard, type User, createAppAuth, useAuth };
40
+ export { AuthGuard, RoleGuard, type User, createAppAuth };
package/dist/index.d.ts CHANGED
@@ -2,9 +2,13 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import React__default from 'react';
4
4
 
5
- type AuthContextType<UserType> = {
5
+ type User$1 = {
6
+ [key: string]: any;
7
+ };
8
+
9
+ type AuthContextType<UserType extends User$1> = {
6
10
  user: UserType | null;
7
- login: (tokens: Record<string, string>, user: UserType) => void;
11
+ login: (tokens: Record<string, string>, userData: UserType) => void;
8
12
  logout: () => void;
9
13
  setUser: (user: UserType) => void;
10
14
  loading: boolean;
@@ -15,27 +19,22 @@ type AuthGuardProps = {
15
19
  children: React__default.ReactNode;
16
20
  redirectTo?: string;
17
21
  tokenKey?: string;
18
- refreshToken?: () => Promise<string | null>;
19
22
  };
20
- declare const AuthGuard: ({ children, redirectTo, tokenKey, refreshToken, }: AuthGuardProps) => react_jsx_runtime.JSX.Element | null;
23
+ declare const AuthGuard: ({ children, redirectTo, tokenKey, }: AuthGuardProps) => react_jsx_runtime.JSX.Element;
21
24
 
22
25
  type RoleGuardProps = {
23
26
  children: React__default.ReactNode;
24
27
  allowedRoles: string[];
25
28
  redirectTo?: string;
26
29
  };
27
- declare const RoleGuard: ({ children, allowedRoles, redirectTo, }: RoleGuardProps) => react_jsx_runtime.JSX.Element;
30
+ declare const RoleGuard: ({ children, allowedRoles, redirectTo, }: RoleGuardProps) => react_jsx_runtime.JSX.Element | null;
28
31
 
29
32
  type User = any;
30
33
  declare function createAppAuth(storage?: 'localStorage' | 'sessionStorage' | 'cookie'): {
31
34
  AuthProvider: ({ children }: {
32
35
  children: React.ReactNode;
33
36
  }) => react_jsx_runtime.JSX.Element;
34
- useAuth: () => AuthContextType<any>;
37
+ useAuth: () => AuthContextType<User$1>;
35
38
  };
36
- declare const AuthProvider: ({ children }: {
37
- children: React.ReactNode;
38
- }) => react_jsx_runtime.JSX.Element;
39
- declare const useAuth: () => AuthContextType<any>;
40
39
 
41
- export { AuthGuard, AuthProvider, RoleGuard, type User, createAppAuth, useAuth };
40
+ export { AuthGuard, RoleGuard, type User, createAppAuth };
package/dist/index.js CHANGED
@@ -22,10 +22,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
22
22
  var index_exports = {};
23
23
  __export(index_exports, {
24
24
  AuthGuard: () => AuthGuard_default,
25
- AuthProvider: () => AuthProvider,
26
25
  RoleGuard: () => RoleGuard_default,
27
- createAppAuth: () => createAppAuth,
28
- useAuth: () => useAuth
26
+ createAppAuth: () => createAppAuth
29
27
  });
30
28
  module.exports = __toCommonJS(index_exports);
31
29
 
@@ -39,88 +37,89 @@ var useAuthStore = (0, import_zustand.create)((set) => ({
39
37
  user: null,
40
38
  isAuthenticated: false,
41
39
  isAuthChecked: false,
40
+ loading: true,
41
+ // start as loading
42
42
  error: null,
43
43
  setUser: (user) => set({ user }),
44
44
  setAuth: (isAuth) => set({ isAuthenticated: isAuth }),
45
45
  setAuthChecked: (checked) => set({ isAuthChecked: checked }),
46
+ setLoading: (loading) => set({ loading }),
46
47
  setError: (err) => set({ error: err }),
47
48
  resetAuth: () => set({
48
49
  user: null,
49
50
  isAuthenticated: false,
50
51
  isAuthChecked: false,
52
+ loading: false,
51
53
  error: null
52
54
  })
53
55
  }));
54
56
 
55
57
  // src/AuthProvider.tsx
56
58
  var import_jsx_runtime = require("react/jsx-runtime");
57
- function createAuthContext(options) {
58
- const AuthContext = (0, import_react.createContext)(null);
59
- const AuthProvider2 = ({ children }) => {
60
- const storageType = options?.storage || "cookie";
61
- (0, import_react.useEffect)(() => {
62
- (0, import_react_token_manager.configureTokenManager)({ storage: storageType });
63
- }, [storageType]);
59
+ function createAuthContext(options = {}) {
60
+ const { storage = "cookie" } = options;
61
+ const AuthContext = (0, import_react.createContext)(
62
+ void 0
63
+ );
64
+ const AuthProvider = ({ children }) => {
65
+ const configuredRef = (0, import_react.useRef)(false);
64
66
  const manager = (0, import_react_token_manager.useTokenManager)();
65
- const [loading, setLoading] = (0, import_react.useState)(true);
66
- const rawUser = useAuthStore((state) => state.user);
67
- const error = useAuthStore((state) => state.error);
68
- const user = rawUser;
67
+ const { user, loading, error, setUser, setLoading, setError, resetAuth } = useAuthStore();
68
+ (0, import_react.useEffect)(() => {
69
+ if (!configuredRef.current) {
70
+ (0, import_react_token_manager.configureTokenManager)({ storage });
71
+ configuredRef.current = true;
72
+ }
73
+ }, [storage]);
69
74
  (0, import_react.useEffect)(() => {
70
- const savedUser = manager.getSingleToken("user");
71
- if (savedUser) {
72
- try {
73
- const parsedUser = JSON.parse(savedUser);
74
- useAuthStore.getState().setUser(parsedUser);
75
- useAuthStore.getState().setError(null);
76
- } catch {
77
- useAuthStore.getState().resetAuth();
78
- useAuthStore.getState().setError(
79
- new Error("Failed to parse saved user")
80
- );
75
+ try {
76
+ const savedUser = manager.getSingleToken("user");
77
+ if (savedUser) {
78
+ setUser(JSON.parse(savedUser));
81
79
  }
80
+ } catch (err) {
81
+ setError(err instanceof Error ? err : new Error(String(err)));
82
+ } finally {
83
+ setLoading(false);
82
84
  }
83
- setLoading(false);
84
- }, [manager]);
85
- const setUser = (userData) => {
86
- useAuthStore.getState().setUser(userData);
87
- useAuthStore.getState().setError(null);
88
- manager.setTokens({ user: JSON.stringify(userData) });
89
- };
85
+ }, [manager, setUser, setLoading, setError]);
90
86
  const login = (tokens, userData) => {
91
87
  try {
92
- manager.setTokens(tokens);
88
+ manager.setTokens({ ...tokens, user: JSON.stringify(userData) });
93
89
  setUser(userData);
94
90
  } catch (err) {
95
- useAuthStore.getState().setError(
96
- err instanceof Error ? err : new Error(String(err))
97
- );
91
+ setError(err instanceof Error ? err : new Error(String(err)));
98
92
  }
99
93
  };
100
94
  const logout = () => {
101
95
  try {
102
96
  manager.clearTokens();
103
- useAuthStore.getState().resetAuth();
97
+ resetAuth();
104
98
  } catch (err) {
105
- useAuthStore.getState().setError(
106
- err instanceof Error ? err : new Error(String(err))
107
- );
99
+ setError(err instanceof Error ? err : new Error(String(err)));
108
100
  }
109
101
  };
110
102
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
111
103
  AuthContext.Provider,
112
104
  {
113
- value: { user, login, logout, setUser, loading, error },
105
+ value: {
106
+ user,
107
+ login,
108
+ logout,
109
+ setUser: (u) => setUser(u),
110
+ loading,
111
+ error
112
+ },
114
113
  children
115
114
  }
116
115
  );
117
116
  };
118
- const useAuth2 = () => {
117
+ const useAuth = () => {
119
118
  const ctx = (0, import_react.useContext)(AuthContext);
120
119
  if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
121
120
  return ctx;
122
121
  };
123
- return { AuthProvider: AuthProvider2, useAuth: useAuth2 };
122
+ return { AuthProvider, useAuth };
124
123
  }
125
124
 
126
125
  // src/AuthGuard.tsx
@@ -131,48 +130,25 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
131
130
  var AuthGuard = ({
132
131
  children,
133
132
  redirectTo = "/login",
134
- tokenKey = "access_token",
135
- refreshToken
133
+ tokenKey = "access_token"
136
134
  }) => {
137
- const manager = (0, import_react_token_manager2.useTokenManager)();
138
135
  const router = (0, import_navigation.useRouter)();
139
- const isAuthChecked = useAuthStore((state) => state.isAuthChecked);
140
- const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
141
- const error = useAuthStore((state) => state.error);
136
+ const manager = (0, import_react_token_manager2.useTokenManager)();
137
+ const setAuth = useAuthStore((state) => state.setAuth);
138
+ const setAuthChecked = useAuthStore((state) => state.setAuthChecked);
139
+ const [loading, setLoading] = (0, import_react2.useState)(true);
142
140
  (0, import_react2.useEffect)(() => {
143
- const checkAuth = async () => {
144
- try {
145
- let token = manager.getSingleToken(tokenKey);
146
- if (!token || manager.isExpired(token)) {
147
- if (refreshToken) {
148
- const newToken = await refreshToken();
149
- if (newToken) {
150
- manager.setTokens({ [tokenKey]: newToken });
151
- token = newToken;
152
- }
153
- }
154
- }
155
- const isValid = token && !manager.isExpired(token);
156
- useAuthStore.getState().setAuth(Boolean(isValid));
157
- if (!isValid) {
158
- router.replace(redirectTo);
159
- }
160
- } catch (err) {
161
- useAuthStore.getState().setError(err instanceof Error ? err : new Error(String(err)));
162
- useAuthStore.getState().setAuth(false);
163
- router.replace(redirectTo);
164
- } finally {
165
- useAuthStore.getState().setAuthChecked(true);
166
- }
167
- };
168
- checkAuth();
169
- }, [manager, router, redirectTo, tokenKey, refreshToken]);
170
- if (!isAuthChecked) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: "Loading..." });
171
- if (error) return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
172
- "Error: ",
173
- error.message
174
- ] });
175
- if (!isAuthenticated) return null;
141
+ const token = manager.getSingleToken(tokenKey);
142
+ const isValid = Boolean(token) && !manager.isExpired(token);
143
+ setAuth(Boolean(isValid));
144
+ setAuthChecked(true);
145
+ if (!isValid) {
146
+ router.replace(redirectTo);
147
+ } else {
148
+ setLoading(false);
149
+ }
150
+ }, [manager, tokenKey, redirectTo, router, setAuth, setAuthChecked]);
151
+ if (loading) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: "Loading..." });
176
152
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
177
153
  };
178
154
  var AuthGuard_default = AuthGuard;
@@ -186,18 +162,23 @@ var RoleGuard = ({
186
162
  allowedRoles,
187
163
  redirectTo = "/unauthorized"
188
164
  }) => {
189
- const { user, loading } = useAuth();
190
165
  const router = (0, import_navigation2.useRouter)();
191
- const [isChecking, setIsChecking] = (0, import_react3.useState)(true);
166
+ const { user, isAuthChecked, isAuthenticated } = useAuthStore();
192
167
  (0, import_react3.useEffect)(() => {
193
- if (!user) return;
194
- const hasAccess = allowedRoles.includes(user?.role);
195
- if (!hasAccess) {
168
+ if (!isAuthChecked) return;
169
+ if (!isAuthenticated || !user) {
170
+ router.replace("/login");
171
+ return;
172
+ }
173
+ const role2 = user?.role;
174
+ if (!allowedRoles.includes(role2)) {
196
175
  router.replace(redirectTo);
197
176
  }
198
- setIsChecking(false);
199
- }, [user, allowedRoles, redirectTo, router]);
200
- if (loading || !user || isChecking) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: "Loading..." });
177
+ }, [isAuthChecked, isAuthenticated, user, allowedRoles, redirectTo, router]);
178
+ if (!isAuthChecked) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: "Loading..." });
179
+ if (!isAuthenticated || !user) return null;
180
+ const role = user?.role;
181
+ if (!allowedRoles.includes(role)) return null;
201
182
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
202
183
  };
203
184
  var RoleGuard_default = RoleGuard;
@@ -206,12 +187,9 @@ var RoleGuard_default = RoleGuard;
206
187
  function createAppAuth(storage = "cookie") {
207
188
  return createAuthContext({ storage });
208
189
  }
209
- var { AuthProvider, useAuth } = createAppAuth();
210
190
  // Annotate the CommonJS export names for ESM import in node:
211
191
  0 && (module.exports = {
212
192
  AuthGuard,
213
- AuthProvider,
214
193
  RoleGuard,
215
- createAppAuth,
216
- useAuth
194
+ createAppAuth
217
195
  });
package/dist/index.mjs CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  createContext,
6
6
  useContext,
7
7
  useEffect,
8
- useState
8
+ useRef
9
9
  } from "react";
10
10
  import { configureTokenManager, useTokenManager } from "react-token-manager";
11
11
 
@@ -15,146 +15,124 @@ var useAuthStore = create((set) => ({
15
15
  user: null,
16
16
  isAuthenticated: false,
17
17
  isAuthChecked: false,
18
+ loading: true,
19
+ // start as loading
18
20
  error: null,
19
21
  setUser: (user) => set({ user }),
20
22
  setAuth: (isAuth) => set({ isAuthenticated: isAuth }),
21
23
  setAuthChecked: (checked) => set({ isAuthChecked: checked }),
24
+ setLoading: (loading) => set({ loading }),
22
25
  setError: (err) => set({ error: err }),
23
26
  resetAuth: () => set({
24
27
  user: null,
25
28
  isAuthenticated: false,
26
29
  isAuthChecked: false,
30
+ loading: false,
27
31
  error: null
28
32
  })
29
33
  }));
30
34
 
31
35
  // src/AuthProvider.tsx
32
36
  import { jsx } from "react/jsx-runtime";
33
- function createAuthContext(options) {
34
- const AuthContext = createContext(null);
35
- const AuthProvider2 = ({ children }) => {
36
- const storageType = options?.storage || "cookie";
37
- useEffect(() => {
38
- configureTokenManager({ storage: storageType });
39
- }, [storageType]);
37
+ function createAuthContext(options = {}) {
38
+ const { storage = "cookie" } = options;
39
+ const AuthContext = createContext(
40
+ void 0
41
+ );
42
+ const AuthProvider = ({ children }) => {
43
+ const configuredRef = useRef(false);
40
44
  const manager = useTokenManager();
41
- const [loading, setLoading] = useState(true);
42
- const rawUser = useAuthStore((state) => state.user);
43
- const error = useAuthStore((state) => state.error);
44
- const user = rawUser;
45
+ const { user, loading, error, setUser, setLoading, setError, resetAuth } = useAuthStore();
46
+ useEffect(() => {
47
+ if (!configuredRef.current) {
48
+ configureTokenManager({ storage });
49
+ configuredRef.current = true;
50
+ }
51
+ }, [storage]);
45
52
  useEffect(() => {
46
- const savedUser = manager.getSingleToken("user");
47
- if (savedUser) {
48
- try {
49
- const parsedUser = JSON.parse(savedUser);
50
- useAuthStore.getState().setUser(parsedUser);
51
- useAuthStore.getState().setError(null);
52
- } catch {
53
- useAuthStore.getState().resetAuth();
54
- useAuthStore.getState().setError(
55
- new Error("Failed to parse saved user")
56
- );
53
+ try {
54
+ const savedUser = manager.getSingleToken("user");
55
+ if (savedUser) {
56
+ setUser(JSON.parse(savedUser));
57
57
  }
58
+ } catch (err) {
59
+ setError(err instanceof Error ? err : new Error(String(err)));
60
+ } finally {
61
+ setLoading(false);
58
62
  }
59
- setLoading(false);
60
- }, [manager]);
61
- const setUser = (userData) => {
62
- useAuthStore.getState().setUser(userData);
63
- useAuthStore.getState().setError(null);
64
- manager.setTokens({ user: JSON.stringify(userData) });
65
- };
63
+ }, [manager, setUser, setLoading, setError]);
66
64
  const login = (tokens, userData) => {
67
65
  try {
68
- manager.setTokens(tokens);
66
+ manager.setTokens({ ...tokens, user: JSON.stringify(userData) });
69
67
  setUser(userData);
70
68
  } catch (err) {
71
- useAuthStore.getState().setError(
72
- err instanceof Error ? err : new Error(String(err))
73
- );
69
+ setError(err instanceof Error ? err : new Error(String(err)));
74
70
  }
75
71
  };
76
72
  const logout = () => {
77
73
  try {
78
74
  manager.clearTokens();
79
- useAuthStore.getState().resetAuth();
75
+ resetAuth();
80
76
  } catch (err) {
81
- useAuthStore.getState().setError(
82
- err instanceof Error ? err : new Error(String(err))
83
- );
77
+ setError(err instanceof Error ? err : new Error(String(err)));
84
78
  }
85
79
  };
86
80
  return /* @__PURE__ */ jsx(
87
81
  AuthContext.Provider,
88
82
  {
89
- value: { user, login, logout, setUser, loading, error },
83
+ value: {
84
+ user,
85
+ login,
86
+ logout,
87
+ setUser: (u) => setUser(u),
88
+ loading,
89
+ error
90
+ },
90
91
  children
91
92
  }
92
93
  );
93
94
  };
94
- const useAuth2 = () => {
95
+ const useAuth = () => {
95
96
  const ctx = useContext(AuthContext);
96
97
  if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
97
98
  return ctx;
98
99
  };
99
- return { AuthProvider: AuthProvider2, useAuth: useAuth2 };
100
+ return { AuthProvider, useAuth };
100
101
  }
101
102
 
102
103
  // src/AuthGuard.tsx
103
- import { useEffect as useEffect2 } from "react";
104
+ import { useEffect as useEffect2, useState } from "react";
104
105
  import { useRouter } from "next/navigation";
105
106
  import { useTokenManager as useTokenManager2 } from "react-token-manager";
106
- import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
107
+ import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
107
108
  var AuthGuard = ({
108
109
  children,
109
110
  redirectTo = "/login",
110
- tokenKey = "access_token",
111
- refreshToken
111
+ tokenKey = "access_token"
112
112
  }) => {
113
- const manager = useTokenManager2();
114
113
  const router = useRouter();
115
- const isAuthChecked = useAuthStore((state) => state.isAuthChecked);
116
- const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
117
- const error = useAuthStore((state) => state.error);
114
+ const manager = useTokenManager2();
115
+ const setAuth = useAuthStore((state) => state.setAuth);
116
+ const setAuthChecked = useAuthStore((state) => state.setAuthChecked);
117
+ const [loading, setLoading] = useState(true);
118
118
  useEffect2(() => {
119
- const checkAuth = async () => {
120
- try {
121
- let token = manager.getSingleToken(tokenKey);
122
- if (!token || manager.isExpired(token)) {
123
- if (refreshToken) {
124
- const newToken = await refreshToken();
125
- if (newToken) {
126
- manager.setTokens({ [tokenKey]: newToken });
127
- token = newToken;
128
- }
129
- }
130
- }
131
- const isValid = token && !manager.isExpired(token);
132
- useAuthStore.getState().setAuth(Boolean(isValid));
133
- if (!isValid) {
134
- router.replace(redirectTo);
135
- }
136
- } catch (err) {
137
- useAuthStore.getState().setError(err instanceof Error ? err : new Error(String(err)));
138
- useAuthStore.getState().setAuth(false);
139
- router.replace(redirectTo);
140
- } finally {
141
- useAuthStore.getState().setAuthChecked(true);
142
- }
143
- };
144
- checkAuth();
145
- }, [manager, router, redirectTo, tokenKey, refreshToken]);
146
- if (!isAuthChecked) return /* @__PURE__ */ jsx2("div", { children: "Loading..." });
147
- if (error) return /* @__PURE__ */ jsxs("div", { children: [
148
- "Error: ",
149
- error.message
150
- ] });
151
- if (!isAuthenticated) return null;
119
+ const token = manager.getSingleToken(tokenKey);
120
+ const isValid = Boolean(token) && !manager.isExpired(token);
121
+ setAuth(Boolean(isValid));
122
+ setAuthChecked(true);
123
+ if (!isValid) {
124
+ router.replace(redirectTo);
125
+ } else {
126
+ setLoading(false);
127
+ }
128
+ }, [manager, tokenKey, redirectTo, router, setAuth, setAuthChecked]);
129
+ if (loading) return /* @__PURE__ */ jsx2("div", { children: "Loading..." });
152
130
  return /* @__PURE__ */ jsx2(Fragment, { children });
153
131
  };
154
132
  var AuthGuard_default = AuthGuard;
155
133
 
156
134
  // src/RoleGuard.tsx
157
- import { useEffect as useEffect3, useState as useState3 } from "react";
135
+ import { useEffect as useEffect3 } from "react";
158
136
  import { useRouter as useRouter2 } from "next/navigation";
159
137
  import { Fragment as Fragment2, jsx as jsx3 } from "react/jsx-runtime";
160
138
  var RoleGuard = ({
@@ -162,18 +140,23 @@ var RoleGuard = ({
162
140
  allowedRoles,
163
141
  redirectTo = "/unauthorized"
164
142
  }) => {
165
- const { user, loading } = useAuth();
166
143
  const router = useRouter2();
167
- const [isChecking, setIsChecking] = useState3(true);
144
+ const { user, isAuthChecked, isAuthenticated } = useAuthStore();
168
145
  useEffect3(() => {
169
- if (!user) return;
170
- const hasAccess = allowedRoles.includes(user?.role);
171
- if (!hasAccess) {
146
+ if (!isAuthChecked) return;
147
+ if (!isAuthenticated || !user) {
148
+ router.replace("/login");
149
+ return;
150
+ }
151
+ const role2 = user?.role;
152
+ if (!allowedRoles.includes(role2)) {
172
153
  router.replace(redirectTo);
173
154
  }
174
- setIsChecking(false);
175
- }, [user, allowedRoles, redirectTo, router]);
176
- if (loading || !user || isChecking) return /* @__PURE__ */ jsx3("div", { children: "Loading..." });
155
+ }, [isAuthChecked, isAuthenticated, user, allowedRoles, redirectTo, router]);
156
+ if (!isAuthChecked) return /* @__PURE__ */ jsx3("div", { children: "Loading..." });
157
+ if (!isAuthenticated || !user) return null;
158
+ const role = user?.role;
159
+ if (!allowedRoles.includes(role)) return null;
177
160
  return /* @__PURE__ */ jsx3(Fragment2, { children });
178
161
  };
179
162
  var RoleGuard_default = RoleGuard;
@@ -182,11 +165,8 @@ var RoleGuard_default = RoleGuard;
182
165
  function createAppAuth(storage = "cookie") {
183
166
  return createAuthContext({ storage });
184
167
  }
185
- var { AuthProvider, useAuth } = createAppAuth();
186
168
  export {
187
169
  AuthGuard_default as AuthGuard,
188
- AuthProvider,
189
170
  RoleGuard_default as RoleGuard,
190
- createAppAuth,
191
- useAuth
171
+ createAppAuth
192
172
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextauthz",
3
- "version": "1.1.9",
3
+ "version": "1.2.1",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/src/AuthGuard.tsx CHANGED
@@ -9,57 +9,34 @@ type AuthGuardProps = {
9
9
  children: React.ReactNode
10
10
  redirectTo?: string
11
11
  tokenKey?: string
12
- refreshToken?: () => Promise<string | null>
13
12
  }
14
13
 
15
14
  const AuthGuard = ({
16
15
  children,
17
16
  redirectTo = '/login',
18
17
  tokenKey = 'access_token',
19
- refreshToken,
20
18
  }: AuthGuardProps) => {
21
- const manager = useTokenManager()
22
19
  const router = useRouter()
23
- const isAuthChecked = useAuthStore((state) => state.isAuthChecked)
24
- const isAuthenticated = useAuthStore((state) => state.isAuthenticated)
25
- const error = useAuthStore((state) => state.error)
20
+ const manager = useTokenManager()
21
+ const setAuth = useAuthStore((state) => state.setAuth)
22
+ const setAuthChecked = useAuthStore((state) => state.setAuthChecked)
23
+ const [loading, setLoading] = useState(true)
26
24
 
27
25
  useEffect(() => {
28
- const checkAuth = async () => {
29
- try {
30
- let token = manager.getSingleToken(tokenKey)
26
+ const token = manager.getSingleToken(tokenKey)
27
+ const isValid = Boolean(token) && !manager.isExpired(token as any)
31
28
 
32
- if (!token || manager.isExpired(token)) {
33
- if (refreshToken) {
34
- const newToken = await refreshToken()
35
- if (newToken) {
36
- manager.setTokens({ [tokenKey]: newToken })
37
- token = newToken
38
- }
39
- }
40
- }
29
+ setAuth(Boolean(isValid))
30
+ setAuthChecked(true)
41
31
 
42
- const isValid = token && !manager.isExpired(token)
43
- useAuthStore.getState().setAuth(Boolean(isValid))
44
-
45
- if (!isValid) {
46
- router.replace(redirectTo)
47
- }
48
- } catch (err: any) {
49
- useAuthStore.getState().setError(err instanceof Error ? err : new Error(String(err)))
50
- useAuthStore.getState().setAuth(false)
51
- router.replace(redirectTo)
52
- } finally {
53
- useAuthStore.getState().setAuthChecked(true)
54
- }
32
+ if (!isValid) {
33
+ router.replace(redirectTo)
34
+ } else {
35
+ setLoading(false)
55
36
  }
37
+ }, [manager, tokenKey, redirectTo, router, setAuth, setAuthChecked])
56
38
 
57
- checkAuth()
58
- }, [manager, router, redirectTo, tokenKey, refreshToken])
59
-
60
- if (!isAuthChecked) return <div>Loading...</div>
61
- if (error) return <div>Error: {error.message}</div>
62
- if (!isAuthenticated) return null
39
+ if (loading) return <div>Loading...</div>
63
40
 
64
41
  return <>{children}</>
65
42
  }
@@ -5,96 +5,90 @@ import React, {
5
5
  useContext,
6
6
  ReactNode,
7
7
  useEffect,
8
- useState,
8
+ useRef,
9
9
  } from 'react'
10
10
  import { configureTokenManager, useTokenManager } from 'react-token-manager'
11
- import { useAuthStore } from '../store/useGuardStore'
11
+ import { useAuthStore, User } from '../store/useGuardStore'
12
12
 
13
- export type AuthContextType<UserType> = {
13
+ export type AuthContextType<UserType extends User> = {
14
14
  user: UserType | null
15
- login: (tokens: Record<string, string>, user: UserType) => void
15
+ login: (tokens: Record<string, string>, userData: UserType) => void
16
16
  logout: () => void
17
17
  setUser: (user: UserType) => void
18
18
  loading: boolean
19
19
  error: Error | null
20
20
  }
21
21
 
22
- export type AuthContextOptions = {
22
+ type CreateAuthOptions = {
23
23
  storage?: 'localStorage' | 'sessionStorage' | 'cookie'
24
24
  }
25
25
 
26
- /**
27
- * Factory to create AuthProvider and typed useAuth hook
28
- */
29
- export function createAuthContext<UserType>(options?: AuthContextOptions) {
30
- const AuthContext = createContext<AuthContextType<UserType> | null>(null)
26
+ export function createAuthContext<UserType extends User = User>(
27
+ options: CreateAuthOptions = {}
28
+ ) {
29
+ const { storage = 'cookie' } = options
31
30
 
32
- const AuthProvider = ({ children }: { children: ReactNode }) => {
33
- const storageType = options?.storage || 'cookie'
34
-
35
- // Configure token manager once on mount
36
- useEffect(() => {
37
- configureTokenManager({ storage: storageType })
38
- }, [storageType])
31
+ const AuthContext = createContext<AuthContextType<UserType> | undefined>(
32
+ undefined
33
+ )
39
34
 
40
- // Hooks must be called inside component
35
+ const AuthProvider = ({ children }: { children: ReactNode }) => {
36
+ const configuredRef = useRef(false)
41
37
  const manager = useTokenManager()
42
38
 
43
- const [loading, setLoading] = useState(true)
39
+ const { user, loading, error, setUser, setLoading, setError, resetAuth } =
40
+ useAuthStore()
44
41
 
45
- const rawUser = useAuthStore((state) => state.user)
46
- const error = useAuthStore((state) => state.error)
47
- const user = rawUser as UserType | null
42
+ // Configure token manager once
43
+ useEffect(() => {
44
+ if (!configuredRef.current) {
45
+ configureTokenManager({ storage })
46
+ configuredRef.current = true
47
+ }
48
+ }, [storage])
48
49
 
49
- // Restore saved user from token manager
50
+ // Restore user from token storage
50
51
  useEffect(() => {
51
- const savedUser = manager.getSingleToken('user')
52
- if (savedUser) {
53
- try {
54
- const parsedUser = JSON.parse(savedUser)
55
- useAuthStore.getState().setUser(parsedUser)
56
- useAuthStore.getState().setError(null)
57
- } catch {
58
- useAuthStore.getState().resetAuth()
59
- useAuthStore.getState().setError(
60
- new Error('Failed to parse saved user')
61
- )
52
+ try {
53
+ const savedUser = manager.getSingleToken('user')
54
+ if (savedUser) {
55
+ setUser(JSON.parse(savedUser) as UserType)
62
56
  }
57
+ } catch (err) {
58
+ setError(err instanceof Error ? err : new Error(String(err)))
59
+ } finally {
60
+ setLoading(false)
63
61
  }
64
- setLoading(false)
65
- }, [manager])
66
-
67
- const setUser = (userData: UserType) => {
68
- useAuthStore.getState().setUser(userData as any)
69
- useAuthStore.getState().setError(null)
70
- manager.setTokens({ user: JSON.stringify(userData) })
71
- }
62
+ }, [manager, setUser, setLoading, setError])
72
63
 
73
64
  const login = (tokens: Record<string, string>, userData: UserType) => {
74
65
  try {
75
- manager.setTokens(tokens)
66
+ manager.setTokens({ ...tokens, user: JSON.stringify(userData) })
76
67
  setUser(userData)
77
68
  } catch (err) {
78
- useAuthStore.getState().setError(
79
- err instanceof Error ? err : new Error(String(err))
80
- )
69
+ setError(err instanceof Error ? err : new Error(String(err)))
81
70
  }
82
71
  }
83
72
 
84
73
  const logout = () => {
85
74
  try {
86
75
  manager.clearTokens()
87
- useAuthStore.getState().resetAuth()
76
+ resetAuth()
88
77
  } catch (err) {
89
- useAuthStore.getState().setError(
90
- err instanceof Error ? err : new Error(String(err))
91
- )
78
+ setError(err instanceof Error ? err : new Error(String(err)))
92
79
  }
93
80
  }
94
81
 
95
82
  return (
96
83
  <AuthContext.Provider
97
- value={{ user, login, logout, setUser, loading, error }}
84
+ value={{
85
+ user: user as UserType | null,
86
+ login,
87
+ logout,
88
+ setUser: (u: UserType) => setUser(u),
89
+ loading,
90
+ error,
91
+ }}
98
92
  >
99
93
  {children}
100
94
  </AuthContext.Provider>
package/src/RoleGuard.tsx CHANGED
@@ -1,8 +1,8 @@
1
1
  'use client'
2
2
 
3
- import React, { useEffect, useState } from 'react'
3
+ import React, { useEffect } from 'react'
4
4
  import { useRouter } from 'next/navigation'
5
- import { useAuth } from '.'
5
+ import { useAuthStore } from '../store/useGuardStore'
6
6
 
7
7
  type RoleGuardProps = {
8
8
  children: React.ReactNode
@@ -15,21 +15,37 @@ const RoleGuard = ({
15
15
  allowedRoles,
16
16
  redirectTo = '/unauthorized',
17
17
  }: RoleGuardProps) => {
18
- const { user, loading } = useAuth()
19
18
  const router = useRouter()
20
- const [isChecking, setIsChecking] = useState(true)
19
+
20
+ // Get auth state from Zustand
21
+ const { user, isAuthChecked, isAuthenticated } = useAuthStore()
21
22
 
22
23
  useEffect(() => {
23
- if (!user) return
24
+ // Wait until auth is checked
25
+ if (!isAuthChecked) return
26
+
27
+ // Not authenticated
28
+ if (!isAuthenticated || !user) {
29
+ router.replace('/login')
30
+ return
31
+ }
24
32
 
25
- const hasAccess = allowedRoles.includes(user?.role)
26
- if (!hasAccess) {
33
+ // Role check
34
+ const role = user?.role
35
+ if (!allowedRoles.includes(role)) {
27
36
  router.replace(redirectTo)
28
37
  }
29
- setIsChecking(false)
30
- }, [user, allowedRoles, redirectTo, router])
38
+ }, [isAuthChecked, isAuthenticated, user, allowedRoles, redirectTo, router])
39
+
40
+ // Show loading until auth is checked
41
+ if (!isAuthChecked) return <div>Loading...</div>
42
+
43
+ // Not authenticated
44
+ if (!isAuthenticated || !user) return null
31
45
 
32
- if (loading || !user || isChecking) return <div>Loading...</div>
46
+ // Role not allowed
47
+ const role = (user as any)?.role
48
+ if (!allowedRoles.includes(role)) return null
33
49
 
34
50
  return <>{children}</>
35
51
  }
package/src/index.ts CHANGED
@@ -1,18 +1,14 @@
1
- // src/index.ts
2
1
  'use client'
3
2
 
4
3
  import { createAuthContext } from './AuthProvider'
4
+
5
5
  export { default as AuthGuard } from './AuthGuard'
6
6
  export { default as RoleGuard } from './RoleGuard'
7
7
 
8
8
  export type User = any
9
9
 
10
- // Factory function for app
11
10
  export function createAppAuth(
12
11
  storage: 'localStorage' | 'sessionStorage' | 'cookie' = 'cookie'
13
12
  ) {
14
- return createAuthContext<User>({ storage })
13
+ return createAuthContext({ storage })
15
14
  }
16
-
17
- // Default instance (optional)
18
- export const { AuthProvider, useAuth } = createAppAuth()
@@ -7,13 +7,15 @@ export type User = {
7
7
  }
8
8
 
9
9
  type AuthState = {
10
- user: User | null // user can be null
10
+ user: User | null // user can be null
11
11
  isAuthenticated: boolean
12
12
  isAuthChecked: boolean
13
+ loading: boolean // new loading state
13
14
  error: Error | null
14
15
  setUser: (user: User | null) => void
15
16
  setAuth: (isAuth: boolean) => void
16
17
  setAuthChecked: (checked: boolean) => void
18
+ setLoading: (loading: boolean) => void
17
19
  setError: (err: Error | null) => void
18
20
  resetAuth: () => void
19
21
  }
@@ -22,11 +24,13 @@ export const useAuthStore = create<AuthState>((set) => ({
22
24
  user: null,
23
25
  isAuthenticated: false,
24
26
  isAuthChecked: false,
27
+ loading: true, // start as loading
25
28
  error: null,
26
29
 
27
30
  setUser: (user) => set({ user }),
28
31
  setAuth: (isAuth) => set({ isAuthenticated: isAuth }),
29
32
  setAuthChecked: (checked) => set({ isAuthChecked: checked }),
33
+ setLoading: (loading) => set({ loading }),
30
34
  setError: (err) => set({ error: err }),
31
35
 
32
36
  resetAuth: () =>
@@ -34,6 +38,7 @@ export const useAuthStore = create<AuthState>((set) => ({
34
38
  user: null,
35
39
  isAuthenticated: false,
36
40
  isAuthChecked: false,
41
+ loading: false,
37
42
  error: null,
38
43
  }),
39
44
  }))