react-token-manager 1.0.1 → 1.0.3
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 +66 -36
- package/dist/index.d.mts +23 -17
- package/dist/index.d.ts +23 -17
- package/dist/index.js +48 -42
- package/dist/index.mjs +49 -43
- package/package.json +5 -5
- package/src/core.ts +39 -31
- package/src/hook.ts +15 -32
- package/src/useTokenManager.ts +0 -38
package/README.md
CHANGED
|
@@ -19,7 +19,6 @@ import { configureTokenManager } from 'react-token-manager'
|
|
|
19
19
|
|
|
20
20
|
configureTokenManager({
|
|
21
21
|
storage: 'localStorage', // 'localStorage' | 'sessionStorage' | 'cookie'
|
|
22
|
-
tokenKey: 'access_token', // default: 'access_token'
|
|
23
22
|
})
|
|
24
23
|
```
|
|
25
24
|
## Using the Hook useTokenManager
|
|
@@ -28,18 +27,33 @@ configureTokenManager({
|
|
|
28
27
|
import { useTokenManager } from 'react-token-manager'
|
|
29
28
|
|
|
30
29
|
export default function Dashboard() {
|
|
31
|
-
const {
|
|
30
|
+
const { setTokens, getTokens, removeTokens, decodeToken, isExpired } = useTokenManager()
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
// Set multiple tokens at once
|
|
33
|
+
setTokens({
|
|
34
|
+
access_token: 'abc123',
|
|
35
|
+
refresh_token: 'xyz789',
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
// Get multiple tokens
|
|
39
|
+
const tokens = getTokens(['access_token', 'refresh_token'])
|
|
40
|
+
console.log(tokens.access_token) // 'abc123'
|
|
41
|
+
console.log(tokens.refresh_token) // 'xyz789'
|
|
42
|
+
|
|
43
|
+
// Decode a token
|
|
44
|
+
const payload = decodeToken(tokens.access_token!)
|
|
45
|
+
|
|
46
|
+
// Check if a token is expired
|
|
47
|
+
console.log(isExpired(tokens.access_token!))
|
|
48
|
+
|
|
49
|
+
// Remove multiple tokens
|
|
50
|
+
removeTokens(['access_token', 'refresh_token'])
|
|
35
51
|
|
|
36
52
|
return (
|
|
37
53
|
<div>
|
|
38
|
-
<p>Token: {
|
|
39
|
-
<p>
|
|
40
|
-
<p>Decoded Payload: {JSON.stringify(
|
|
41
|
-
<button onClick={handleLogin}>Login</button>
|
|
42
|
-
<button onClick={handleLogout}>Logout</button>
|
|
54
|
+
<p>Access Token: {tokens.access_token}</p>
|
|
55
|
+
<p>Refresh Token: {tokens.refresh_token}</p>
|
|
56
|
+
<p>Decoded Payload: {JSON.stringify(payload)}</p>
|
|
43
57
|
</div>
|
|
44
58
|
)
|
|
45
59
|
}
|
|
@@ -52,13 +66,25 @@ You can override storage or tokenKey per hook if needed.
|
|
|
52
66
|
```bash
|
|
53
67
|
import { TokenManager } from 'react-token-manager'
|
|
54
68
|
|
|
55
|
-
const manager = new TokenManager({ storage: 'cookie'
|
|
69
|
+
const manager = new TokenManager({ storage: 'cookie' })
|
|
70
|
+
|
|
71
|
+
// Set multiple tokens
|
|
72
|
+
manager.set({
|
|
73
|
+
access_token: 'abc123',
|
|
74
|
+
refresh_token: 'xyz789',
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
// Get multiple tokens
|
|
78
|
+
const tokens = manager.get(['access_token', 'refresh_token'])
|
|
79
|
+
console.log(tokens.access_token) // 'abc123'
|
|
80
|
+
console.log(tokens.refresh_token) // 'xyz789'
|
|
81
|
+
|
|
82
|
+
// Remove multiple tokens
|
|
83
|
+
manager.remove(['access_token', 'refresh_token'])
|
|
56
84
|
|
|
57
|
-
|
|
58
|
-
console.log(manager.
|
|
59
|
-
console.log(manager.
|
|
60
|
-
console.log(manager.isExpired())
|
|
61
|
-
manager.remove()
|
|
85
|
+
// Decode and check expiration of a single token
|
|
86
|
+
console.log(manager.decode(tokens.access_token!))
|
|
87
|
+
console.log(manager.isExpired(tokens.access_token!))
|
|
62
88
|
```
|
|
63
89
|
|
|
64
90
|
## API Reference
|
|
@@ -70,36 +96,34 @@ Set global options.
|
|
|
70
96
|
```bash
|
|
71
97
|
{
|
|
72
98
|
storage?: 'localStorage' | 'sessionStorage' | 'cookie';
|
|
73
|
-
tokenKey?: string;
|
|
74
99
|
}
|
|
75
100
|
|
|
101
|
+
|
|
76
102
|
useTokenManager(options?: TokenManagerOptions)
|
|
77
103
|
|
|
78
104
|
Returns:
|
|
105
|
+
setTokens(tokens: Record<string, string>) // Set multiple tokens
|
|
79
106
|
|
|
80
|
-
|
|
107
|
+
getTokens(keys: string | string[]) // Get multiple tokens
|
|
81
108
|
|
|
82
|
-
|
|
109
|
+
removeTokens(keys: string | string[]) // Remove multiple tokens
|
|
83
110
|
|
|
84
|
-
|
|
111
|
+
decodeToken<T = unknown>(token: string) // Decode a single token
|
|
85
112
|
|
|
86
|
-
|
|
113
|
+
isExpired(token: string) // Check if a token is expired
|
|
87
114
|
|
|
88
|
-
decode<T>(): T | null — decode JWT payload
|
|
89
115
|
|
|
90
116
|
TokenManager Class Methods
|
|
117
|
+
set(tokens: Record<string, string>) // Store multiple tokens
|
|
91
118
|
|
|
92
|
-
|
|
119
|
+
get(keys: string | string[]) // Retrieve multiple tokens
|
|
93
120
|
|
|
94
|
-
|
|
121
|
+
remove(keys: string | string[]) // Delete multiple tokens
|
|
95
122
|
|
|
96
|
-
|
|
123
|
+
decode<T = unknown>(token: string) // Decode a single token
|
|
97
124
|
|
|
98
|
-
|
|
125
|
+
isExpired(token: string) // Check if a token is expired
|
|
99
126
|
|
|
100
|
-
isExpired(): boolean — check if token is expired
|
|
101
|
-
|
|
102
|
-
getValid(): string | null — get token only if valid
|
|
103
127
|
|
|
104
128
|
```
|
|
105
129
|
|
|
@@ -108,25 +132,31 @@ TokenManager Class Methods
|
|
|
108
132
|
Multiple Tokens
|
|
109
133
|
|
|
110
134
|
```bash
|
|
111
|
-
const {
|
|
112
|
-
|
|
135
|
+
const { setTokens, getTokens } = useTokenManager()
|
|
136
|
+
|
|
137
|
+
setTokens({
|
|
138
|
+
access_token: 'abc',
|
|
139
|
+
refresh_token: 'xyz',
|
|
140
|
+
})
|
|
113
141
|
|
|
114
|
-
|
|
115
|
-
|
|
142
|
+
const tokens = getTokens(['access_token', 'refresh_token'])
|
|
143
|
+
console.log(tokens.access_token) // 'abc'
|
|
144
|
+
console.log(tokens.refresh_token) // 'xyz'
|
|
116
145
|
```
|
|
117
146
|
|
|
118
147
|
##Using Cookies
|
|
119
148
|
```bash
|
|
120
|
-
configureTokenManager({ storage: 'cookie'
|
|
149
|
+
configureTokenManager({ storage: 'cookie' })
|
|
121
150
|
```
|
|
122
151
|
|
|
123
152
|
Checking Expiry Before API Call
|
|
124
153
|
|
|
125
154
|
```bash
|
|
126
|
-
const
|
|
155
|
+
const { getTokens, isExpired } = useTokenManager()
|
|
156
|
+
const { access_token } = getTokens(['access_token'])
|
|
127
157
|
|
|
128
|
-
if (!
|
|
129
|
-
callApi(
|
|
158
|
+
if (!isExpired(access_token!)) {
|
|
159
|
+
callApi(access_token)
|
|
130
160
|
}
|
|
131
161
|
```
|
|
132
162
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
type StorageType = 'localStorage' | 'sessionStorage' | 'cookie';
|
|
2
2
|
interface TokenManagerOptions {
|
|
3
3
|
storage?: StorageType;
|
|
4
|
-
tokenKey?: string;
|
|
5
4
|
}
|
|
6
5
|
declare const configureTokenManager: (options: TokenManagerOptions) => void;
|
|
7
6
|
declare class TokenManager {
|
|
8
7
|
private storage;
|
|
9
|
-
private tokenKey;
|
|
10
8
|
constructor(options?: TokenManagerOptions);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
/** Set multiple tokens at once */
|
|
10
|
+
set(tokens: Record<string, string>): void;
|
|
11
|
+
/** Get single token by key or all tokens in an array of keys */
|
|
12
|
+
get(keys: string | string[]): Record<string, string | null>;
|
|
13
|
+
/** Remove multiple tokens by keys */
|
|
14
|
+
remove(keys: string | string[]): void;
|
|
15
|
+
/** Decode a single token by key */
|
|
16
|
+
decode<T = unknown>(token: string): T | null;
|
|
17
|
+
/** Check if a token is expired */
|
|
18
|
+
isExpired(token: string): boolean;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
declare const useTokenManager: () => {
|
|
22
|
+
/** Set multiple tokens */
|
|
23
|
+
setTokens: (tokens: Record<string, string>) => void;
|
|
24
|
+
/** Get multiple tokens by keys */
|
|
25
|
+
getTokens: (keys: string | string[]) => Record<string, string | null>;
|
|
26
|
+
/** Remove multiple tokens by keys */
|
|
27
|
+
removeTokens: (keys: string | string[]) => void;
|
|
28
|
+
/** Decode a single token */
|
|
29
|
+
decodeToken: <T = unknown>(token: string) => T | null;
|
|
30
|
+
/** Check expiration of a single token */
|
|
31
|
+
isExpired: (token: string) => boolean;
|
|
32
|
+
};
|
|
27
33
|
|
|
28
|
-
export { type StorageType, TokenManager, type TokenManagerOptions,
|
|
34
|
+
export { type StorageType, TokenManager, type TokenManagerOptions, configureTokenManager, useTokenManager };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,28 +1,34 @@
|
|
|
1
1
|
type StorageType = 'localStorage' | 'sessionStorage' | 'cookie';
|
|
2
2
|
interface TokenManagerOptions {
|
|
3
3
|
storage?: StorageType;
|
|
4
|
-
tokenKey?: string;
|
|
5
4
|
}
|
|
6
5
|
declare const configureTokenManager: (options: TokenManagerOptions) => void;
|
|
7
6
|
declare class TokenManager {
|
|
8
7
|
private storage;
|
|
9
|
-
private tokenKey;
|
|
10
8
|
constructor(options?: TokenManagerOptions);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
/** Set multiple tokens at once */
|
|
10
|
+
set(tokens: Record<string, string>): void;
|
|
11
|
+
/** Get single token by key or all tokens in an array of keys */
|
|
12
|
+
get(keys: string | string[]): Record<string, string | null>;
|
|
13
|
+
/** Remove multiple tokens by keys */
|
|
14
|
+
remove(keys: string | string[]): void;
|
|
15
|
+
/** Decode a single token by key */
|
|
16
|
+
decode<T = unknown>(token: string): T | null;
|
|
17
|
+
/** Check if a token is expired */
|
|
18
|
+
isExpired(token: string): boolean;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
declare const useTokenManager: () => {
|
|
22
|
+
/** Set multiple tokens */
|
|
23
|
+
setTokens: (tokens: Record<string, string>) => void;
|
|
24
|
+
/** Get multiple tokens by keys */
|
|
25
|
+
getTokens: (keys: string | string[]) => Record<string, string | null>;
|
|
26
|
+
/** Remove multiple tokens by keys */
|
|
27
|
+
removeTokens: (keys: string | string[]) => void;
|
|
28
|
+
/** Decode a single token */
|
|
29
|
+
decodeToken: <T = unknown>(token: string) => T | null;
|
|
30
|
+
/** Check expiration of a single token */
|
|
31
|
+
isExpired: (token: string) => boolean;
|
|
32
|
+
};
|
|
27
33
|
|
|
28
|
-
export { type StorageType, TokenManager, type TokenManagerOptions,
|
|
34
|
+
export { type StorageType, TokenManager, type TokenManagerOptions, configureTokenManager, useTokenManager };
|
package/dist/index.js
CHANGED
|
@@ -40,8 +40,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
40
40
|
var jwtDecodeModule = __toESM(require("jwt-decode"));
|
|
41
41
|
var jwtDecode = jwtDecodeModule.default || jwtDecodeModule;
|
|
42
42
|
var globalOptions = {
|
|
43
|
-
storage: "localStorage"
|
|
44
|
-
tokenKey: "access_token"
|
|
43
|
+
storage: "localStorage"
|
|
45
44
|
};
|
|
46
45
|
var configureTokenManager = (options) => {
|
|
47
46
|
globalOptions = { ...globalOptions, ...options };
|
|
@@ -50,26 +49,42 @@ var TokenManager = class {
|
|
|
50
49
|
constructor(options) {
|
|
51
50
|
const opts = options || globalOptions;
|
|
52
51
|
this.storage = opts.storage || "localStorage";
|
|
53
|
-
this.tokenKey = opts.tokenKey || "access_token";
|
|
54
52
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
/** Set multiple tokens at once */
|
|
54
|
+
set(tokens) {
|
|
55
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
56
|
+
if (this.storage === "localStorage") localStorage.setItem(key, value);
|
|
57
|
+
else if (this.storage === "sessionStorage") sessionStorage.setItem(key, value);
|
|
58
|
+
else document.cookie = `${key}=${value}; path=/`;
|
|
59
|
+
});
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
61
|
+
/** Get single token by key or all tokens in an array of keys */
|
|
62
|
+
get(keys) {
|
|
63
|
+
const keyArray = Array.isArray(keys) ? keys : [keys];
|
|
64
|
+
const result = {};
|
|
65
|
+
keyArray.forEach((key) => {
|
|
66
|
+
let value = null;
|
|
67
|
+
if (this.storage === "localStorage") value = localStorage.getItem(key);
|
|
68
|
+
else if (this.storage === "sessionStorage") value = sessionStorage.getItem(key);
|
|
69
|
+
else {
|
|
70
|
+
const match = document.cookie.match(new RegExp("(^| )" + key + "=([^;]+)"));
|
|
71
|
+
value = match ? match[2] : null;
|
|
72
|
+
}
|
|
73
|
+
result[key] = value;
|
|
74
|
+
});
|
|
75
|
+
return result;
|
|
65
76
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
/** Remove multiple tokens by keys */
|
|
78
|
+
remove(keys) {
|
|
79
|
+
const keyArray = Array.isArray(keys) ? keys : [keys];
|
|
80
|
+
keyArray.forEach((key) => {
|
|
81
|
+
if (this.storage === "localStorage") localStorage.removeItem(key);
|
|
82
|
+
else if (this.storage === "sessionStorage") sessionStorage.removeItem(key);
|
|
83
|
+
else document.cookie = `${key}=;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
|
|
84
|
+
});
|
|
70
85
|
}
|
|
71
|
-
|
|
72
|
-
|
|
86
|
+
/** Decode a single token by key */
|
|
87
|
+
decode(token) {
|
|
73
88
|
if (!token) return null;
|
|
74
89
|
try {
|
|
75
90
|
return jwtDecode(token);
|
|
@@ -77,38 +92,29 @@ var TokenManager = class {
|
|
|
77
92
|
return null;
|
|
78
93
|
}
|
|
79
94
|
}
|
|
80
|
-
|
|
81
|
-
|
|
95
|
+
/** Check if a token is expired */
|
|
96
|
+
isExpired(token) {
|
|
97
|
+
const decoded = this.decode(token);
|
|
82
98
|
if (!decoded || !decoded.exp) return true;
|
|
83
99
|
return Date.now() >= decoded.exp * 1e3;
|
|
84
100
|
}
|
|
85
|
-
getValid() {
|
|
86
|
-
return this.isExpired() ? null : this.get();
|
|
87
|
-
}
|
|
88
101
|
};
|
|
89
102
|
|
|
90
103
|
// src/hook.ts
|
|
91
104
|
var import_react = require("react");
|
|
92
|
-
var useTokenManager = (
|
|
93
|
-
const manager = new TokenManager(
|
|
94
|
-
const [token, setTokenState] = (0, import_react.useState)(null);
|
|
95
|
-
(0, import_react.useEffect)(() => {
|
|
96
|
-
setTokenState(manager.getValid());
|
|
97
|
-
}, []);
|
|
98
|
-
const setToken = (value) => {
|
|
99
|
-
manager.set(value);
|
|
100
|
-
setTokenState(value);
|
|
101
|
-
};
|
|
102
|
-
const removeToken = () => {
|
|
103
|
-
manager.remove();
|
|
104
|
-
setTokenState(null);
|
|
105
|
-
};
|
|
105
|
+
var useTokenManager = () => {
|
|
106
|
+
const manager = (0, import_react.useMemo)(() => new TokenManager(), []);
|
|
106
107
|
return {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
/** Set multiple tokens */
|
|
109
|
+
setTokens: (tokens) => manager.set(tokens),
|
|
110
|
+
/** Get multiple tokens by keys */
|
|
111
|
+
getTokens: (keys) => manager.get(keys),
|
|
112
|
+
/** Remove multiple tokens by keys */
|
|
113
|
+
removeTokens: (keys) => manager.remove(keys),
|
|
114
|
+
/** Decode a single token */
|
|
115
|
+
decodeToken: (token) => manager.decode(token),
|
|
116
|
+
/** Check expiration of a single token */
|
|
117
|
+
isExpired: (token) => manager.isExpired(token)
|
|
112
118
|
};
|
|
113
119
|
};
|
|
114
120
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.mjs
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
import * as jwtDecodeModule from "jwt-decode";
|
|
3
3
|
var jwtDecode = jwtDecodeModule.default || jwtDecodeModule;
|
|
4
4
|
var globalOptions = {
|
|
5
|
-
storage: "localStorage"
|
|
6
|
-
tokenKey: "access_token"
|
|
5
|
+
storage: "localStorage"
|
|
7
6
|
};
|
|
8
7
|
var configureTokenManager = (options) => {
|
|
9
8
|
globalOptions = { ...globalOptions, ...options };
|
|
@@ -12,26 +11,42 @@ var TokenManager = class {
|
|
|
12
11
|
constructor(options) {
|
|
13
12
|
const opts = options || globalOptions;
|
|
14
13
|
this.storage = opts.storage || "localStorage";
|
|
15
|
-
this.tokenKey = opts.tokenKey || "access_token";
|
|
16
14
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
/** Set multiple tokens at once */
|
|
16
|
+
set(tokens) {
|
|
17
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
18
|
+
if (this.storage === "localStorage") localStorage.setItem(key, value);
|
|
19
|
+
else if (this.storage === "sessionStorage") sessionStorage.setItem(key, value);
|
|
20
|
+
else document.cookie = `${key}=${value}; path=/`;
|
|
21
|
+
});
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
23
|
+
/** Get single token by key or all tokens in an array of keys */
|
|
24
|
+
get(keys) {
|
|
25
|
+
const keyArray = Array.isArray(keys) ? keys : [keys];
|
|
26
|
+
const result = {};
|
|
27
|
+
keyArray.forEach((key) => {
|
|
28
|
+
let value = null;
|
|
29
|
+
if (this.storage === "localStorage") value = localStorage.getItem(key);
|
|
30
|
+
else if (this.storage === "sessionStorage") value = sessionStorage.getItem(key);
|
|
31
|
+
else {
|
|
32
|
+
const match = document.cookie.match(new RegExp("(^| )" + key + "=([^;]+)"));
|
|
33
|
+
value = match ? match[2] : null;
|
|
34
|
+
}
|
|
35
|
+
result[key] = value;
|
|
36
|
+
});
|
|
37
|
+
return result;
|
|
27
38
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
/** Remove multiple tokens by keys */
|
|
40
|
+
remove(keys) {
|
|
41
|
+
const keyArray = Array.isArray(keys) ? keys : [keys];
|
|
42
|
+
keyArray.forEach((key) => {
|
|
43
|
+
if (this.storage === "localStorage") localStorage.removeItem(key);
|
|
44
|
+
else if (this.storage === "sessionStorage") sessionStorage.removeItem(key);
|
|
45
|
+
else document.cookie = `${key}=;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
|
|
46
|
+
});
|
|
32
47
|
}
|
|
33
|
-
|
|
34
|
-
|
|
48
|
+
/** Decode a single token by key */
|
|
49
|
+
decode(token) {
|
|
35
50
|
if (!token) return null;
|
|
36
51
|
try {
|
|
37
52
|
return jwtDecode(token);
|
|
@@ -39,38 +54,29 @@ var TokenManager = class {
|
|
|
39
54
|
return null;
|
|
40
55
|
}
|
|
41
56
|
}
|
|
42
|
-
|
|
43
|
-
|
|
57
|
+
/** Check if a token is expired */
|
|
58
|
+
isExpired(token) {
|
|
59
|
+
const decoded = this.decode(token);
|
|
44
60
|
if (!decoded || !decoded.exp) return true;
|
|
45
61
|
return Date.now() >= decoded.exp * 1e3;
|
|
46
62
|
}
|
|
47
|
-
getValid() {
|
|
48
|
-
return this.isExpired() ? null : this.get();
|
|
49
|
-
}
|
|
50
63
|
};
|
|
51
64
|
|
|
52
65
|
// src/hook.ts
|
|
53
|
-
import {
|
|
54
|
-
var useTokenManager = (
|
|
55
|
-
const manager = new TokenManager(
|
|
56
|
-
const [token, setTokenState] = useState(null);
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
setTokenState(manager.getValid());
|
|
59
|
-
}, []);
|
|
60
|
-
const setToken = (value) => {
|
|
61
|
-
manager.set(value);
|
|
62
|
-
setTokenState(value);
|
|
63
|
-
};
|
|
64
|
-
const removeToken = () => {
|
|
65
|
-
manager.remove();
|
|
66
|
-
setTokenState(null);
|
|
67
|
-
};
|
|
66
|
+
import { useMemo } from "react";
|
|
67
|
+
var useTokenManager = () => {
|
|
68
|
+
const manager = useMemo(() => new TokenManager(), []);
|
|
68
69
|
return {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
/** Set multiple tokens */
|
|
71
|
+
setTokens: (tokens) => manager.set(tokens),
|
|
72
|
+
/** Get multiple tokens by keys */
|
|
73
|
+
getTokens: (keys) => manager.get(keys),
|
|
74
|
+
/** Remove multiple tokens by keys */
|
|
75
|
+
removeTokens: (keys) => manager.remove(keys),
|
|
76
|
+
/** Decode a single token */
|
|
77
|
+
decodeToken: (token) => manager.decode(token),
|
|
78
|
+
/** Check expiration of a single token */
|
|
79
|
+
isExpired: (token) => manager.isExpired(token)
|
|
74
80
|
};
|
|
75
81
|
};
|
|
76
82
|
export {
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-token-manager",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "A simple React library to manage JWT tokens",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"module": "dist/index.mjs",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"author": "",
|
|
13
13
|
"license": "ISC",
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"react": "^
|
|
16
|
-
"react-dom": "^
|
|
15
|
+
"react": "^19.2.3",
|
|
16
|
+
"react-dom": "^19.2.3"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"js-cookie": "^3.0.5",
|
package/src/core.ts
CHANGED
|
@@ -1,75 +1,83 @@
|
|
|
1
1
|
import type { JwtPayload } from 'jwt-decode'
|
|
2
2
|
import * as jwtDecodeModule from 'jwt-decode'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
const jwtDecode: <T = unknown>(token: string) => T =
|
|
4
|
+
const jwtDecode: <T = unknown>(token: string) => T =
|
|
6
5
|
(jwtDecodeModule as any).default || jwtDecodeModule
|
|
7
6
|
|
|
8
|
-
|
|
9
7
|
export type StorageType = 'localStorage' | 'sessionStorage' | 'cookie'
|
|
10
8
|
|
|
11
9
|
export interface TokenManagerOptions {
|
|
12
10
|
storage?: StorageType
|
|
13
|
-
tokenKey?: string
|
|
14
11
|
}
|
|
15
12
|
|
|
16
|
-
// ---------------- Global configuration ----------------
|
|
17
13
|
let globalOptions: TokenManagerOptions = {
|
|
18
14
|
storage: 'localStorage',
|
|
19
|
-
tokenKey: 'access_token',
|
|
20
15
|
}
|
|
21
16
|
|
|
22
17
|
export const configureTokenManager = (options: TokenManagerOptions) => {
|
|
23
18
|
globalOptions = { ...globalOptions, ...options }
|
|
24
19
|
}
|
|
25
20
|
|
|
26
|
-
// ---------------- TokenManager Class ----------------
|
|
27
21
|
export class TokenManager {
|
|
28
22
|
private storage: StorageType
|
|
29
|
-
private tokenKey: string
|
|
30
23
|
|
|
31
24
|
constructor(options?: TokenManagerOptions) {
|
|
32
25
|
const opts = options || globalOptions
|
|
33
26
|
this.storage = opts.storage || 'localStorage'
|
|
34
|
-
this.tokenKey = opts.tokenKey || 'access_token'
|
|
35
27
|
}
|
|
36
28
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
/** Set multiple tokens at once */
|
|
30
|
+
set(tokens: Record<string, string>) {
|
|
31
|
+
Object.entries(tokens).forEach(([key, value]) => {
|
|
32
|
+
if (this.storage === 'localStorage') localStorage.setItem(key, value)
|
|
33
|
+
else if (this.storage === 'sessionStorage') sessionStorage.setItem(key, value)
|
|
34
|
+
else document.cookie = `${key}=${value}; path=/`
|
|
35
|
+
})
|
|
41
36
|
}
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
38
|
+
/** Get single token by key or all tokens in an array of keys */
|
|
39
|
+
get(keys: string | string[]): Record<string, string | null> {
|
|
40
|
+
const keyArray = Array.isArray(keys) ? keys : [keys]
|
|
41
|
+
const result: Record<string, string | null> = {}
|
|
42
|
+
|
|
43
|
+
keyArray.forEach((key) => {
|
|
44
|
+
let value: string | null = null
|
|
45
|
+
if (this.storage === 'localStorage') value = localStorage.getItem(key)
|
|
46
|
+
else if (this.storage === 'sessionStorage') value = sessionStorage.getItem(key)
|
|
47
|
+
else {
|
|
48
|
+
const match = document.cookie.match(new RegExp('(^| )' + key + '=([^;]+)'))
|
|
49
|
+
value = match ? match[2] : null
|
|
50
|
+
}
|
|
51
|
+
result[key] = value
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
return result
|
|
48
55
|
}
|
|
49
56
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
/** Remove multiple tokens by keys */
|
|
58
|
+
remove(keys: string | string[]) {
|
|
59
|
+
const keyArray = Array.isArray(keys) ? keys : [keys]
|
|
60
|
+
keyArray.forEach((key) => {
|
|
61
|
+
if (this.storage === 'localStorage') localStorage.removeItem(key)
|
|
62
|
+
else if (this.storage === 'sessionStorage') sessionStorage.removeItem(key)
|
|
63
|
+
else document.cookie = `${key}=;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`
|
|
64
|
+
})
|
|
54
65
|
}
|
|
55
66
|
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
/** Decode a single token by key */
|
|
68
|
+
decode<T = unknown>(token: string): T | null {
|
|
58
69
|
if (!token) return null
|
|
59
70
|
try {
|
|
60
|
-
return jwtDecode<T>(token)
|
|
71
|
+
return jwtDecode<T>(token)
|
|
61
72
|
} catch {
|
|
62
73
|
return null
|
|
63
74
|
}
|
|
64
75
|
}
|
|
65
76
|
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
/** Check if a token is expired */
|
|
78
|
+
isExpired(token: string): boolean {
|
|
79
|
+
const decoded = this.decode<JwtPayload>(token)
|
|
68
80
|
if (!decoded || !decoded.exp) return true
|
|
69
81
|
return Date.now() >= decoded.exp * 1000
|
|
70
82
|
}
|
|
71
|
-
|
|
72
|
-
getValid(): string | null {
|
|
73
|
-
return this.isExpired() ? null : this.get()
|
|
74
|
-
}
|
|
75
83
|
}
|
package/src/hook.ts
CHANGED
|
@@ -1,40 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { TokenManager
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import { TokenManager } from './core'
|
|
3
3
|
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
setToken: (value: string) => void
|
|
7
|
-
removeToken: () => void
|
|
8
|
-
isExpired: () => boolean
|
|
9
|
-
decode: <T = unknown>() => T | null
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const useTokenManager = (
|
|
13
|
-
options?: TokenManagerOptions
|
|
14
|
-
): UseTokenManagerReturn => {
|
|
15
|
-
const manager = new TokenManager(options)
|
|
4
|
+
export const useTokenManager = () => {
|
|
5
|
+
const manager = useMemo(() => new TokenManager(), [])
|
|
16
6
|
|
|
17
|
-
|
|
7
|
+
return {
|
|
8
|
+
/** Set multiple tokens */
|
|
9
|
+
setTokens: (tokens: Record<string, string>) => manager.set(tokens),
|
|
18
10
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}, [])
|
|
11
|
+
/** Get multiple tokens by keys */
|
|
12
|
+
getTokens: (keys: string | string[]) => manager.get(keys),
|
|
22
13
|
|
|
23
|
-
|
|
24
|
-
manager.
|
|
25
|
-
setTokenState(value)
|
|
26
|
-
}
|
|
14
|
+
/** Remove multiple tokens by keys */
|
|
15
|
+
removeTokens: (keys: string | string[]) => manager.remove(keys),
|
|
27
16
|
|
|
28
|
-
|
|
29
|
-
manager.
|
|
30
|
-
setTokenState(null)
|
|
31
|
-
}
|
|
17
|
+
/** Decode a single token */
|
|
18
|
+
decodeToken: <T = unknown>(token: string) => manager.decode<T>(token),
|
|
32
19
|
|
|
33
|
-
|
|
34
|
-
token,
|
|
35
|
-
setToken,
|
|
36
|
-
removeToken,
|
|
37
|
-
isExpired: () => manager.isExpired(),
|
|
38
|
-
decode: <T = unknown>() => manager.decode<T>(),
|
|
20
|
+
/** Check expiration of a single token */
|
|
21
|
+
isExpired: (token: string) => manager.isExpired(token),
|
|
39
22
|
}
|
|
40
23
|
}
|
package/src/useTokenManager.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState, useMemo } from 'react'
|
|
2
|
-
import { TokenManager } from './core'
|
|
3
|
-
|
|
4
|
-
export interface UseTokenManagerReturn {
|
|
5
|
-
token: string | null
|
|
6
|
-
setToken: (value: string) => void
|
|
7
|
-
removeToken: () => void
|
|
8
|
-
isExpired: () => boolean
|
|
9
|
-
decode: <T = unknown>() => T | null
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const useTokenManager = (): UseTokenManagerReturn => {
|
|
13
|
-
const manager = useMemo(() => new TokenManager(), [])
|
|
14
|
-
|
|
15
|
-
const [token, setTokenState] = useState<string | null>(null)
|
|
16
|
-
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
setTokenState(manager.getValid())
|
|
19
|
-
}, [manager])
|
|
20
|
-
|
|
21
|
-
const setToken = (value: string) => {
|
|
22
|
-
manager.set(value)
|
|
23
|
-
setTokenState(value)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const removeToken = () => {
|
|
27
|
-
manager.remove()
|
|
28
|
-
setTokenState(null)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
token,
|
|
33
|
-
setToken,
|
|
34
|
-
removeToken,
|
|
35
|
-
isExpired: () => manager.isExpired(),
|
|
36
|
-
decode: <T = unknown>() => manager.decode<T>(),
|
|
37
|
-
}
|
|
38
|
-
}
|