nextauthz 1.3.34 → 1.3.37

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
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import React, { ReactNode } from 'react';
2
+ import { ReactNode } from 'react';
3
3
 
4
4
  type User = {
5
5
  [key: string]: any;
@@ -10,7 +10,7 @@ type AuthContextType<UserType extends User = User> = {
10
10
  role: string | null;
11
11
  isAuthenticated: boolean;
12
12
  isAuthChecked: boolean;
13
- login: (tokens: Record<string, string>, userData?: UserType, role?: string) => void;
13
+ login: (tokens: Record<string, string>, userData?: UserType) => void;
14
14
  logout: () => void;
15
15
  setUser: (user: UserType | null) => void;
16
16
  tokenKey: string;
@@ -24,22 +24,19 @@ declare function createAuthContext<UserType extends User = User>(option?: {
24
24
  children: ReactNode;
25
25
  }) => react_jsx_runtime.JSX.Element;
26
26
  useAuth: () => AuthContextType<UserType>;
27
- tokenKey: string;
28
27
  };
29
28
 
30
- type AuthGuardProps = {
29
+ declare const AuthGuard: ({ children, redirectTo, fallback, }: {
31
30
  children: React.ReactNode;
32
31
  redirectTo?: string;
33
32
  fallback?: React.ReactNode;
34
- };
35
- declare const AuthGuard: ({ children, redirectTo, fallback, }: AuthGuardProps) => react_jsx_runtime.JSX.Element | null;
33
+ }) => react_jsx_runtime.JSX.Element | null;
36
34
 
37
- type RoleGuardProps = {
35
+ declare const RoleGuard: ({ children, allowedRoles, redirectTo, fallback, }: {
38
36
  children: React.ReactNode;
39
37
  allowedRoles: string[];
40
38
  redirectTo?: string;
41
39
  fallback?: React.ReactNode;
42
- };
43
- declare const RoleGuard: ({ children, allowedRoles, redirectTo, fallback, }: RoleGuardProps) => react_jsx_runtime.JSX.Element | null;
40
+ }) => react_jsx_runtime.JSX.Element | null;
44
41
 
45
42
  export { AuthGuard, RoleGuard, createAuthContext };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import React, { ReactNode } from 'react';
2
+ import { ReactNode } from 'react';
3
3
 
4
4
  type User = {
5
5
  [key: string]: any;
@@ -10,7 +10,7 @@ type AuthContextType<UserType extends User = User> = {
10
10
  role: string | null;
11
11
  isAuthenticated: boolean;
12
12
  isAuthChecked: boolean;
13
- login: (tokens: Record<string, string>, userData?: UserType, role?: string) => void;
13
+ login: (tokens: Record<string, string>, userData?: UserType) => void;
14
14
  logout: () => void;
15
15
  setUser: (user: UserType | null) => void;
16
16
  tokenKey: string;
@@ -24,22 +24,19 @@ declare function createAuthContext<UserType extends User = User>(option?: {
24
24
  children: ReactNode;
25
25
  }) => react_jsx_runtime.JSX.Element;
26
26
  useAuth: () => AuthContextType<UserType>;
27
- tokenKey: string;
28
27
  };
29
28
 
30
- type AuthGuardProps = {
29
+ declare const AuthGuard: ({ children, redirectTo, fallback, }: {
31
30
  children: React.ReactNode;
32
31
  redirectTo?: string;
33
32
  fallback?: React.ReactNode;
34
- };
35
- declare const AuthGuard: ({ children, redirectTo, fallback, }: AuthGuardProps) => react_jsx_runtime.JSX.Element | null;
33
+ }) => react_jsx_runtime.JSX.Element | null;
36
34
 
37
- type RoleGuardProps = {
35
+ declare const RoleGuard: ({ children, allowedRoles, redirectTo, fallback, }: {
38
36
  children: React.ReactNode;
39
37
  allowedRoles: string[];
40
38
  redirectTo?: string;
41
39
  fallback?: React.ReactNode;
42
- };
43
- declare const RoleGuard: ({ children, allowedRoles, redirectTo, fallback, }: RoleGuardProps) => react_jsx_runtime.JSX.Element | null;
40
+ }) => react_jsx_runtime.JSX.Element | null;
44
41
 
45
42
  export { AuthGuard, RoleGuard, createAuthContext };
package/dist/index.js CHANGED
@@ -60,92 +60,95 @@ var useAuthStore = (0, import_zustand.create)((set) => ({
60
60
  // src/AuthProvider.tsx
61
61
  var import_jsx_runtime = require("react/jsx-runtime");
62
62
  function createAuthContext(option) {
63
- const AuthContext = (0, import_react.createContext)(void 0);
63
+ const AuthContext = (0, import_react.createContext)(
64
+ void 0
65
+ );
64
66
  const AuthProvider = ({ children }) => {
65
67
  const storage = option?.storage ?? "cookie";
66
68
  const tokenKey = option?.tokenKey ?? "access_token";
67
69
  const rolePath = option?.rolePath ?? "role";
70
+ const manager = (0, import_react_token_manager.useTokenManager)();
71
+ const user = useAuthStore((s) => s.user);
72
+ const role = useAuthStore((s) => s.role);
73
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
74
+ const isAuthChecked = useAuthStore((s) => s.isAuthChecked);
75
+ const setUser = useAuthStore((s) => s.setUser);
76
+ const setRole = useAuthStore((s) => s.setRole);
77
+ const setAuth = useAuthStore((s) => s.setAuth);
78
+ const setAuthChecked = useAuthStore((s) => s.setAuthChecked);
79
+ const resetAuth = useAuthStore((s) => s.resetAuth);
68
80
  (0, import_react.useEffect)(() => {
69
81
  (0, import_react_token_manager.configureTokenManager)({ storage });
70
82
  }, [storage]);
71
- const manager = (0, import_react_token_manager.useTokenManager)();
72
- const {
73
- user,
74
- role,
75
- setUser,
76
- setRole,
77
- resetAuth,
78
- isAuthChecked,
79
- isAuthenticated,
80
- setAuth,
81
- setAuthChecked
82
- } = useAuthStore();
83
- const extractRole = (userObj) => {
84
- if (!userObj || !rolePath) return null;
85
- return rolePath.split(".").reduce((acc, key) => acc?.[key], userObj) ?? null;
86
- };
83
+ const extractRole = (0, import_react.useCallback)(
84
+ (userObj) => {
85
+ if (!userObj) return null;
86
+ return rolePath.split(".").reduce((acc, key) => acc?.[key], userObj) ?? null;
87
+ },
88
+ [rolePath]
89
+ );
87
90
  (0, import_react.useEffect)(() => {
88
- const storedUser = manager.getSingleToken("user");
89
91
  const token = manager.getSingleToken(tokenKey);
90
92
  if (token && !manager.isExpired(token)) {
91
- try {
92
- setAuth(true);
93
- if (storedUser) {
94
- const parsedUser = JSON.parse(storedUser);
95
- setUser(parsedUser);
96
- setRole(extractRole(parsedUser));
93
+ setAuth(true);
94
+ if (user) {
95
+ try {
96
+ setUser(user);
97
+ setRole(extractRole(user));
98
+ } catch {
99
+ resetAuth();
97
100
  }
98
- } catch {
99
- resetAuth();
100
101
  }
101
102
  } else {
102
103
  resetAuth();
103
104
  }
104
105
  setAuthChecked(true);
105
- }, [tokenKey]);
106
- const login = (tokens, userData, role2) => {
107
- const tokenValue = tokens[tokenKey] ?? tokens["access_token"] ?? Object.values(tokens)[0];
108
- manager.setTokens({
109
- ...tokens,
110
- [tokenKey]: tokenValue,
111
- user: JSON.stringify(userData ?? null)
112
- });
113
- if (userData) setUser(userData);
114
- setRole(role2 ?? extractRole(userData));
115
- setAuth(true);
116
- setAuthChecked(true);
117
- };
118
- const logout = () => {
106
+ }, [tokenKey, manager, user, setAuth, setAuthChecked, setUser, setRole, resetAuth, extractRole]);
107
+ const login = (0, import_react.useCallback)(
108
+ (tokens, userData) => {
109
+ const tokenValue = tokens[tokenKey] ?? tokens["access_token"] ?? Object.values(tokens)[0];
110
+ manager.setTokens({
111
+ ...tokens,
112
+ [tokenKey]: tokenValue,
113
+ user: JSON.stringify(userData ?? null)
114
+ });
115
+ if (userData) {
116
+ setUser(userData);
117
+ setRole(extractRole(userData));
118
+ }
119
+ setAuth(true);
120
+ setAuthChecked(true);
121
+ },
122
+ [tokenKey, manager, setUser, setRole, extractRole, setAuth, setAuthChecked]
123
+ );
124
+ const logout = (0, import_react.useCallback)(() => {
119
125
  manager.clearTokens();
120
126
  resetAuth();
121
- };
122
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
123
- AuthContext.Provider,
124
- {
125
- value: {
126
- user,
127
- role,
128
- isAuthenticated,
129
- isAuthChecked,
130
- login,
131
- logout,
132
- setUser: (u) => setUser(u),
133
- tokenKey
127
+ }, [manager, resetAuth]);
128
+ const value = (0, import_react.useMemo)(
129
+ () => ({
130
+ user,
131
+ role,
132
+ isAuthenticated,
133
+ isAuthChecked,
134
+ login,
135
+ logout,
136
+ setUser: (u) => {
137
+ setUser(u);
138
+ setRole(extractRole(u));
134
139
  },
135
- children
136
- }
140
+ tokenKey
141
+ }),
142
+ [user, role, isAuthenticated, isAuthChecked, login, logout, setUser, tokenKey, extractRole]
137
143
  );
144
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthContext.Provider, { value, children });
138
145
  };
139
146
  const useAuth = () => {
140
147
  const context = (0, import_react.useContext)(AuthContext);
141
148
  if (!context) throw new Error("useAuth must be used within AuthProvider");
142
149
  return context;
143
150
  };
144
- return {
145
- AuthProvider,
146
- useAuth,
147
- tokenKey: option?.tokenKey ?? "access_token"
148
- };
151
+ return { AuthProvider, useAuth };
149
152
  }
150
153
 
151
154
  // src/AuthGuard.tsx
@@ -158,18 +161,16 @@ var AuthGuard = ({
158
161
  fallback = null
159
162
  }) => {
160
163
  const router = (0, import_navigation.useRouter)();
161
- const { isAuthenticated, isAuthChecked } = useAuthStore();
164
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
165
+ const isAuthChecked = useAuthStore((s) => s.isAuthChecked);
162
166
  (0, import_react2.useEffect)(() => {
163
167
  if (!isAuthChecked) return;
164
168
  if (!isAuthenticated) {
165
169
  router.replace(redirectTo);
166
170
  }
167
- }, [isAuthenticated, isAuthChecked, redirectTo, router]);
171
+ }, [isAuthenticated, isAuthChecked]);
168
172
  if (!isAuthChecked) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: fallback });
169
- if (!isAuthenticated) {
170
- router.replace(redirectTo);
171
- return null;
172
- }
173
+ if (!isAuthenticated) return null;
173
174
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
174
175
  };
175
176
  var AuthGuard_default = AuthGuard;
@@ -185,19 +186,19 @@ var RoleGuard = ({
185
186
  fallback = null
186
187
  }) => {
187
188
  const router = (0, import_navigation2.useRouter)();
188
- const { role, isAuthChecked, isAuthenticated } = useAuthStore();
189
+ const role = useAuthStore((s) => s.role);
190
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
191
+ const isAuthChecked = useAuthStore((s) => s.isAuthChecked);
189
192
  (0, import_react3.useEffect)(() => {
190
- if (!isAuthChecked) return;
193
+ if (!isAuthChecked || !isAuthenticated) return;
191
194
  if (!role || !allowedRoles.includes(role)) {
192
195
  router.replace(redirectTo);
193
196
  }
194
- }, [role, isAuthChecked, allowedRoles, redirectTo, router]);
197
+ }, [role, isAuthenticated, isAuthChecked]);
195
198
  if (!isAuthChecked) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: fallback });
196
- if (!isAuthenticated) {
197
- router.replace(redirectTo);
198
- return null;
199
- }
199
+ if (!isAuthenticated) return null;
200
200
  if (!role || !allowedRoles.includes(role)) return null;
201
+ console.log(role);
201
202
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
202
203
  };
203
204
  var RoleGuard_default = RoleGuard;
package/dist/index.mjs CHANGED
@@ -1,7 +1,13 @@
1
1
  "use client";
2
2
 
3
3
  // src/AuthProvider.tsx
4
- import { createContext, useContext, useEffect } from "react";
4
+ import {
5
+ createContext,
6
+ useContext,
7
+ useEffect,
8
+ useMemo,
9
+ useCallback
10
+ } from "react";
5
11
  import { configureTokenManager, useTokenManager } from "react-token-manager";
6
12
 
7
13
  // store/useGuardStore.ts
@@ -33,92 +39,95 @@ var useAuthStore = create((set) => ({
33
39
  // src/AuthProvider.tsx
34
40
  import { jsx } from "react/jsx-runtime";
35
41
  function createAuthContext(option) {
36
- const AuthContext = createContext(void 0);
42
+ const AuthContext = createContext(
43
+ void 0
44
+ );
37
45
  const AuthProvider = ({ children }) => {
38
46
  const storage = option?.storage ?? "cookie";
39
47
  const tokenKey = option?.tokenKey ?? "access_token";
40
48
  const rolePath = option?.rolePath ?? "role";
49
+ const manager = useTokenManager();
50
+ const user = useAuthStore((s) => s.user);
51
+ const role = useAuthStore((s) => s.role);
52
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
53
+ const isAuthChecked = useAuthStore((s) => s.isAuthChecked);
54
+ const setUser = useAuthStore((s) => s.setUser);
55
+ const setRole = useAuthStore((s) => s.setRole);
56
+ const setAuth = useAuthStore((s) => s.setAuth);
57
+ const setAuthChecked = useAuthStore((s) => s.setAuthChecked);
58
+ const resetAuth = useAuthStore((s) => s.resetAuth);
41
59
  useEffect(() => {
42
60
  configureTokenManager({ storage });
43
61
  }, [storage]);
44
- const manager = useTokenManager();
45
- const {
46
- user,
47
- role,
48
- setUser,
49
- setRole,
50
- resetAuth,
51
- isAuthChecked,
52
- isAuthenticated,
53
- setAuth,
54
- setAuthChecked
55
- } = useAuthStore();
56
- const extractRole = (userObj) => {
57
- if (!userObj || !rolePath) return null;
58
- return rolePath.split(".").reduce((acc, key) => acc?.[key], userObj) ?? null;
59
- };
62
+ const extractRole = useCallback(
63
+ (userObj) => {
64
+ if (!userObj) return null;
65
+ return rolePath.split(".").reduce((acc, key) => acc?.[key], userObj) ?? null;
66
+ },
67
+ [rolePath]
68
+ );
60
69
  useEffect(() => {
61
- const storedUser = manager.getSingleToken("user");
62
70
  const token = manager.getSingleToken(tokenKey);
63
71
  if (token && !manager.isExpired(token)) {
64
- try {
65
- setAuth(true);
66
- if (storedUser) {
67
- const parsedUser = JSON.parse(storedUser);
68
- setUser(parsedUser);
69
- setRole(extractRole(parsedUser));
72
+ setAuth(true);
73
+ if (user) {
74
+ try {
75
+ setUser(user);
76
+ setRole(extractRole(user));
77
+ } catch {
78
+ resetAuth();
70
79
  }
71
- } catch {
72
- resetAuth();
73
80
  }
74
81
  } else {
75
82
  resetAuth();
76
83
  }
77
84
  setAuthChecked(true);
78
- }, [tokenKey]);
79
- const login = (tokens, userData, role2) => {
80
- const tokenValue = tokens[tokenKey] ?? tokens["access_token"] ?? Object.values(tokens)[0];
81
- manager.setTokens({
82
- ...tokens,
83
- [tokenKey]: tokenValue,
84
- user: JSON.stringify(userData ?? null)
85
- });
86
- if (userData) setUser(userData);
87
- setRole(role2 ?? extractRole(userData));
88
- setAuth(true);
89
- setAuthChecked(true);
90
- };
91
- const logout = () => {
85
+ }, [tokenKey, manager, user, setAuth, setAuthChecked, setUser, setRole, resetAuth, extractRole]);
86
+ const login = useCallback(
87
+ (tokens, userData) => {
88
+ const tokenValue = tokens[tokenKey] ?? tokens["access_token"] ?? Object.values(tokens)[0];
89
+ manager.setTokens({
90
+ ...tokens,
91
+ [tokenKey]: tokenValue,
92
+ user: JSON.stringify(userData ?? null)
93
+ });
94
+ if (userData) {
95
+ setUser(userData);
96
+ setRole(extractRole(userData));
97
+ }
98
+ setAuth(true);
99
+ setAuthChecked(true);
100
+ },
101
+ [tokenKey, manager, setUser, setRole, extractRole, setAuth, setAuthChecked]
102
+ );
103
+ const logout = useCallback(() => {
92
104
  manager.clearTokens();
93
105
  resetAuth();
94
- };
95
- return /* @__PURE__ */ jsx(
96
- AuthContext.Provider,
97
- {
98
- value: {
99
- user,
100
- role,
101
- isAuthenticated,
102
- isAuthChecked,
103
- login,
104
- logout,
105
- setUser: (u) => setUser(u),
106
- tokenKey
106
+ }, [manager, resetAuth]);
107
+ const value = useMemo(
108
+ () => ({
109
+ user,
110
+ role,
111
+ isAuthenticated,
112
+ isAuthChecked,
113
+ login,
114
+ logout,
115
+ setUser: (u) => {
116
+ setUser(u);
117
+ setRole(extractRole(u));
107
118
  },
108
- children
109
- }
119
+ tokenKey
120
+ }),
121
+ [user, role, isAuthenticated, isAuthChecked, login, logout, setUser, tokenKey, extractRole]
110
122
  );
123
+ return /* @__PURE__ */ jsx(AuthContext.Provider, { value, children });
111
124
  };
112
125
  const useAuth = () => {
113
126
  const context = useContext(AuthContext);
114
127
  if (!context) throw new Error("useAuth must be used within AuthProvider");
115
128
  return context;
116
129
  };
117
- return {
118
- AuthProvider,
119
- useAuth,
120
- tokenKey: option?.tokenKey ?? "access_token"
121
- };
130
+ return { AuthProvider, useAuth };
122
131
  }
123
132
 
124
133
  // src/AuthGuard.tsx
@@ -131,18 +140,16 @@ var AuthGuard = ({
131
140
  fallback = null
132
141
  }) => {
133
142
  const router = useRouter();
134
- const { isAuthenticated, isAuthChecked } = useAuthStore();
143
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
144
+ const isAuthChecked = useAuthStore((s) => s.isAuthChecked);
135
145
  useEffect2(() => {
136
146
  if (!isAuthChecked) return;
137
147
  if (!isAuthenticated) {
138
148
  router.replace(redirectTo);
139
149
  }
140
- }, [isAuthenticated, isAuthChecked, redirectTo, router]);
150
+ }, [isAuthenticated, isAuthChecked]);
141
151
  if (!isAuthChecked) return /* @__PURE__ */ jsx2(Fragment, { children: fallback });
142
- if (!isAuthenticated) {
143
- router.replace(redirectTo);
144
- return null;
145
- }
152
+ if (!isAuthenticated) return null;
146
153
  return /* @__PURE__ */ jsx2(Fragment, { children });
147
154
  };
148
155
  var AuthGuard_default = AuthGuard;
@@ -158,19 +165,19 @@ var RoleGuard = ({
158
165
  fallback = null
159
166
  }) => {
160
167
  const router = useRouter2();
161
- const { role, isAuthChecked, isAuthenticated } = useAuthStore();
168
+ const role = useAuthStore((s) => s.role);
169
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
170
+ const isAuthChecked = useAuthStore((s) => s.isAuthChecked);
162
171
  useEffect3(() => {
163
- if (!isAuthChecked) return;
172
+ if (!isAuthChecked || !isAuthenticated) return;
164
173
  if (!role || !allowedRoles.includes(role)) {
165
174
  router.replace(redirectTo);
166
175
  }
167
- }, [role, isAuthChecked, allowedRoles, redirectTo, router]);
176
+ }, [role, isAuthenticated, isAuthChecked]);
168
177
  if (!isAuthChecked) return /* @__PURE__ */ jsx3(Fragment2, { children: fallback });
169
- if (!isAuthenticated) {
170
- router.replace(redirectTo);
171
- return null;
172
- }
178
+ if (!isAuthenticated) return null;
173
179
  if (!role || !allowedRoles.includes(role)) return null;
180
+ console.log(role);
174
181
  return /* @__PURE__ */ jsx3(Fragment2, { children });
175
182
  };
176
183
  var RoleGuard_default = RoleGuard;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextauthz",
3
- "version": "1.3.34",
3
+ "version": "1.3.37",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/readme.md CHANGED
@@ -153,7 +153,7 @@ Props
153
153
  ## Usage Example
154
154
 
155
155
  ```bash
156
- import AuthGuard from 'nextauthz'
156
+ import { AuthGuard } from 'nextauthz'
157
157
 
158
158
  function DashboardPage() {
159
159
  return (
package/src/AuthGuard.tsx CHANGED
@@ -1,41 +1,34 @@
1
1
  'use client'
2
2
 
3
- import React, { useEffect } from 'react'
3
+ import { useEffect } from 'react'
4
4
  import { useRouter } from 'next/navigation'
5
5
  import { useAuthStore } from '../store/useGuardStore'
6
6
 
7
- type AuthGuardProps = {
8
- children: React.ReactNode
9
- redirectTo?: string
10
- fallback?: React.ReactNode
11
- }
12
-
13
7
  const AuthGuard = ({
14
8
  children,
15
9
  redirectTo = '/login',
16
10
  fallback = null,
17
- }: AuthGuardProps) => {
11
+ }: {
12
+ children: React.ReactNode
13
+ redirectTo?: string
14
+ fallback?: React.ReactNode
15
+ }) => {
18
16
  const router = useRouter()
19
17
 
20
- const { isAuthenticated, isAuthChecked } = useAuthStore()
18
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated)
19
+ const isAuthChecked = useAuthStore((s) => s.isAuthChecked)
21
20
 
22
21
  useEffect(() => {
23
22
  if (!isAuthChecked) return
24
-
25
23
  if (!isAuthenticated) {
26
24
  router.replace(redirectTo)
27
25
  }
28
- }, [isAuthenticated, isAuthChecked, redirectTo, router])
26
+ }, [isAuthenticated, isAuthChecked])
29
27
 
30
28
  if (!isAuthChecked) return <>{fallback}</>
31
-
32
- if (!isAuthenticated) {
33
- router.replace(redirectTo)
34
- return null
35
- }
36
-
29
+ if (!isAuthenticated) return null
37
30
 
38
31
  return <>{children}</>
39
32
  }
40
33
 
41
- export default AuthGuard
34
+ export default AuthGuard
@@ -1,143 +1,138 @@
1
1
  'use client'
2
2
 
3
- import { createContext, useContext, ReactNode, useEffect } from 'react'
3
+ import {
4
+ createContext,
5
+ useContext,
6
+ ReactNode,
7
+ useEffect,
8
+ useMemo,
9
+ useCallback,
10
+ } from 'react'
4
11
  import { configureTokenManager, useTokenManager } from 'react-token-manager'
5
12
  import { useAuthStore, User } from '../store/useGuardStore'
6
13
 
7
- /* ---------------------------------- */
8
- /* Types */
9
- /* ---------------------------------- */
10
-
11
14
  export type AuthContextType<UserType extends User = User> = {
12
15
  user: UserType | null
13
16
  role: string | null
14
17
  isAuthenticated: boolean
15
18
  isAuthChecked: boolean
16
- login: (tokens: Record<string, string>, userData?: UserType, role?: string) => void
19
+ login: (tokens: Record<string, string>, userData?: UserType) => void
17
20
  logout: () => void
18
21
  setUser: (user: UserType | null) => void
19
22
  tokenKey: string
20
23
  }
21
24
 
22
- /* ---------------------------------- */
23
- /* Factory */
24
- /* ---------------------------------- */
25
-
26
25
  export function createAuthContext<UserType extends User = User>(option?: {
27
26
  storage?: 'localStorage' | 'sessionStorage' | 'cookie'
28
27
  tokenKey?: string
29
- rolePath?: string // e.g. 'role' or 'profile.role'
28
+ rolePath?: string
30
29
  }) {
31
- const AuthContext = createContext<AuthContextType<UserType> | undefined>(undefined)
30
+ const AuthContext = createContext<AuthContextType<UserType> | undefined>(
31
+ undefined
32
+ )
32
33
 
33
34
  const AuthProvider = ({ children }: { children: ReactNode }) => {
34
35
  const storage = option?.storage ?? 'cookie'
35
36
  const tokenKey = option?.tokenKey ?? 'access_token'
36
37
  const rolePath = option?.rolePath ?? 'role'
37
38
 
39
+ const manager = useTokenManager()
40
+
41
+ // ✅ Selectors
42
+ const user = useAuthStore((s) => s.user)
43
+ const role = useAuthStore((s) => s.role)
44
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated)
45
+ const isAuthChecked = useAuthStore((s) => s.isAuthChecked)
46
+
47
+ const setUser = useAuthStore((s) => s.setUser)
48
+ const setRole = useAuthStore((s) => s.setRole)
49
+ const setAuth = useAuthStore((s) => s.setAuth)
50
+ const setAuthChecked = useAuthStore((s) => s.setAuthChecked)
51
+ const resetAuth = useAuthStore((s) => s.resetAuth)
52
+
38
53
  useEffect(() => {
39
54
  configureTokenManager({ storage })
40
55
  }, [storage])
41
56
 
42
- const manager = useTokenManager()
43
- const {
44
- user,
45
- role,
46
- setUser,
47
- setRole,
48
- resetAuth,
49
- isAuthChecked,
50
- isAuthenticated,
51
- setAuth,
52
- setAuthChecked,
53
- } = useAuthStore()
54
-
55
- /* ---------------------------------- */
56
- /* Helper: get role from path */
57
- /* ---------------------------------- */
58
- const extractRole = (userObj: any) => {
59
- if (!userObj || !rolePath) return null
60
- return rolePath.split('.').reduce((acc: any, key: string) => acc?.[key], userObj) ?? null
61
- }
62
-
63
-
64
- /* ---------------------------------- */
65
- /* Hydrate user from storage */
66
- /* ---------------------------------- */
57
+ // Extract role from user
58
+ const extractRole = useCallback(
59
+ (userObj: any) => {
60
+ if (!userObj) return null
61
+ return rolePath.split('.').reduce((acc: any, key: string) => acc?.[key], userObj) ?? null
62
+ },
63
+ [rolePath]
64
+ )
67
65
 
66
+ // ✅ Hydrate once
68
67
  useEffect(() => {
69
- const storedUser = manager.getSingleToken('user')
70
68
  const token = manager.getSingleToken(tokenKey)
71
69
 
72
70
  if (token && !manager.isExpired(token)) {
73
- try {
74
- setAuth(true)
75
-
76
- if (storedUser) {
77
- const parsedUser = JSON.parse(storedUser) as UserType
78
- setUser(parsedUser)
79
- setRole(extractRole(parsedUser))
71
+ setAuth(true)
72
+
73
+ if (user) {
74
+ try {
75
+ setUser(user) // ensure user is set in store
76
+ setRole(extractRole(user)) // set role automatically
77
+ } catch {
78
+ resetAuth()
80
79
  }
81
- } catch {
82
- resetAuth()
83
80
  }
84
81
  } else {
85
82
  resetAuth()
86
83
  }
87
84
 
88
85
  setAuthChecked(true)
89
- // eslint-disable-next-line react-hooks/exhaustive-deps
90
- }, [tokenKey])
91
-
92
- /* ---------------------------------- */
93
- /* Login */
94
- /* ---------------------------------- */
95
-
96
- const login = (tokens: Record<string, string>, userData?: UserType, role?: string) => {
97
- const tokenValue = tokens[tokenKey] ?? tokens['access_token'] ?? Object.values(tokens)[0]
98
-
99
- manager.setTokens({
100
- ...tokens,
101
- [tokenKey]: tokenValue,
102
- user: JSON.stringify(userData ?? null),
103
- })
104
-
105
- if (userData) setUser(userData)
106
- setRole(role ?? extractRole(userData))
107
- setAuth(true)
108
- setAuthChecked(true)
109
- }
86
+ }, [tokenKey, manager, user, setAuth, setAuthChecked, setUser, setRole, resetAuth, extractRole])
87
+
88
+ // ✅ Login function
89
+ const login = useCallback(
90
+ (tokens: Record<string, string>, userData?: UserType) => {
91
+ const tokenValue =
92
+ tokens[tokenKey] ?? tokens['access_token'] ?? Object.values(tokens)[0]
93
+
94
+ manager.setTokens({
95
+ ...tokens,
96
+ [tokenKey]: tokenValue,
97
+ user: JSON.stringify(userData ?? null),
98
+ })
99
+
100
+ if (userData) {
101
+ setUser(userData)
102
+ setRole(extractRole(userData)) // set role whenever user is logged in
103
+ }
110
104
 
111
- /* ---------------------------------- */
112
- /* Logout */
113
- /* ---------------------------------- */
105
+ setAuth(true)
106
+ setAuthChecked(true)
107
+ },
108
+ [tokenKey, manager, setUser, setRole, extractRole, setAuth, setAuthChecked]
109
+ )
114
110
 
115
- const logout = () => {
111
+ const logout = useCallback(() => {
116
112
  manager.clearTokens()
117
113
  resetAuth()
118
- }
119
-
120
- return (
121
- <AuthContext.Provider
122
- value={{
123
- user: user as UserType | null,
124
- role,
125
- isAuthenticated,
126
- isAuthChecked,
127
- login,
128
- logout,
129
- setUser: (u) => setUser(u),
130
- tokenKey,
131
- }}
132
- >
133
- {children}
134
- </AuthContext.Provider>
114
+ }, [manager, resetAuth])
115
+
116
+ // ✅ MEMOIZED CONTEXT VALUE
117
+ const value = useMemo(
118
+ () => ({
119
+ user: user as UserType | null,
120
+ role,
121
+ isAuthenticated,
122
+ isAuthChecked,
123
+ login,
124
+ logout,
125
+ setUser: (u: UserType | null) => {
126
+ setUser(u)
127
+ setRole(extractRole(u))
128
+ },
129
+ tokenKey,
130
+ }),
131
+ [user, role, isAuthenticated, isAuthChecked, login, logout, setUser, tokenKey, extractRole]
135
132
  )
136
- }
137
133
 
138
- /* ---------------------------------- */
139
- /* Hook */
140
- /* ---------------------------------- */
134
+ return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
135
+ }
141
136
 
142
137
  const useAuth = () => {
143
138
  const context = useContext(AuthContext)
@@ -145,9 +140,5 @@ export function createAuthContext<UserType extends User = User>(option?: {
145
140
  return context
146
141
  }
147
142
 
148
- return {
149
- AuthProvider,
150
- useAuth,
151
- tokenKey: option?.tokenKey ?? 'access_token',
152
- }
153
- }
143
+ return { AuthProvider, useAuth }
144
+ }
package/src/RoleGuard.tsx CHANGED
@@ -1,45 +1,42 @@
1
1
  'use client'
2
2
 
3
- import React, { useEffect } from 'react'
3
+ import { useEffect } from 'react'
4
4
  import { useRouter } from 'next/navigation'
5
5
  import { useAuthStore } from '../store/useGuardStore'
6
6
 
7
- type RoleGuardProps = {
8
- children: React.ReactNode
9
- allowedRoles: string[]
10
- redirectTo?: string
11
- fallback?: React.ReactNode
12
- }
13
-
14
7
  const RoleGuard = ({
15
8
  children,
16
9
  allowedRoles,
17
10
  redirectTo = '/unauthorized',
18
11
  fallback = null,
19
- }: RoleGuardProps) => {
12
+ }: {
13
+ children: React.ReactNode
14
+ allowedRoles: string[]
15
+ redirectTo?: string
16
+ fallback?: React.ReactNode
17
+ }) => {
20
18
  const router = useRouter()
21
- const { role, isAuthChecked, isAuthenticated } = useAuthStore()
19
+
20
+ const role = useAuthStore((s) => s.role)
21
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated)
22
+ const isAuthChecked = useAuthStore((s) => s.isAuthChecked)
22
23
 
23
24
  useEffect(() => {
24
- if (!isAuthChecked) return
25
+ if (!isAuthChecked || !isAuthenticated) return
25
26
 
26
- // If role not allowed, redirect
27
27
  if (!role || !allowedRoles.includes(role)) {
28
28
  router.replace(redirectTo)
29
29
  }
30
- }, [role, isAuthChecked, allowedRoles, redirectTo, router])
30
+ }, [role, isAuthenticated, isAuthChecked])
31
31
 
32
32
  if (!isAuthChecked) return <>{fallback}</>
33
-
34
- if (!isAuthenticated) {
35
- router.replace(redirectTo)
36
- return null
37
- }
38
-
39
- // Block rendering if role is not allowed
33
+ if (!isAuthenticated) return null
40
34
  if (!role || !allowedRoles.includes(role)) return null
41
35
 
36
+ console.log(role);
37
+
38
+
42
39
  return <>{children}</>
43
40
  }
44
41
 
45
- export default RoleGuard
42
+ export default RoleGuard