simple-m-auth 1.0.2 → 1.0.4
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 +54 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -1
- package/dist/crypto.d.ts +8 -0
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +60 -0
- package/dist/crypto.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/session.d.ts +12 -5
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +61 -12
- package/dist/session.js.map +1 -1
- package/dist/types.d.ts +41 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,20 +52,20 @@ export const authConfig: AuthConfig = {
|
|
|
52
52
|
},
|
|
53
53
|
|
|
54
54
|
cookie: {
|
|
55
|
-
// Example for Next.js App Router
|
|
56
|
-
set: async (name, value, options) => {
|
|
55
|
+
// Example for Next.js App Router (context not needed)
|
|
56
|
+
set: async (name, value, options, ctx?) => {
|
|
57
57
|
const { cookies } = await import('next/headers');
|
|
58
58
|
const cookieStore = await cookies();
|
|
59
59
|
cookieStore.set(name, value, options);
|
|
60
60
|
},
|
|
61
61
|
|
|
62
|
-
get: async (name) => {
|
|
62
|
+
get: async (name, ctx?) => {
|
|
63
63
|
const { cookies } = await import('next/headers');
|
|
64
64
|
const cookieStore = await cookies();
|
|
65
65
|
return cookieStore.get(name)?.value ?? null;
|
|
66
66
|
},
|
|
67
67
|
|
|
68
|
-
delete: async (name) => {
|
|
68
|
+
delete: async (name, ctx?) => {
|
|
69
69
|
const { cookies } = await import('next/headers');
|
|
70
70
|
const cookieStore = await cookies();
|
|
71
71
|
cookieStore.delete(name);
|
|
@@ -107,6 +107,9 @@ model Session {
|
|
|
107
107
|
```typescript
|
|
108
108
|
import { createSession, validateSession, getUser, deleteSession } from 'simple-m-auth';
|
|
109
109
|
|
|
110
|
+
// All functions accept an optional context parameter for frameworks that need it
|
|
111
|
+
// e.g., createSession(userId, ctx), getUser(ctx), validateSession(ctx), deleteSession(ctx)
|
|
112
|
+
|
|
110
113
|
// Login - create session after verifying password
|
|
111
114
|
async function login(userId: string) {
|
|
112
115
|
const session = await createSession(userId);
|
|
@@ -136,6 +139,53 @@ async function logout() {
|
|
|
136
139
|
}
|
|
137
140
|
```
|
|
138
141
|
|
|
142
|
+
## JWT Support (Stateless Tokens)
|
|
143
|
+
|
|
144
|
+
Enable short-lived JWTs for faster authentication. Based on [Lucia Auth stateless tokens](https://lucia-auth.com/sessions/stateless-tokens) principles:
|
|
145
|
+
|
|
146
|
+
- JWTs are short-lived (5 minutes default)
|
|
147
|
+
- `getUser()` checks JWT first (no DB lookup if valid)
|
|
148
|
+
- Falls back to session validation if JWT expired
|
|
149
|
+
- Auto-refreshes JWT when session is valid
|
|
150
|
+
|
|
151
|
+
Add `jwt` config:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
export const authConfig: AuthConfig = {
|
|
155
|
+
db: { /* ... */ },
|
|
156
|
+
cookie: { /* ... */ },
|
|
157
|
+
|
|
158
|
+
jwt: {
|
|
159
|
+
secret: 'your-32-character-or-longer-secret-key',
|
|
160
|
+
expiresIn: 300, // 5 minutes (default)
|
|
161
|
+
|
|
162
|
+
getJwtToken: (ctx?) => {
|
|
163
|
+
// Get from Authorization header
|
|
164
|
+
return ctx?.req?.headers.get('Authorization')?.replace('Bearer ', '') ?? null;
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
setJwtToken: (token, ctx?) => {
|
|
168
|
+
// Set in response header
|
|
169
|
+
ctx?.res?.headers.set('Authorization', `Bearer ${token}`);
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Pass context to functions:
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// With context (for frameworks like Express, Hono, etc.)
|
|
179
|
+
const ctx = { req, res };
|
|
180
|
+
const session = await createSession(userId, ctx);
|
|
181
|
+
const user = await getUser(ctx);
|
|
182
|
+
const valid = await validateSession(ctx);
|
|
183
|
+
await deleteSession(ctx);
|
|
184
|
+
|
|
185
|
+
// Without context (Next.js App Router, or when using closures)
|
|
186
|
+
const user = await getUser();
|
|
187
|
+
```
|
|
188
|
+
|
|
139
189
|
## Next.js Example
|
|
140
190
|
|
|
141
191
|
```typescript
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAa7C,wBAAsB,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,CA+BtD;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAa7C,wBAAsB,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,CA+BtD;AA8CD,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAGlD;AAED,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
|
package/dist/config.js
CHANGED
|
@@ -60,6 +60,18 @@ function validateConfig(config) {
|
|
|
60
60
|
if (typeof config.cookie.delete !== 'function') {
|
|
61
61
|
throw new Error('AuthConfig.cookie.delete must be a function');
|
|
62
62
|
}
|
|
63
|
+
// JWT validation (optional, but if provided must be complete)
|
|
64
|
+
if (config.jwt) {
|
|
65
|
+
if (typeof config.jwt.secret !== 'string' || config.jwt.secret.length < 32) {
|
|
66
|
+
throw new Error('AuthConfig.jwt.secret must be a string of at least 32 characters');
|
|
67
|
+
}
|
|
68
|
+
if (typeof config.jwt.getJwtToken !== 'function') {
|
|
69
|
+
throw new Error('AuthConfig.jwt.getJwtToken must be a function');
|
|
70
|
+
}
|
|
71
|
+
if (typeof config.jwt.setJwtToken !== 'function') {
|
|
72
|
+
throw new Error('AuthConfig.jwt.setJwtToken must be a function');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
63
75
|
}
|
|
64
76
|
// Allow manual config setting (useful for testing or non-standard setups)
|
|
65
77
|
export function setConfig(config) {
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/crypto.d.ts
CHANGED
|
@@ -5,4 +5,12 @@ export declare function parseToken(token: string): {
|
|
|
5
5
|
id: string;
|
|
6
6
|
secret: string;
|
|
7
7
|
} | null;
|
|
8
|
+
export interface JwtPayload {
|
|
9
|
+
sessionId: string;
|
|
10
|
+
userId: string;
|
|
11
|
+
iat: number;
|
|
12
|
+
exp: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function signJwt(payload: JwtPayload, secret: string): Promise<string>;
|
|
15
|
+
export declare function verifyJwt(token: string, secret: string): Promise<JwtPayload | null>;
|
|
8
16
|
//# sourceMappingURL=crypto.d.ts.map
|
package/dist/crypto.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAEA,wBAAgB,0BAA0B,IAAI,MAAM,CASnD;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAIpE;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CASvE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAM/E"}
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAEA,wBAAgB,0BAA0B,IAAI,MAAM,CASnD;AAED,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAIpE;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CASvE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAM/E;AA2BD,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAID,wBAAsB,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWlF;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA0CzF"}
|
package/dist/crypto.js
CHANGED
|
@@ -30,4 +30,64 @@ export function parseToken(token) {
|
|
|
30
30
|
}
|
|
31
31
|
return { id: parts[0], secret: parts[1] };
|
|
32
32
|
}
|
|
33
|
+
// JWT utilities using HMAC SHA-256
|
|
34
|
+
function base64UrlEncode(data) {
|
|
35
|
+
const base64 = btoa(String.fromCharCode(...data));
|
|
36
|
+
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
37
|
+
}
|
|
38
|
+
function base64UrlDecode(str) {
|
|
39
|
+
const base64 = str.replace(/-/g, '+').replace(/_/g, '/');
|
|
40
|
+
const padded = base64 + '='.repeat((4 - (base64.length % 4)) % 4);
|
|
41
|
+
const binary = atob(padded);
|
|
42
|
+
return Uint8Array.from(binary, (c) => c.charCodeAt(0));
|
|
43
|
+
}
|
|
44
|
+
async function getHmacKey(secret) {
|
|
45
|
+
const encoder = new TextEncoder();
|
|
46
|
+
return crypto.subtle.importKey('raw', encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign', 'verify']);
|
|
47
|
+
}
|
|
48
|
+
const JWT_HEADER = { alg: 'HS256', typ: 'JWT' };
|
|
49
|
+
export async function signJwt(payload, secret) {
|
|
50
|
+
const encoder = new TextEncoder();
|
|
51
|
+
const headerB64 = base64UrlEncode(encoder.encode(JSON.stringify(JWT_HEADER)));
|
|
52
|
+
const payloadB64 = base64UrlEncode(encoder.encode(JSON.stringify(payload)));
|
|
53
|
+
const data = `${headerB64}.${payloadB64}`;
|
|
54
|
+
const key = await getHmacKey(secret);
|
|
55
|
+
const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(data));
|
|
56
|
+
return `${data}.${base64UrlEncode(new Uint8Array(signature))}`;
|
|
57
|
+
}
|
|
58
|
+
export async function verifyJwt(token, secret) {
|
|
59
|
+
const parts = token.split('.');
|
|
60
|
+
if (parts.length !== 3) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
64
|
+
try {
|
|
65
|
+
// Verify header
|
|
66
|
+
const header = JSON.parse(new TextDecoder().decode(base64UrlDecode(headerB64)));
|
|
67
|
+
if (header.alg !== 'HS256' || header.typ !== 'JWT') {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
// Verify signature
|
|
71
|
+
const key = await getHmacKey(secret);
|
|
72
|
+
const data = `${headerB64}.${payloadB64}`;
|
|
73
|
+
const signature = base64UrlDecode(signatureB64);
|
|
74
|
+
const encoder = new TextEncoder();
|
|
75
|
+
const signatureArray = new Uint8Array(signature);
|
|
76
|
+
const isValid = await crypto.subtle.verify('HMAC', key, signatureArray, encoder.encode(data));
|
|
77
|
+
if (!isValid) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
// Parse and validate payload
|
|
81
|
+
const payload = JSON.parse(new TextDecoder().decode(base64UrlDecode(payloadB64)));
|
|
82
|
+
// Check expiration
|
|
83
|
+
const now = Math.floor(Date.now() / 1000);
|
|
84
|
+
if (payload.exp < now) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
return payload;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
33
93
|
//# sourceMappingURL=crypto.js.map
|
package/dist/crypto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG,kCAAkC,CAAC,CAAC,qCAAqC;AAE1F,MAAM,UAAU,0BAA0B;IACxC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB;IACxD,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAE9B,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAc;IAC7C,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACtE,OAAO,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,CAAa,EAAE,CAAa;IAC5D,IAAI,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5C,CAAC"}
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type { AuthConfig, Session, SessionWithToken, CookieOptions, } from './types.js';
|
|
1
|
+
export type { AuthConfig, Session, SessionWithToken, CookieOptions, CookieConfig, JwtConfig, JwtPayload, } from './types.js';
|
|
2
2
|
export { createSession, validateSession, getUser, deleteSession, deleteSessionById, } from './session.js';
|
|
3
3
|
export { setConfig, clearConfig } from './config.js';
|
|
4
|
-
export { generateSecureRandomString, hashSecret, constantTimeEqual, } from './crypto.js';
|
|
4
|
+
export { generateSecureRandomString, hashSecret, constantTimeEqual, signJwt, verifyJwt, } from './crypto.js';
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,UAAU,EACV,OAAO,EACP,gBAAgB,EAChB,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,UAAU,EACV,OAAO,EACP,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,SAAS,EACT,UAAU,GACX,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,aAAa,EACb,eAAe,EACf,OAAO,EACP,aAAa,EACb,iBAAiB,GAClB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGrD,OAAO,EACL,0BAA0B,EAC1B,UAAU,EACV,iBAAiB,EACjB,OAAO,EACP,SAAS,GACV,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,5 +3,5 @@ export { createSession, validateSession, getUser, deleteSession, deleteSessionBy
|
|
|
3
3
|
// Config utilities (for advanced use)
|
|
4
4
|
export { setConfig, clearConfig } from './config.js';
|
|
5
5
|
// Crypto utilities (if someone needs them)
|
|
6
|
-
export { generateSecureRandomString, hashSecret, constantTimeEqual, } from './crypto.js';
|
|
6
|
+
export { generateSecureRandomString, hashSecret, constantTimeEqual, signJwt, verifyJwt, } from './crypto.js';
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,oBAAoB;AACpB,OAAO,EACL,aAAa,EACb,eAAe,EACf,OAAO,EACP,aAAa,EACb,iBAAiB,GAClB,MAAM,cAAc,CAAC;AAEtB,sCAAsC;AACtC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAErD,2CAA2C;AAC3C,OAAO,EACL,0BAA0B,EAC1B,UAAU,EACV,iBAAiB,EACjB,OAAO,EACP,SAAS,GACV,MAAM,aAAa,CAAC"}
|
package/dist/session.d.ts
CHANGED
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
import type { Session, SessionWithToken } from './types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Create a new session for a user and set the cookie
|
|
4
|
+
* @param userId - The user ID to create a session for
|
|
5
|
+
* @param context - Optional context to pass to JWT handlers (e.g., request/response objects)
|
|
4
6
|
*/
|
|
5
|
-
export declare function createSession(userId: string): Promise<SessionWithToken>;
|
|
7
|
+
export declare function createSession<TContext = unknown>(userId: string, context?: TContext): Promise<SessionWithToken>;
|
|
6
8
|
/**
|
|
7
9
|
* Validate the current session from cookie
|
|
8
10
|
* Returns the session if valid, null otherwise
|
|
11
|
+
* @param context - Optional context to pass to cookie handlers
|
|
9
12
|
*/
|
|
10
|
-
export declare function validateSession(): Promise<Session | null>;
|
|
13
|
+
export declare function validateSession<TContext = unknown>(context?: TContext): Promise<Session | null>;
|
|
11
14
|
/**
|
|
12
15
|
* Get the current user from session
|
|
13
|
-
*
|
|
16
|
+
* When JWT is enabled, first checks JWT for fast validation.
|
|
17
|
+
* If JWT is expired/invalid, falls back to session validation and refreshes JWT.
|
|
18
|
+
* Returns null if no valid session or user not found.
|
|
19
|
+
* @param context - Optional context to pass to JWT handlers (e.g., request/response objects)
|
|
14
20
|
*/
|
|
15
|
-
export declare function getUser<TUser = any>(): Promise<TUser | null>;
|
|
21
|
+
export declare function getUser<TUser = any, TContext = unknown>(context?: TContext): Promise<TUser | null>;
|
|
16
22
|
/**
|
|
17
23
|
* Delete the current session and clear cookie
|
|
24
|
+
* @param context - Optional context to pass to cookie handlers
|
|
18
25
|
*/
|
|
19
|
-
export declare function deleteSession(): Promise<void>;
|
|
26
|
+
export declare function deleteSession<TContext = unknown>(context?: TContext): Promise<void>;
|
|
20
27
|
/**
|
|
21
28
|
* Delete a specific session by ID (useful for "logout all devices")
|
|
22
29
|
*/
|
package/dist/session.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,gBAAgB,EAAc,MAAM,YAAY,CAAC;AAkCxE;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,QAAQ,GAAG,OAAO,EACpD,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,gBAAgB,CAAC,CA2C3B;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,QAAQ,GAAG,OAAO,EACtD,OAAO,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAoCzB;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,KAAK,GAAG,GAAG,EAAE,QAAQ,GAAG,OAAO,EAC3D,OAAO,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CA2CvB;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,QAAQ,GAAG,OAAO,EACpD,OAAO,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGxE"}
|
package/dist/session.js
CHANGED
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
import { loadConfig } from './config.js';
|
|
2
|
-
import { generateSecureRandomString, hashSecret, constantTimeEqual, parseToken, } from './crypto.js';
|
|
2
|
+
import { generateSecureRandomString, hashSecret, constantTimeEqual, parseToken, signJwt, verifyJwt, } from './crypto.js';
|
|
3
3
|
const DEFAULT_EXPIRES_IN = 60 * 60 * 24; // 24 hours
|
|
4
4
|
const DEFAULT_COOKIE_NAME = 'session_token';
|
|
5
|
+
const DEFAULT_JWT_EXPIRES_IN = 60 * 5; // 5 minutes (short-lived per Lucia Auth)
|
|
6
|
+
/**
|
|
7
|
+
* Create a JWT for a session
|
|
8
|
+
*/
|
|
9
|
+
async function createJwtForSession(sessionId, userId, secret, expiresIn) {
|
|
10
|
+
const now = Math.floor(Date.now() / 1000);
|
|
11
|
+
const payload = {
|
|
12
|
+
sessionId,
|
|
13
|
+
userId,
|
|
14
|
+
iat: now,
|
|
15
|
+
exp: now + expiresIn,
|
|
16
|
+
};
|
|
17
|
+
return signJwt(payload, secret);
|
|
18
|
+
}
|
|
5
19
|
/**
|
|
6
20
|
* Create a new session for a user and set the cookie
|
|
21
|
+
* @param userId - The user ID to create a session for
|
|
22
|
+
* @param context - Optional context to pass to JWT handlers (e.g., request/response objects)
|
|
7
23
|
*/
|
|
8
|
-
export async function createSession(userId) {
|
|
24
|
+
export async function createSession(userId, context) {
|
|
9
25
|
const config = await loadConfig();
|
|
10
26
|
const id = generateSecureRandomString();
|
|
11
27
|
const secret = generateSecureRandomString();
|
|
@@ -33,18 +49,25 @@ export async function createSession(userId) {
|
|
|
33
49
|
secure: true,
|
|
34
50
|
path: '/',
|
|
35
51
|
sameSite: 'lax',
|
|
36
|
-
});
|
|
52
|
+
}, context);
|
|
53
|
+
// Issue JWT if enabled
|
|
54
|
+
if (config.jwt) {
|
|
55
|
+
const jwtExpiresIn = config.jwt.expiresIn ?? DEFAULT_JWT_EXPIRES_IN;
|
|
56
|
+
const jwt = await createJwtForSession(id, userId, config.jwt.secret, jwtExpiresIn);
|
|
57
|
+
await config.jwt.setJwtToken(jwt, context);
|
|
58
|
+
}
|
|
37
59
|
return session;
|
|
38
60
|
}
|
|
39
61
|
/**
|
|
40
62
|
* Validate the current session from cookie
|
|
41
63
|
* Returns the session if valid, null otherwise
|
|
64
|
+
* @param context - Optional context to pass to cookie handlers
|
|
42
65
|
*/
|
|
43
|
-
export async function validateSession() {
|
|
66
|
+
export async function validateSession(context) {
|
|
44
67
|
const config = await loadConfig();
|
|
45
68
|
const cookieName = config.cookieName ?? DEFAULT_COOKIE_NAME;
|
|
46
69
|
const expiresIn = config.sessionExpiresIn ?? DEFAULT_EXPIRES_IN;
|
|
47
|
-
const token = await config.cookie.get(cookieName);
|
|
70
|
+
const token = await config.cookie.get(cookieName, context);
|
|
48
71
|
if (!token) {
|
|
49
72
|
return null;
|
|
50
73
|
}
|
|
@@ -61,7 +84,7 @@ export async function validateSession() {
|
|
|
61
84
|
const sessionAge = now - session.createdAt.getTime();
|
|
62
85
|
if (sessionAge >= expiresIn * 1000) {
|
|
63
86
|
await config.db.deleteSession(session.id);
|
|
64
|
-
await config.cookie.delete(cookieName);
|
|
87
|
+
await config.cookie.delete(cookieName, context);
|
|
65
88
|
return null;
|
|
66
89
|
}
|
|
67
90
|
// Verify secret
|
|
@@ -73,11 +96,36 @@ export async function validateSession() {
|
|
|
73
96
|
}
|
|
74
97
|
/**
|
|
75
98
|
* Get the current user from session
|
|
76
|
-
*
|
|
99
|
+
* When JWT is enabled, first checks JWT for fast validation.
|
|
100
|
+
* If JWT is expired/invalid, falls back to session validation and refreshes JWT.
|
|
101
|
+
* Returns null if no valid session or user not found.
|
|
102
|
+
* @param context - Optional context to pass to JWT handlers (e.g., request/response objects)
|
|
77
103
|
*/
|
|
78
|
-
export async function getUser() {
|
|
104
|
+
export async function getUser(context) {
|
|
79
105
|
const config = await loadConfig();
|
|
80
|
-
|
|
106
|
+
// If JWT is enabled, try JWT first (fast path - no DB lookup)
|
|
107
|
+
if (config.jwt) {
|
|
108
|
+
const jwtToken = await config.jwt.getJwtToken(context);
|
|
109
|
+
if (jwtToken) {
|
|
110
|
+
const payload = await verifyJwt(jwtToken, config.jwt.secret);
|
|
111
|
+
if (payload) {
|
|
112
|
+
// JWT is valid, get user directly without session validation
|
|
113
|
+
return config.db.getUserById(payload.userId);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// JWT missing or invalid - fall back to session validation
|
|
117
|
+
const session = await validateSession(context);
|
|
118
|
+
if (!session) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
// Session is valid - refresh the JWT
|
|
122
|
+
const jwtExpiresIn = config.jwt.expiresIn ?? DEFAULT_JWT_EXPIRES_IN;
|
|
123
|
+
const newJwt = await createJwtForSession(session.id, session.userId, config.jwt.secret, jwtExpiresIn);
|
|
124
|
+
await config.jwt.setJwtToken(newJwt, context);
|
|
125
|
+
return config.db.getUserById(session.userId);
|
|
126
|
+
}
|
|
127
|
+
// No JWT configured - use regular session validation
|
|
128
|
+
const session = await validateSession(context);
|
|
81
129
|
if (!session) {
|
|
82
130
|
return null;
|
|
83
131
|
}
|
|
@@ -85,11 +133,12 @@ export async function getUser() {
|
|
|
85
133
|
}
|
|
86
134
|
/**
|
|
87
135
|
* Delete the current session and clear cookie
|
|
136
|
+
* @param context - Optional context to pass to cookie handlers
|
|
88
137
|
*/
|
|
89
|
-
export async function deleteSession() {
|
|
138
|
+
export async function deleteSession(context) {
|
|
90
139
|
const config = await loadConfig();
|
|
91
140
|
const cookieName = config.cookieName ?? DEFAULT_COOKIE_NAME;
|
|
92
|
-
const token = await config.cookie.get(cookieName);
|
|
141
|
+
const token = await config.cookie.get(cookieName, context);
|
|
93
142
|
if (!token) {
|
|
94
143
|
return;
|
|
95
144
|
}
|
|
@@ -97,7 +146,7 @@ export async function deleteSession() {
|
|
|
97
146
|
if (parsed) {
|
|
98
147
|
await config.db.deleteSession(parsed.id);
|
|
99
148
|
}
|
|
100
|
-
await config.cookie.delete(cookieName);
|
|
149
|
+
await config.cookie.delete(cookieName, context);
|
|
101
150
|
}
|
|
102
151
|
/**
|
|
103
152
|
* Delete a specific session by ID (useful for "logout all devices")
|
package/dist/session.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,0BAA0B,EAC1B,UAAU,EACV,iBAAiB,EACjB,UAAU,
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -14,18 +14,53 @@ export interface CookieOptions {
|
|
|
14
14
|
path: string;
|
|
15
15
|
sameSite: 'lax' | 'strict' | 'none';
|
|
16
16
|
}
|
|
17
|
-
export interface
|
|
17
|
+
export interface JwtPayload {
|
|
18
|
+
sessionId: string;
|
|
19
|
+
userId: string;
|
|
20
|
+
iat: number;
|
|
21
|
+
exp: number;
|
|
22
|
+
}
|
|
23
|
+
export interface JwtConfig<TContext = unknown> {
|
|
24
|
+
/**
|
|
25
|
+
* Secret key for signing JWTs (min 32 characters recommended)
|
|
26
|
+
*/
|
|
27
|
+
secret: string;
|
|
28
|
+
/**
|
|
29
|
+
* JWT lifespan in seconds (default: 300 = 5 minutes)
|
|
30
|
+
* Keep short as per Lucia Auth recommendations
|
|
31
|
+
*/
|
|
32
|
+
expiresIn?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Get JWT from request (e.g., from Authorization header)
|
|
35
|
+
* @param context - Optional context (e.g., request object, headers, etc.)
|
|
36
|
+
*/
|
|
37
|
+
getJwtToken: (context?: TContext) => string | null | Promise<string | null>;
|
|
38
|
+
/**
|
|
39
|
+
* Set JWT in response (e.g., in Authorization header or response body)
|
|
40
|
+
* @param token - The JWT token to set
|
|
41
|
+
* @param context - Optional context (e.g., response object, headers, etc.)
|
|
42
|
+
*/
|
|
43
|
+
setJwtToken: (token: string, context?: TContext) => void | Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
export interface CookieConfig<TContext = unknown> {
|
|
46
|
+
set: (name: string, value: string, options: CookieOptions, context?: TContext) => void | Promise<void>;
|
|
47
|
+
get: (name: string, context?: TContext) => string | null | Promise<string | null>;
|
|
48
|
+
delete: (name: string, context?: TContext) => void | Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
export interface AuthConfig<TUser = any, TContext = unknown> {
|
|
18
51
|
db: {
|
|
19
52
|
insertSession: (session: Session) => Promise<void>;
|
|
20
53
|
getSessionById: (sessionId: string) => Promise<Session | null>;
|
|
21
54
|
deleteSession: (sessionId: string) => Promise<void>;
|
|
22
55
|
getUserById: (userId: string) => Promise<TUser | null>;
|
|
23
56
|
};
|
|
24
|
-
cookie:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
57
|
+
cookie: CookieConfig<TContext>;
|
|
58
|
+
/**
|
|
59
|
+
* Enable stateless JWT tokens for faster user lookups.
|
|
60
|
+
* When enabled, getUser() will first check the JWT before hitting the database.
|
|
61
|
+
* JWTs are short-lived (5 min default) and auto-refresh on valid session.
|
|
62
|
+
*/
|
|
63
|
+
jwt?: JwtConfig;
|
|
29
64
|
sessionExpiresIn?: number;
|
|
30
65
|
cookieName?: string;
|
|
31
66
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,gBAAiB,SAAQ,OAAO;IAC/C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,UAAU,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,gBAAiB,SAAQ,OAAO;IAC/C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAS,CAAC,QAAQ,GAAG,OAAO;IAC3C;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAE5E;;;;OAIG;IACH,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1E;AAED,MAAM,WAAW,YAAY,CAAC,QAAQ,GAAG,OAAO;IAC9C,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvG,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAClF,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpE;AAED,MAAM,WAAW,UAAU,CAAC,KAAK,GAAG,GAAG,EAAE,QAAQ,GAAG,OAAO;IACzD,EAAE,EAAE;QACF,aAAa,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACnD,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;QAC/D,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACpD,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;KACxD,CAAC;IAEF,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;IAE/B;;;;OAIG;IACH,GAAG,CAAC,EAAE,SAAS,CAAC;IAEhB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
|