@molecule/app-auth 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 +115 -0
- package/dist/client.d.ts +19 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +413 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +88 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/provider.d.ts +31 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +38 -0
- package/dist/provider.js.map +1 -0
- package/dist/token.d.ts +57 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +133 -0
- package/dist/token.js.map +1 -0
- package/dist/types.d.ts +387 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/utilities.d.ts +39 -0
- package/dist/utilities.d.ts.map +1 -0
- package/dist/utilities.js +39 -0
- package/dist/utilities.js.map +1 -0
- package/package.json +52 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side authentication interface for molecule.dev.
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified auth API that works across different auth strategies
|
|
5
|
+
* (JWT, session, OAuth, etc.): `createJWTAuthClient` builds a fetch-based
|
|
6
|
+
* client; `setClient`/`getClient` bond it; `login`/`logout`/`register`/
|
|
7
|
+
* `isAuthenticated`/`getUser` delegate to the bonded client. Framework
|
|
8
|
+
* bindings (e.g. `AuthProvider`/`useAuth` in `@molecule/app-react`) wrap the
|
|
9
|
+
* same client.
|
|
10
|
+
*
|
|
11
|
+
* @remarks
|
|
12
|
+
* - **A page reload "logging the user out" is the config default, not a bug.**
|
|
13
|
+
* Token storage defaults to `'memory'` (the secure default — a localStorage
|
|
14
|
+
* bearer token is XSS-exfiltratable). Staying signed in across reloads works
|
|
15
|
+
* by calling `client.initialize()` once at startup: it re-fetches
|
|
16
|
+
* `currentUserEndpoint` (default `/users/me`) with the httpOnly cookie the
|
|
17
|
+
* API set at login. Wire `initialize()`; do NOT "fix" reload-logout by
|
|
18
|
+
* copying tokens into localStorage.
|
|
19
|
+
* - **Endpoint defaults must match your API's real routes** (`/auth/login`,
|
|
20
|
+
* `/auth/register`, `/auth/refresh`, `/users/logout`, `/users/me`, …).
|
|
21
|
+
* Align them via `createJWTAuthClient({ baseURL, ...endpoints })` — never by
|
|
22
|
+
* hand-editing fetch calls in components.
|
|
23
|
+
* - Client-side auth state is UX only — the server enforces authorization on
|
|
24
|
+
* every request; hiding a screen is not protection.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { createJWTAuthClient, setClient } from '@molecule/app-auth'
|
|
29
|
+
*
|
|
30
|
+
* const client = createJWTAuthClient({ baseURL: '/api' })
|
|
31
|
+
* setClient(client)
|
|
32
|
+
* await client.initialize() // restore the session from the httpOnly cookie
|
|
33
|
+
*
|
|
34
|
+
* // anywhere in the app
|
|
35
|
+
* import { getUser, isAuthenticated, login, logout } from '@molecule/app-auth'
|
|
36
|
+
* await login({ email, password })
|
|
37
|
+
* if (isAuthenticated()) console.log(getUser()?.email)
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @e2e
|
|
41
|
+
* Integration checklist — drive the real UI (live preview, no mocks), adapt
|
|
42
|
+
* each item to this app's actual screens/flows, and check every box off one
|
|
43
|
+
* by one. A box you can't check is an integration bug to fix — not a skip:
|
|
44
|
+
* - [ ] Logging in with VALID credentials on the real login screen resolves
|
|
45
|
+
* `login()` and flips AuthState to `authenticated: true` with `getUser()`
|
|
46
|
+
* returning the actual UserProfile — the UI shows that user's own `email` /
|
|
47
|
+
* `name` / `avatar`, never a placeholder or a different account.
|
|
48
|
+
* - [ ] A WRONG password shows a visible error (AuthState `error` is set and
|
|
49
|
+
* the promise rejects) and establishes NO session: `isAuthenticated()` stays
|
|
50
|
+
* false and no protected screen becomes reachable.
|
|
51
|
+
* - [ ] Registering through the sign-up form calls `register()`, creates the
|
|
52
|
+
* account, and lands authenticated (`authenticated: true`, `user` populated)
|
|
53
|
+
* on the app's post-signup screen — not back on the login form. If the flow
|
|
54
|
+
* shows an email-verification / "check your inbox" step, it must be genuinely
|
|
55
|
+
* backed (this client's `register()` returns an authenticated session
|
|
56
|
+
* directly and exposes no verify method) — never a dead screen the auth
|
|
57
|
+
* contract cannot advance past.
|
|
58
|
+
* - [ ] Logout calls `logout()` and clears the session (`authenticated: false`,
|
|
59
|
+
* `user: null`, tokens cleared); afterward every protected screen redirects
|
|
60
|
+
* back to login.
|
|
61
|
+
* - [ ] Visiting a protected route while logged OUT redirects to login (the
|
|
62
|
+
* guard reads `isAuthenticated()`), and after authenticating you land back on
|
|
63
|
+
* the originally-requested screen rather than a generic home.
|
|
64
|
+
* - [ ] The session survives a FULL page reload: after login, hard-reload →
|
|
65
|
+
* `initialize()` restores it from the httpOnly cookie (via
|
|
66
|
+
* `currentUserEndpoint`, default `/users/me`) and you stay signed in — you are
|
|
67
|
+
* NOT bounced to login. (The in-memory bearer token is dropped by design; the
|
|
68
|
+
* cookie restore is what keeps you in — do not "fix" this by writing the token
|
|
69
|
+
* to localStorage.)
|
|
70
|
+
* - [ ] Password reset round-trips: `requestPasswordReset({ email })` then
|
|
71
|
+
* `confirmPasswordReset({ token, password })` with the emailed token, after
|
|
72
|
+
* which `login()` with the NEW password succeeds and the OLD password no
|
|
73
|
+
* longer works.
|
|
74
|
+
* - [ ] Authorization holds: a signed-in user only ever reads/edits their OWN
|
|
75
|
+
* record (`getUser()` is the caller's profile, never another user's); the
|
|
76
|
+
* bearer token lives in memory only — it is never written to
|
|
77
|
+
* localStorage / sessionStorage where another script could read it; and an
|
|
78
|
+
* expired/invalid token fails closed — the app re-authenticates (`refresh()`
|
|
79
|
+
* or `logout()`), never silently serving another user's data.
|
|
80
|
+
*
|
|
81
|
+
* @module
|
|
82
|
+
*/
|
|
83
|
+
export * from './client.js';
|
|
84
|
+
export * from './provider.js';
|
|
85
|
+
export * from './token.js';
|
|
86
|
+
export * from './types.js';
|
|
87
|
+
export * from './utilities.js';
|
|
88
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiFG;AAEH,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth client bond accessor.
|
|
3
|
+
*
|
|
4
|
+
* Bond packages call `setClient()` during setup. Application code uses
|
|
5
|
+
* `getClient()` to access login, logout, register, token management,
|
|
6
|
+
* and auth state subscription.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import type { AuthClient, UserProfile } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Registers an auth client as the active singleton. Called by bond
|
|
13
|
+
* packages during application startup.
|
|
14
|
+
*
|
|
15
|
+
* @param client - The auth client implementation to bond.
|
|
16
|
+
*/
|
|
17
|
+
export declare const setClient: (client: AuthClient) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Retrieves the bonded auth client, throwing if none is configured.
|
|
20
|
+
*
|
|
21
|
+
* @returns The bonded auth client.
|
|
22
|
+
* @throws {Error} If no auth client has been bonded.
|
|
23
|
+
*/
|
|
24
|
+
export declare const getClient: <T extends UserProfile = UserProfile>() => AuthClient<T>;
|
|
25
|
+
/**
|
|
26
|
+
* Checks whether an auth client is currently bonded.
|
|
27
|
+
*
|
|
28
|
+
* @returns `true` if an auth client is bonded.
|
|
29
|
+
*/
|
|
30
|
+
export declare const hasClient: () => boolean;
|
|
31
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAIzD;;;;;GAKG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,UAAU,KAAG,IAE9C,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,WAAW,GAAG,WAAW,OAAK,UAAU,CAAC,CAAC,CAE7E,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,SAAS,QAAO,OAE5B,CAAA"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth client bond accessor.
|
|
3
|
+
*
|
|
4
|
+
* Bond packages call `setClient()` during setup. Application code uses
|
|
5
|
+
* `getClient()` to access login, logout, register, token management,
|
|
6
|
+
* and auth state subscription.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { bond, isBonded, require as bondRequire } from '@molecule/app-bond';
|
|
11
|
+
const BOND_TYPE = 'auth-client';
|
|
12
|
+
/**
|
|
13
|
+
* Registers an auth client as the active singleton. Called by bond
|
|
14
|
+
* packages during application startup.
|
|
15
|
+
*
|
|
16
|
+
* @param client - The auth client implementation to bond.
|
|
17
|
+
*/
|
|
18
|
+
export const setClient = (client) => {
|
|
19
|
+
bond(BOND_TYPE, client);
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Retrieves the bonded auth client, throwing if none is configured.
|
|
23
|
+
*
|
|
24
|
+
* @returns The bonded auth client.
|
|
25
|
+
* @throws {Error} If no auth client has been bonded.
|
|
26
|
+
*/
|
|
27
|
+
export const getClient = () => {
|
|
28
|
+
return bondRequire(BOND_TYPE);
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Checks whether an auth client is currently bonded.
|
|
32
|
+
*
|
|
33
|
+
* @returns `true` if an auth client is bonded.
|
|
34
|
+
*/
|
|
35
|
+
export const hasClient = () => {
|
|
36
|
+
return isBonded(BOND_TYPE);
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAI3E,MAAM,SAAS,GAAG,aAAa,CAAA;AAE/B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAkB,EAAQ,EAAE;IACpD,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;AACzB,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,GAAuD,EAAE;IAChF,OAAO,WAAW,CAAgB,SAAS,CAAC,CAAA;AAC9C,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,GAAY,EAAE;IACrC,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAA;AAC5B,CAAC,CAAA"}
|
package/dist/token.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token management utilities for authentication.
|
|
3
|
+
*
|
|
4
|
+
* Provides token storage, JWT parsing, and expiration checking.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import type { StorageAdapter, TokenStorage } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Creates a token storage implementation backed by either in-memory
|
|
11
|
+
* storage or a custom `StorageAdapter`.
|
|
12
|
+
*
|
|
13
|
+
* @param storage - `'memory'` for in-memory storage (lost on refresh),
|
|
14
|
+
* or a `StorageAdapter` for persistent storage.
|
|
15
|
+
* @param prefix - Key prefix for storage items (default: `'molecule:auth:'`).
|
|
16
|
+
* @returns A `TokenStorage` instance.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // In-memory storage (default)
|
|
21
|
+
* const storage = createTokenStorage('memory')
|
|
22
|
+
*
|
|
23
|
+
* // Custom storage adapter from @molecule/app-storage
|
|
24
|
+
* import { getProvider } from '@molecule/app-storage'
|
|
25
|
+
* const provider = getProvider()
|
|
26
|
+
* const storage = createTokenStorage({
|
|
27
|
+
* getItem: (key) => provider.get(key),
|
|
28
|
+
* setItem: (key, value) => provider.set(key, value),
|
|
29
|
+
* removeItem: (key) => provider.remove(key),
|
|
30
|
+
* })
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare const createTokenStorage: (storage?: "memory" | StorageAdapter, prefix?: string) => TokenStorage;
|
|
34
|
+
/**
|
|
35
|
+
* Parses a JWT token payload without verification (base64-decodes
|
|
36
|
+
* the payload segment).
|
|
37
|
+
*
|
|
38
|
+
* @param token - The raw JWT string (header.payload.signature).
|
|
39
|
+
* @returns The decoded payload object, or `null` if parsing fails.
|
|
40
|
+
*/
|
|
41
|
+
export declare const parseJWT: <T = Record<string, unknown>>(token: string) => T | null;
|
|
42
|
+
/**
|
|
43
|
+
* Checks if a JWT token is expired (or will expire within the buffer window).
|
|
44
|
+
*
|
|
45
|
+
* @param token - The raw JWT string.
|
|
46
|
+
* @param bufferSeconds - Seconds before actual expiry to consider the token expired (default: 0).
|
|
47
|
+
* @returns `true` if the token is expired or lacks an `exp` claim.
|
|
48
|
+
*/
|
|
49
|
+
export declare const isTokenExpired: (token: string, bufferSeconds?: number) => boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Returns the expiration timestamp of a JWT token in milliseconds.
|
|
52
|
+
*
|
|
53
|
+
* @param token - The raw JWT string.
|
|
54
|
+
* @returns The expiration time in ms since epoch, or `null` if the token has no `exp` claim.
|
|
55
|
+
*/
|
|
56
|
+
export declare const getTokenExpiration: (token: string) => number | null;
|
|
57
|
+
//# sourceMappingURL=token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAe,MAAM,YAAY,CAAA;AAE3E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAS,QAAQ,GAAG,cAAyB,EAC7C,SAAQ,MAAyB,KAChC,YAoDF,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,MAAM,KAAG,CAAC,GAAG,IAWzE,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,EAAE,gBAAe,MAAU,KAAG,OAMzE,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,IAI3D,CAAA"}
|
package/dist/token.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token management utilities for authentication.
|
|
3
|
+
*
|
|
4
|
+
* Provides token storage, JWT parsing, and expiration checking.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Creates a token storage implementation backed by either in-memory
|
|
10
|
+
* storage or a custom `StorageAdapter`.
|
|
11
|
+
*
|
|
12
|
+
* @param storage - `'memory'` for in-memory storage (lost on refresh),
|
|
13
|
+
* or a `StorageAdapter` for persistent storage.
|
|
14
|
+
* @param prefix - Key prefix for storage items (default: `'molecule:auth:'`).
|
|
15
|
+
* @returns A `TokenStorage` instance.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* // In-memory storage (default)
|
|
20
|
+
* const storage = createTokenStorage('memory')
|
|
21
|
+
*
|
|
22
|
+
* // Custom storage adapter from @molecule/app-storage
|
|
23
|
+
* import { getProvider } from '@molecule/app-storage'
|
|
24
|
+
* const provider = getProvider()
|
|
25
|
+
* const storage = createTokenStorage({
|
|
26
|
+
* getItem: (key) => provider.get(key),
|
|
27
|
+
* setItem: (key, value) => provider.set(key, value),
|
|
28
|
+
* removeItem: (key) => provider.remove(key),
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const createTokenStorage = (storage = 'memory', prefix = 'molecule:auth:') => {
|
|
33
|
+
const memoryStore = {};
|
|
34
|
+
// Determine storage adapter
|
|
35
|
+
let adapter = null;
|
|
36
|
+
if (typeof storage === 'object') {
|
|
37
|
+
adapter = storage;
|
|
38
|
+
}
|
|
39
|
+
const get = (key) => {
|
|
40
|
+
if (adapter) {
|
|
41
|
+
return adapter.getItem(prefix + key);
|
|
42
|
+
}
|
|
43
|
+
return memoryStore[key] ?? null;
|
|
44
|
+
};
|
|
45
|
+
const set = (key, value) => {
|
|
46
|
+
if (adapter) {
|
|
47
|
+
if (value === null) {
|
|
48
|
+
adapter.removeItem(prefix + key);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
adapter.setItem(prefix + key, value);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
memoryStore[key] = value;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
getAccessToken: () => get('accessToken'),
|
|
60
|
+
setAccessToken: (token) => set('accessToken', token),
|
|
61
|
+
getRefreshToken: () => get('refreshToken'),
|
|
62
|
+
setRefreshToken: (token) => set('refreshToken', token),
|
|
63
|
+
getUser: () => {
|
|
64
|
+
const data = get('user');
|
|
65
|
+
if (!data)
|
|
66
|
+
return null;
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(data);
|
|
69
|
+
}
|
|
70
|
+
catch (_error) {
|
|
71
|
+
// Stored value is not valid JSON (corrupted/stale); returning null is safe
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
setUser: (user) => {
|
|
76
|
+
set('user', user ? JSON.stringify(user) : null);
|
|
77
|
+
},
|
|
78
|
+
clear: () => {
|
|
79
|
+
set('accessToken', null);
|
|
80
|
+
set('refreshToken', null);
|
|
81
|
+
set('user', null);
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Parses a JWT token payload without verification (base64-decodes
|
|
87
|
+
* the payload segment).
|
|
88
|
+
*
|
|
89
|
+
* @param token - The raw JWT string (header.payload.signature).
|
|
90
|
+
* @returns The decoded payload object, or `null` if parsing fails.
|
|
91
|
+
*/
|
|
92
|
+
export const parseJWT = (token) => {
|
|
93
|
+
try {
|
|
94
|
+
const parts = token.split('.');
|
|
95
|
+
if (parts.length !== 3)
|
|
96
|
+
return null;
|
|
97
|
+
const payload = parts[1];
|
|
98
|
+
const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));
|
|
99
|
+
return JSON.parse(decoded);
|
|
100
|
+
}
|
|
101
|
+
catch (_error) {
|
|
102
|
+
// Malformed base64 or invalid JSON payload; returning null is the documented contract
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Checks if a JWT token is expired (or will expire within the buffer window).
|
|
108
|
+
*
|
|
109
|
+
* @param token - The raw JWT string.
|
|
110
|
+
* @param bufferSeconds - Seconds before actual expiry to consider the token expired (default: 0).
|
|
111
|
+
* @returns `true` if the token is expired or lacks an `exp` claim.
|
|
112
|
+
*/
|
|
113
|
+
export const isTokenExpired = (token, bufferSeconds = 0) => {
|
|
114
|
+
const payload = parseJWT(token);
|
|
115
|
+
if (!payload || !payload.exp)
|
|
116
|
+
return true;
|
|
117
|
+
const expiresAt = payload.exp * 1000;
|
|
118
|
+
const now = Date.now() + bufferSeconds * 1000;
|
|
119
|
+
return now >= expiresAt;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* Returns the expiration timestamp of a JWT token in milliseconds.
|
|
123
|
+
*
|
|
124
|
+
* @param token - The raw JWT string.
|
|
125
|
+
* @returns The expiration time in ms since epoch, or `null` if the token has no `exp` claim.
|
|
126
|
+
*/
|
|
127
|
+
export const getTokenExpiration = (token) => {
|
|
128
|
+
const payload = parseJWT(token);
|
|
129
|
+
if (!payload || !payload.exp)
|
|
130
|
+
return null;
|
|
131
|
+
return payload.exp * 1000;
|
|
132
|
+
};
|
|
133
|
+
//# sourceMappingURL=token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"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"}
|