react-token-manager 1.0.0
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/LICENSE +6 -0
- package/README.md +132 -0
- package/dist/index.d.mts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +1571 -0
- package/dist/index.mjs +1555 -0
- package/package.json +25 -0
- package/src/core.ts +75 -0
- package/src/hook.ts +40 -0
- package/src/index.ts +2 -0
- package/src/useTokenManager.ts +38 -0
- package/tsconfig.json +14 -0
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-token-manager",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A simple React library to manage JWT tokens",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsup src/index.ts --format esm,cjs --dts",
|
|
10
|
+
"dev": "tsup src/index.ts --watch"
|
|
11
|
+
},
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"js-cookie": "^3.0.5",
|
|
16
|
+
"jwt-decode": "^4.0.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/js-cookie": "^3.0.6",
|
|
20
|
+
"@types/react": "^19.2.14",
|
|
21
|
+
"react": "^19.2.4",
|
|
22
|
+
"tsup": "^8.5.1",
|
|
23
|
+
"typescript": "^5.9.3"
|
|
24
|
+
}
|
|
25
|
+
}
|
package/src/core.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { JwtPayload } from 'jwt-decode'
|
|
2
|
+
import * as jwtDecodeModule from 'jwt-decode'
|
|
3
|
+
|
|
4
|
+
// Properly type the callable function
|
|
5
|
+
const jwtDecode: <T = unknown>(token: string) => T =
|
|
6
|
+
(jwtDecodeModule as any).default || jwtDecodeModule
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export type StorageType = 'localStorage' | 'sessionStorage' | 'cookie'
|
|
10
|
+
|
|
11
|
+
export interface TokenManagerOptions {
|
|
12
|
+
storage?: StorageType
|
|
13
|
+
tokenKey?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// ---------------- Global configuration ----------------
|
|
17
|
+
let globalOptions: TokenManagerOptions = {
|
|
18
|
+
storage: 'localStorage',
|
|
19
|
+
tokenKey: 'access_token',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const configureTokenManager = (options: TokenManagerOptions) => {
|
|
23
|
+
globalOptions = { ...globalOptions, ...options }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ---------------- TokenManager Class ----------------
|
|
27
|
+
export class TokenManager {
|
|
28
|
+
private storage: StorageType
|
|
29
|
+
private tokenKey: string
|
|
30
|
+
|
|
31
|
+
constructor(options?: TokenManagerOptions) {
|
|
32
|
+
const opts = options || globalOptions
|
|
33
|
+
this.storage = opts.storage || 'localStorage'
|
|
34
|
+
this.tokenKey = opts.tokenKey || 'access_token'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
set(token: string) {
|
|
38
|
+
if (this.storage === 'localStorage') localStorage.setItem(this.tokenKey, token)
|
|
39
|
+
else if (this.storage === 'sessionStorage') sessionStorage.setItem(this.tokenKey, token)
|
|
40
|
+
else document.cookie = `${this.tokenKey}=${token}; path=/`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get(): string | null {
|
|
44
|
+
if (this.storage === 'localStorage') return localStorage.getItem(this.tokenKey)
|
|
45
|
+
if (this.storage === 'sessionStorage') return sessionStorage.getItem(this.tokenKey)
|
|
46
|
+
const match = document.cookie.match(new RegExp('(^| )' + this.tokenKey + '=([^;]+)'))
|
|
47
|
+
return match ? match[2] : null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
remove() {
|
|
51
|
+
if (this.storage === 'localStorage') localStorage.removeItem(this.tokenKey)
|
|
52
|
+
else if (this.storage === 'sessionStorage') sessionStorage.removeItem(this.tokenKey)
|
|
53
|
+
else document.cookie = `${this.tokenKey}=;expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
decode<T = unknown>(): T | null {
|
|
57
|
+
const token = this.get()
|
|
58
|
+
if (!token) return null
|
|
59
|
+
try {
|
|
60
|
+
return jwtDecode<T>(token) // Now callable
|
|
61
|
+
} catch {
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
isExpired(): boolean {
|
|
67
|
+
const decoded = this.decode<JwtPayload>()
|
|
68
|
+
if (!decoded || !decoded.exp) return true
|
|
69
|
+
return Date.now() >= decoded.exp * 1000
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
getValid(): string | null {
|
|
73
|
+
return this.isExpired() ? null : this.get()
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/hook.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
import { TokenManager, TokenManagerOptions } 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 = (
|
|
13
|
+
options?: TokenManagerOptions
|
|
14
|
+
): UseTokenManagerReturn => {
|
|
15
|
+
const manager = new TokenManager(options)
|
|
16
|
+
|
|
17
|
+
const [token, setTokenState] = useState<string | null>(null)
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
setTokenState(manager.getValid())
|
|
21
|
+
}, [])
|
|
22
|
+
|
|
23
|
+
const setToken = (value: string) => {
|
|
24
|
+
manager.set(value)
|
|
25
|
+
setTokenState(value)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const removeToken = () => {
|
|
29
|
+
manager.remove()
|
|
30
|
+
setTokenState(null)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
token,
|
|
35
|
+
setToken,
|
|
36
|
+
removeToken,
|
|
37
|
+
isExpired: () => manager.isExpired(),
|
|
38
|
+
decode: <T = unknown>() => manager.decode<T>(),
|
|
39
|
+
}
|
|
40
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
}
|
package/tsconfig.json
ADDED