@zhmdff/auth-react 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -6
- package/dist/index.d.mts +43 -5
- package/dist/index.d.ts +43 -5
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,8 +32,9 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
32
32
|
<html lang="en">
|
|
33
33
|
<body>
|
|
34
34
|
<AuthProvider
|
|
35
|
-
authUrl=
|
|
36
|
-
apiUrl=
|
|
35
|
+
authUrl={process.env.NEXT_PUBLIC_AUTH_URL}
|
|
36
|
+
apiUrl={process.env.NEXT_PUBLIC_API_URL}
|
|
37
|
+
loginPath="/login"
|
|
37
38
|
>
|
|
38
39
|
{children}
|
|
39
40
|
</AuthProvider>
|
|
@@ -54,8 +55,9 @@ import App from './App';
|
|
|
54
55
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
55
56
|
<React.StrictMode>
|
|
56
57
|
<AuthProvider
|
|
57
|
-
authUrl=
|
|
58
|
-
apiUrl=
|
|
58
|
+
authUrl={import.meta.env.VITE_AUTH_URL}
|
|
59
|
+
apiUrl={import.meta.env.VITE_API_URL}
|
|
60
|
+
loginPath="/login"
|
|
59
61
|
>
|
|
60
62
|
<App />
|
|
61
63
|
</AuthProvider>
|
|
@@ -85,6 +87,26 @@ export default function UserProfile() {
|
|
|
85
87
|
</div>
|
|
86
88
|
);
|
|
87
89
|
}
|
|
90
|
+
|
|
91
|
+
### 3. Protect routes with `AuthGuard`
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
import { AuthGuard } from "@zhmdff/auth-react";
|
|
95
|
+
|
|
96
|
+
export default function DashboardLayout({ children }) {
|
|
97
|
+
return (
|
|
98
|
+
<AuthGuard
|
|
99
|
+
loadingComponent={<Spinner />}
|
|
100
|
+
// Required roles (optional)
|
|
101
|
+
allowedRoles={["Admin", "SuperAdmin"]}
|
|
102
|
+
// Redirects to loginPath if not authenticated
|
|
103
|
+
>
|
|
104
|
+
{children}
|
|
105
|
+
</AuthGuard>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
88
110
|
```
|
|
89
111
|
|
|
90
112
|
## API Reference
|
|
@@ -93,8 +115,9 @@ export default function UserProfile() {
|
|
|
93
115
|
|
|
94
116
|
| Prop | Type | Required | Description |
|
|
95
117
|
| :--- | :--- | :--- | :--- |
|
|
96
|
-
| `authUrl` | `string` | Yes | The base URL for authentication endpoints
|
|
97
|
-
| `apiUrl` | `string` | No | The base URL for your API.
|
|
118
|
+
| `authUrl` | `string` | Yes | The base URL for authentication endpoints. Recommended to use environment variables. |
|
|
119
|
+
| `apiUrl` | `string` | No | The base URL for your API. Recommended to use environment variables. |
|
|
120
|
+
| `loginPath` | `string` | No | Path to redirect unauthenticated users to (default: `/login`). |
|
|
98
121
|
| `children` | `ReactNode` | Yes | The components to be wrapped. |
|
|
99
122
|
|
|
100
123
|
### `useAuth()` Hook
|
package/dist/index.d.mts
CHANGED
|
@@ -34,6 +34,7 @@ type AuthContextType = {
|
|
|
34
34
|
checkAuth: () => Promise<boolean>;
|
|
35
35
|
logout: () => Promise<void>;
|
|
36
36
|
fetch: (endpoint: string, options?: any) => Promise<any>;
|
|
37
|
+
loginPath?: string;
|
|
37
38
|
};
|
|
38
39
|
interface LoginRequest {
|
|
39
40
|
identifier: string;
|
|
@@ -46,14 +47,18 @@ interface RegisterRequest {
|
|
|
46
47
|
role?: string;
|
|
47
48
|
adminLevel?: number;
|
|
48
49
|
}
|
|
49
|
-
|
|
50
|
-
declare const AuthContext: React.Context<AuthContextType>;
|
|
51
|
-
interface AuthProviderProps extends PropsWithChildren {
|
|
50
|
+
interface AuthConfig {
|
|
52
51
|
authUrl: string;
|
|
53
52
|
apiUrl?: string;
|
|
53
|
+
loginPath?: string;
|
|
54
54
|
storageKey?: string;
|
|
55
55
|
}
|
|
56
|
-
|
|
56
|
+
|
|
57
|
+
declare const AuthContext: React.Context<AuthContextType>;
|
|
58
|
+
|
|
59
|
+
interface AuthProviderProps extends PropsWithChildren, AuthConfig {
|
|
60
|
+
}
|
|
61
|
+
declare const AuthProvider: ({ children, authUrl, apiUrl, loginPath }: AuthProviderProps) => react_jsx_runtime.JSX.Element;
|
|
57
62
|
declare const useAuth: () => AuthContextType;
|
|
58
63
|
|
|
59
64
|
type FetchOptions = {
|
|
@@ -81,4 +86,37 @@ type FetchOptions = {
|
|
|
81
86
|
};
|
|
82
87
|
declare function apiFetch(endpoint: string, options?: FetchOptions): Promise<any>;
|
|
83
88
|
|
|
84
|
-
|
|
89
|
+
interface AuthGuardProps {
|
|
90
|
+
children: React.ReactNode;
|
|
91
|
+
/**
|
|
92
|
+
* Component to show while checking authentication status.
|
|
93
|
+
*/
|
|
94
|
+
loadingComponent?: React.ReactNode;
|
|
95
|
+
/**
|
|
96
|
+
* Called when the user is confirmed to be unauthenticated.
|
|
97
|
+
* Use this to handle redirection (e.g., router.push('/login')).
|
|
98
|
+
*/
|
|
99
|
+
onUnauthenticated?: () => void;
|
|
100
|
+
/**
|
|
101
|
+
* If true, the guard will allow access even if unauthenticated.
|
|
102
|
+
* Useful for layout-level guards where some sub-paths are public.
|
|
103
|
+
*/
|
|
104
|
+
isPublic?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Optional array of roles allowed to access this component/route.
|
|
107
|
+
* If the user is logged in but doesn't have one of these roles,
|
|
108
|
+
* the guard will not render children.
|
|
109
|
+
*/
|
|
110
|
+
allowedRoles?: string[];
|
|
111
|
+
/**
|
|
112
|
+
* Fallback to show when a user is logged in but lacks required roles (forbidden).
|
|
113
|
+
*/
|
|
114
|
+
forbiddenComponent?: React.ReactNode;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* A flexible component to protect routes or sections of an application.
|
|
118
|
+
* It handles the loading state and unauthenticated callback automatically.
|
|
119
|
+
*/
|
|
120
|
+
declare const AuthGuard: ({ children, loadingComponent, onUnauthenticated, isPublic, allowedRoles, forbiddenComponent }: AuthGuardProps) => react_jsx_runtime.JSX.Element;
|
|
121
|
+
|
|
122
|
+
export { type AuthConfig, AuthContext, type AuthContextType, AuthGuard, type AuthGuardProps, AuthProvider, type AuthProviderProps, type AuthResult, type FetchOptions, type LoginRequest, type RegisterRequest, type User, apiFetch, useAuth };
|
package/dist/index.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ type AuthContextType = {
|
|
|
34
34
|
checkAuth: () => Promise<boolean>;
|
|
35
35
|
logout: () => Promise<void>;
|
|
36
36
|
fetch: (endpoint: string, options?: any) => Promise<any>;
|
|
37
|
+
loginPath?: string;
|
|
37
38
|
};
|
|
38
39
|
interface LoginRequest {
|
|
39
40
|
identifier: string;
|
|
@@ -46,14 +47,18 @@ interface RegisterRequest {
|
|
|
46
47
|
role?: string;
|
|
47
48
|
adminLevel?: number;
|
|
48
49
|
}
|
|
49
|
-
|
|
50
|
-
declare const AuthContext: React.Context<AuthContextType>;
|
|
51
|
-
interface AuthProviderProps extends PropsWithChildren {
|
|
50
|
+
interface AuthConfig {
|
|
52
51
|
authUrl: string;
|
|
53
52
|
apiUrl?: string;
|
|
53
|
+
loginPath?: string;
|
|
54
54
|
storageKey?: string;
|
|
55
55
|
}
|
|
56
|
-
|
|
56
|
+
|
|
57
|
+
declare const AuthContext: React.Context<AuthContextType>;
|
|
58
|
+
|
|
59
|
+
interface AuthProviderProps extends PropsWithChildren, AuthConfig {
|
|
60
|
+
}
|
|
61
|
+
declare const AuthProvider: ({ children, authUrl, apiUrl, loginPath }: AuthProviderProps) => react_jsx_runtime.JSX.Element;
|
|
57
62
|
declare const useAuth: () => AuthContextType;
|
|
58
63
|
|
|
59
64
|
type FetchOptions = {
|
|
@@ -81,4 +86,37 @@ type FetchOptions = {
|
|
|
81
86
|
};
|
|
82
87
|
declare function apiFetch(endpoint: string, options?: FetchOptions): Promise<any>;
|
|
83
88
|
|
|
84
|
-
|
|
89
|
+
interface AuthGuardProps {
|
|
90
|
+
children: React.ReactNode;
|
|
91
|
+
/**
|
|
92
|
+
* Component to show while checking authentication status.
|
|
93
|
+
*/
|
|
94
|
+
loadingComponent?: React.ReactNode;
|
|
95
|
+
/**
|
|
96
|
+
* Called when the user is confirmed to be unauthenticated.
|
|
97
|
+
* Use this to handle redirection (e.g., router.push('/login')).
|
|
98
|
+
*/
|
|
99
|
+
onUnauthenticated?: () => void;
|
|
100
|
+
/**
|
|
101
|
+
* If true, the guard will allow access even if unauthenticated.
|
|
102
|
+
* Useful for layout-level guards where some sub-paths are public.
|
|
103
|
+
*/
|
|
104
|
+
isPublic?: boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Optional array of roles allowed to access this component/route.
|
|
107
|
+
* If the user is logged in but doesn't have one of these roles,
|
|
108
|
+
* the guard will not render children.
|
|
109
|
+
*/
|
|
110
|
+
allowedRoles?: string[];
|
|
111
|
+
/**
|
|
112
|
+
* Fallback to show when a user is logged in but lacks required roles (forbidden).
|
|
113
|
+
*/
|
|
114
|
+
forbiddenComponent?: React.ReactNode;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* A flexible component to protect routes or sections of an application.
|
|
118
|
+
* It handles the loading state and unauthenticated callback automatically.
|
|
119
|
+
*/
|
|
120
|
+
declare const AuthGuard: ({ children, loadingComponent, onUnauthenticated, isPublic, allowedRoles, forbiddenComponent }: AuthGuardProps) => react_jsx_runtime.JSX.Element;
|
|
121
|
+
|
|
122
|
+
export { type AuthConfig, AuthContext, type AuthContextType, AuthGuard, type AuthGuardProps, AuthProvider, type AuthProviderProps, type AuthResult, type FetchOptions, type LoginRequest, type RegisterRequest, type User, apiFetch, useAuth };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var y=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var S=(n,t)=>{for(var s in t)y(n,s,{get:t[s],enumerable:!0})},b=(n,t,s,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of $(t))!v.call(n,r)&&r!==s&&y(n,r,{get:()=>t[r],enumerable:!(a=E(t,r))||a.enumerable});return n};var F=n=>b(y({},"__esModule",{value:!0}),n);var G={};S(G,{AuthContext:()=>R,AuthGuard:()=>U,AuthProvider:()=>O,apiFetch:()=>k,useAuth:()=>w});module.exports=F(G);var l=require("react");async function k(n,t={}){let{method:s="GET",body:a,token:r,onTokenRefresh:p,onAuthFail:i,apiUrl:h="/api",authUrl:f="/auth",headers:m,disableAutoRefresh:c=!1}=t,g={"Content-Type":"application/json",...m||{}};r&&(g.Authorization=`Bearer ${r}`);let A={method:s,headers:g,credentials:"include"};a&&s!=="GET"&&(A.body=JSON.stringify(a));let T=await fetch(`${h}${n}`,A);if(!c&&T.status===401&&r&&p)try{let e=await fetch(`${f}/refresh`,{method:"POST",credentials:"include"});if(e.ok){let d=(await e.json()).accessToken;p(d),g.Authorization=`Bearer ${d}`;let x=await fetch(`${h}${n}`,{...A,headers:g});if(!x.ok)throw new Error(await x.text());return x.json()}else throw i?.(),new Error("Session expired")}catch(e){throw i?.(),e}if(!T.ok){let e=await T.text(),o="An error occurred";try{let d=JSON.parse(e);o=d.message||d||o}catch{o=e||o}throw new Error(o)}return T.json()}var P=require("react/jsx-runtime"),R=(0,l.createContext)({accessToken:null,setAccessToken:()=>{},user:null,setUser:()=>{},isLoading:!0,checkAuth:async()=>!1,logout:async()=>{},fetch:async()=>{throw new Error("AuthContext.fetch not implemented")},loginPath:"/login"}),O=({children:n,authUrl:t,apiUrl:s,loginPath:a="/login"})=>{let[r,p]=(0,l.useState)(null),[i,h]=(0,l.useState)(null),[f,m]=(0,l.useState)(!0);(0,l.useEffect)(()=>{(async()=>(await A(),m(!1)))()},[]);let c=(e,o)=>{p(e),h(o)},g=async(e,o={})=>k(e,{...o,token:r,apiUrl:s||"",authUrl:t,onTokenRefresh:d=>{c(d,i)},onAuthFail:()=>{c(null,null)}}),A=async()=>{try{let e=await fetch(`${t}/refresh`,{method:"POST",credentials:"include"});if(!e.ok)return c(null,null),!1;let o=await e.json();return o.success&&o.accessToken&&o.user?(c(o.accessToken,o.user),!0):(c(null,null),!1)}catch{return c(null,null),!1}},T=async()=>{try{await fetch(`${t}/logout`,{method:"POST",credentials:"include",headers:r?{Authorization:`Bearer ${r}`}:{}})}catch(e){console.error("Logout failed:",e)}finally{c(null,null)}};return(0,P.jsx)(R.Provider,{value:{accessToken:r,setAccessToken:e=>c(e,i),user:i,setUser:h,isLoading:f,checkAuth:A,logout:T,fetch:g,loginPath:a},children:n})},w=()=>(0,l.useContext)(R);var C=require("react");var u=require("react/jsx-runtime"),U=({children:n,loadingComponent:t,onUnauthenticated:s,isPublic:a=!1,allowedRoles:r,forbiddenComponent:p})=>{let{user:i,isLoading:h,loginPath:f}=w();return(0,C.useEffect)(()=>{!h&&!i&&!a&&(s?s():f&&(window.location.href=f))},[i,h,a,s,f]),h?(0,u.jsx)(u.Fragment,{children:t||null}):!i&&!a?(0,u.jsx)(u.Fragment,{children:t||null}):i&&r&&r.length>0&&!r.includes(i.role)?(0,u.jsx)(u.Fragment,{children:p||null}):(0,u.jsx)(u.Fragment,{children:n})};0&&(module.exports={AuthContext,AuthGuard,AuthProvider,apiFetch,useAuth});
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createContext as
|
|
1
|
+
import{createContext as P,useContext as C,useState as y,useEffect as E}from"react";async function k(h,i={}){let{method:a="GET",body:c,token:r,onTokenRefresh:f,onAuthFail:o,apiUrl:s="/api",authUrl:l="/auth",headers:A,disableAutoRefresh:n=!1}=i,d={"Content-Type":"application/json",...A||{}};r&&(d.Authorization=`Bearer ${r}`);let p={method:a,headers:d,credentials:"include"};c&&a!=="GET"&&(p.body=JSON.stringify(c));let g=await fetch(`${s}${h}`,p);if(!n&&g.status===401&&r&&f)try{let e=await fetch(`${l}/refresh`,{method:"POST",credentials:"include"});if(e.ok){let u=(await e.json()).accessToken;f(u),d.Authorization=`Bearer ${u}`;let x=await fetch(`${s}${h}`,{...p,headers:d});if(!x.ok)throw new Error(await x.text());return x.json()}else throw o?.(),new Error("Session expired")}catch(e){throw o?.(),e}if(!g.ok){let e=await g.text(),t="An error occurred";try{let u=JSON.parse(e);t=u.message||u||t}catch{t=e||t}throw new Error(t)}return g.json()}import{jsx as $}from"react/jsx-runtime";var R=P({accessToken:null,setAccessToken:()=>{},user:null,setUser:()=>{},isLoading:!0,checkAuth:async()=>!1,logout:async()=>{},fetch:async()=>{throw new Error("AuthContext.fetch not implemented")},loginPath:"/login"}),G=({children:h,authUrl:i,apiUrl:a,loginPath:c="/login"})=>{let[r,f]=y(null),[o,s]=y(null),[l,A]=y(!0);E(()=>{(async()=>(await p(),A(!1)))()},[]);let n=(e,t)=>{f(e),s(t)},d=async(e,t={})=>k(e,{...t,token:r,apiUrl:a||"",authUrl:i,onTokenRefresh:u=>{n(u,o)},onAuthFail:()=>{n(null,null)}}),p=async()=>{try{let e=await fetch(`${i}/refresh`,{method:"POST",credentials:"include"});if(!e.ok)return n(null,null),!1;let t=await e.json();return t.success&&t.accessToken&&t.user?(n(t.accessToken,t.user),!0):(n(null,null),!1)}catch{return n(null,null),!1}},g=async()=>{try{await fetch(`${i}/logout`,{method:"POST",credentials:"include",headers:r?{Authorization:`Bearer ${r}`}:{}})}catch(e){console.error("Logout failed:",e)}finally{n(null,null)}};return $(R.Provider,{value:{accessToken:r,setAccessToken:e=>n(e,o),user:o,setUser:s,isLoading:l,checkAuth:p,logout:g,fetch:d,loginPath:c},children:h})},w=()=>C(R);import{useEffect as v}from"react";import{Fragment as T,jsx as m}from"react/jsx-runtime";var J=({children:h,loadingComponent:i,onUnauthenticated:a,isPublic:c=!1,allowedRoles:r,forbiddenComponent:f})=>{let{user:o,isLoading:s,loginPath:l}=w();return v(()=>{!s&&!o&&!c&&(a?a():l&&(window.location.href=l))},[o,s,c,a,l]),s?m(T,{children:i||null}):!o&&!c?m(T,{children:i||null}):o&&r&&r.length>0&&!r.includes(o.role)?m(T,{children:f||null}):m(T,{children:h})};export{R as AuthContext,J as AuthGuard,G as AuthProvider,k as apiFetch,w as useAuth};
|