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