@drawbridge/drawbridge-utils 0.0.45 → 0.0.48

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.
@@ -29,7 +29,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  // lib/oauth/index.js
30
30
  var oauth_exports = {};
31
31
  __export(oauth_exports, {
32
+ clients: () => clients,
32
33
  compare: () => compare,
34
+ cookieOptions: () => cookieOptions,
35
+ cookies: () => cookies,
33
36
  createOAuthClient: () => createOAuthClient,
34
37
  developer: () => developer,
35
38
  developerOptions: () => developerOptions,
@@ -37,10 +40,14 @@ __export(oauth_exports, {
37
40
  hashToken: () => hashToken,
38
41
  intersect: () => intersect,
39
42
  isDeveloperAllowed: () => isDeveloperAllowed,
43
+ lifetimes: () => lifetimes,
44
+ menuEndpoint: () => menuEndpoint,
45
+ otcContexts: () => otcContexts,
40
46
  parse: () => parse,
41
47
  scopeLabels: () => scopeLabels,
42
48
  scopeOptions: () => scopeOptions,
43
49
  scopes: () => scopes,
50
+ tokenTypes: () => tokenTypes,
44
51
  validate: () => validate
45
52
  });
46
53
  module.exports = __toCommonJS(oauth_exports);
@@ -68,6 +75,47 @@ var compare = (a, b) => {
68
75
  };
69
76
 
70
77
  // lib/oauth/index.js
78
+ var cookies = {
79
+ csrf: "drawbridge.csrf",
80
+ refresh: "drawbridge.refresh",
81
+ session: "drawbridge.session"
82
+ };
83
+ var clients = {
84
+ dashboard: "drawbridge-dashboard",
85
+ share: "drawbridge-share"
86
+ };
87
+ var lifetimes = {
88
+ access: 60 * 60,
89
+ // 1 hour
90
+ authorizationCode: 10 * 60,
91
+ // 10 minutes
92
+ code: 15 * 60,
93
+ // 15 minutes (email OTC)
94
+ refresh: 30 * 24 * 60 * 60
95
+ // 30 days
96
+ };
97
+ var tokenTypes = {
98
+ access: "access",
99
+ oauthState: "oauth.state",
100
+ pat: "pat",
101
+ refresh: "refresh"
102
+ };
103
+ var otcContexts = {
104
+ oauthAuthorize: "oauth.authorize",
105
+ signin: "signin",
106
+ signup: "signup"
107
+ };
108
+ var cookieOptions = ({
109
+ expiresAt,
110
+ sameSite = "lax"
111
+ } = {}) => ({
112
+ httpOnly: true,
113
+ path: "/",
114
+ sameSite,
115
+ secure: process.env.NODE_ENV !== "development",
116
+ ...expiresAt && { expires: new Date(expiresAt) }
117
+ });
118
+ var menuEndpoint = (type, id) => "/menu/" + type + (id ? "/" + id : "");
71
119
  var scopes = [
72
120
  "profile:read",
73
121
  "profile:write",
@@ -209,7 +257,10 @@ var createOAuthClient = ({
209
257
  };
210
258
  // Annotate the CommonJS export names for ESM import in node:
211
259
  0 && (module.exports = {
260
+ clients,
212
261
  compare,
262
+ cookieOptions,
263
+ cookies,
213
264
  createOAuthClient,
214
265
  developer,
215
266
  developerOptions,
@@ -217,9 +268,13 @@ var createOAuthClient = ({
217
268
  hashToken,
218
269
  intersect,
219
270
  isDeveloperAllowed,
271
+ lifetimes,
272
+ menuEndpoint,
273
+ otcContexts,
220
274
  parse,
221
275
  scopeLabels,
222
276
  scopeOptions,
223
277
  scopes,
278
+ tokenTypes,
224
279
  validate
225
280
  });
@@ -10,8 +10,74 @@ import 'crypto';
10
10
  // - parse, validate, intersect, isDeveloperAllowed: scope set operations
11
11
  // - hashToken, generateToken, compare: opaque-token primitives
12
12
  // - createOAuthClient: cached client_credentials access token getter
13
+ // - cookies, clients: shared identifier constants so cookie + first-party
14
+ // client names stay in lockstep across repos (api/middleware, api/auth,
15
+ // app-web BFF, sync WS handshake, seed scripts)
13
16
 
14
17
 
18
+ // ─────────────────────────────────────────────────────────────────────────
19
+ // Shared identifier constants — every repo reads from here so the strings
20
+ // stay aligned. Adding a new cookie or first-party client means one edit
21
+ // in this file followed by a utils bump downstream.
22
+ // ─────────────────────────────────────────────────────────────────────────
23
+
24
+ const cookies = {
25
+ csrf : 'drawbridge.csrf',
26
+ refresh : 'drawbridge.refresh',
27
+ session : 'drawbridge.session'
28
+ };
29
+
30
+ const clients = {
31
+ dashboard : 'drawbridge-dashboard',
32
+ share : 'drawbridge-share'
33
+ };
34
+
35
+ // Token / authorization-code / OTC lifetimes in seconds (the OAuth spec's
36
+ // unit for `expires_in`). Multiply by 1000 when feeding to JS Date math.
37
+ const lifetimes = {
38
+ access : 60 * 60, // 1 hour
39
+ authorizationCode : 10 * 60, // 10 minutes
40
+ code : 15 * 60, // 15 minutes (email OTC)
41
+ refresh : 30 * 24 * 60 * 60 // 30 days
42
+ };
43
+
44
+ // Canonical string values for the `token.type` discriminator. Always
45
+ // reference via this map so a future rename (the way oauthState became
46
+ // oauth.state) is a one-line edit here that propagates to every consumer.
47
+ const tokenTypes = {
48
+ access : 'access',
49
+ oauthState : 'oauth.state',
50
+ pat : 'pat',
51
+ refresh : 'refresh'
52
+ };
53
+
54
+ // Canonical string values for the `otc.context` discriminator.
55
+ const otcContexts = {
56
+ oauthAuthorize : 'oauth.authorize',
57
+ signin : 'signin',
58
+ signup : 'signup'
59
+ };
60
+
61
+ // Baseline cookie config dict. Caller adds name/value (and overrides
62
+ // sameSite for refresh cookies that need 'strict'). Both Express
63
+ // (res.cookie( name, value, options )) and Next.js
64
+ // (response.cookies.set({ name, value, ...options })) accept this shape.
65
+ const cookieOptions = ({
66
+ expiresAt,
67
+ sameSite = 'lax'
68
+ } = {}) => ({
69
+ httpOnly : true,
70
+ path : '/',
71
+ sameSite,
72
+ secure : process.env.NODE_ENV !== 'development',
73
+ ...( expiresAt && { expires : new Date( expiresAt ) })
74
+ });
75
+
76
+ // Path builder for the API menu endpoints. Single source of truth for
77
+ // the /menu/<type>(/<id>) shape — drawbridge-api routes and
78
+ // drawbridge-app-web's ProviderLayout wrappers both read from here.
79
+ const menuEndpoint = ( type, id ) => '/menu/' + type + ( id ? '/' + id : '' );
80
+
15
81
  // ─────────────────────────────────────────────────────────────────────────
16
82
  // Scope vocabulary (locked — 15 scopes, 10 in the developer-allowed subset)
17
83
  // ─────────────────────────────────────────────────────────────────────────
@@ -260,4 +326,4 @@ const createOAuthClient = ({
260
326
 
261
327
  };
262
328
 
263
- export { createOAuthClient, developer, developerOptions, generateToken, hashToken, intersect, isDeveloperAllowed, parse, scopeLabels, scopeOptions, scopes, validate };
329
+ export { clients, cookieOptions, cookies, createOAuthClient, developer, developerOptions, generateToken, hashToken, intersect, isDeveloperAllowed, lifetimes, menuEndpoint, otcContexts, parse, scopeLabels, scopeOptions, scopes, tokenTypes, validate };
@@ -10,8 +10,74 @@ import 'crypto';
10
10
  // - parse, validate, intersect, isDeveloperAllowed: scope set operations
11
11
  // - hashToken, generateToken, compare: opaque-token primitives
12
12
  // - createOAuthClient: cached client_credentials access token getter
13
+ // - cookies, clients: shared identifier constants so cookie + first-party
14
+ // client names stay in lockstep across repos (api/middleware, api/auth,
15
+ // app-web BFF, sync WS handshake, seed scripts)
13
16
 
14
17
 
18
+ // ─────────────────────────────────────────────────────────────────────────
19
+ // Shared identifier constants — every repo reads from here so the strings
20
+ // stay aligned. Adding a new cookie or first-party client means one edit
21
+ // in this file followed by a utils bump downstream.
22
+ // ─────────────────────────────────────────────────────────────────────────
23
+
24
+ const cookies = {
25
+ csrf : 'drawbridge.csrf',
26
+ refresh : 'drawbridge.refresh',
27
+ session : 'drawbridge.session'
28
+ };
29
+
30
+ const clients = {
31
+ dashboard : 'drawbridge-dashboard',
32
+ share : 'drawbridge-share'
33
+ };
34
+
35
+ // Token / authorization-code / OTC lifetimes in seconds (the OAuth spec's
36
+ // unit for `expires_in`). Multiply by 1000 when feeding to JS Date math.
37
+ const lifetimes = {
38
+ access : 60 * 60, // 1 hour
39
+ authorizationCode : 10 * 60, // 10 minutes
40
+ code : 15 * 60, // 15 minutes (email OTC)
41
+ refresh : 30 * 24 * 60 * 60 // 30 days
42
+ };
43
+
44
+ // Canonical string values for the `token.type` discriminator. Always
45
+ // reference via this map so a future rename (the way oauthState became
46
+ // oauth.state) is a one-line edit here that propagates to every consumer.
47
+ const tokenTypes = {
48
+ access : 'access',
49
+ oauthState : 'oauth.state',
50
+ pat : 'pat',
51
+ refresh : 'refresh'
52
+ };
53
+
54
+ // Canonical string values for the `otc.context` discriminator.
55
+ const otcContexts = {
56
+ oauthAuthorize : 'oauth.authorize',
57
+ signin : 'signin',
58
+ signup : 'signup'
59
+ };
60
+
61
+ // Baseline cookie config dict. Caller adds name/value (and overrides
62
+ // sameSite for refresh cookies that need 'strict'). Both Express
63
+ // (res.cookie( name, value, options )) and Next.js
64
+ // (response.cookies.set({ name, value, ...options })) accept this shape.
65
+ const cookieOptions = ({
66
+ expiresAt,
67
+ sameSite = 'lax'
68
+ } = {}) => ({
69
+ httpOnly : true,
70
+ path : '/',
71
+ sameSite,
72
+ secure : process.env.NODE_ENV !== 'development',
73
+ ...( expiresAt && { expires : new Date( expiresAt ) })
74
+ });
75
+
76
+ // Path builder for the API menu endpoints. Single source of truth for
77
+ // the /menu/<type>(/<id>) shape — drawbridge-api routes and
78
+ // drawbridge-app-web's ProviderLayout wrappers both read from here.
79
+ const menuEndpoint = ( type, id ) => '/menu/' + type + ( id ? '/' + id : '' );
80
+
15
81
  // ─────────────────────────────────────────────────────────────────────────
16
82
  // Scope vocabulary (locked — 15 scopes, 10 in the developer-allowed subset)
17
83
  // ─────────────────────────────────────────────────────────────────────────
@@ -260,4 +326,4 @@ const createOAuthClient = ({
260
326
 
261
327
  };
262
328
 
263
- export { createOAuthClient, developer, developerOptions, generateToken, hashToken, intersect, isDeveloperAllowed, parse, scopeLabels, scopeOptions, scopes, validate };
329
+ export { clients, cookieOptions, cookies, createOAuthClient, developer, developerOptions, generateToken, hashToken, intersect, isDeveloperAllowed, lifetimes, menuEndpoint, otcContexts, parse, scopeLabels, scopeOptions, scopes, tokenTypes, validate };
@@ -21,6 +21,47 @@ var compare = (a, b) => {
21
21
  };
22
22
 
23
23
  // lib/oauth/index.js
24
+ var cookies = {
25
+ csrf: "drawbridge.csrf",
26
+ refresh: "drawbridge.refresh",
27
+ session: "drawbridge.session"
28
+ };
29
+ var clients = {
30
+ dashboard: "drawbridge-dashboard",
31
+ share: "drawbridge-share"
32
+ };
33
+ var lifetimes = {
34
+ access: 60 * 60,
35
+ // 1 hour
36
+ authorizationCode: 10 * 60,
37
+ // 10 minutes
38
+ code: 15 * 60,
39
+ // 15 minutes (email OTC)
40
+ refresh: 30 * 24 * 60 * 60
41
+ // 30 days
42
+ };
43
+ var tokenTypes = {
44
+ access: "access",
45
+ oauthState: "oauth.state",
46
+ pat: "pat",
47
+ refresh: "refresh"
48
+ };
49
+ var otcContexts = {
50
+ oauthAuthorize: "oauth.authorize",
51
+ signin: "signin",
52
+ signup: "signup"
53
+ };
54
+ var cookieOptions = ({
55
+ expiresAt,
56
+ sameSite = "lax"
57
+ } = {}) => ({
58
+ httpOnly: true,
59
+ path: "/",
60
+ sameSite,
61
+ secure: process.env.NODE_ENV !== "development",
62
+ ...expiresAt && { expires: new Date(expiresAt) }
63
+ });
64
+ var menuEndpoint = (type, id) => "/menu/" + type + (id ? "/" + id : "");
24
65
  var scopes = [
25
66
  "profile:read",
26
67
  "profile:write",
@@ -161,7 +202,10 @@ var createOAuthClient = ({
161
202
  };
162
203
  };
163
204
  export {
205
+ clients,
164
206
  compare,
207
+ cookieOptions,
208
+ cookies,
165
209
  createOAuthClient,
166
210
  developer,
167
211
  developerOptions,
@@ -169,9 +213,13 @@ export {
169
213
  hashToken,
170
214
  intersect,
171
215
  isDeveloperAllowed,
216
+ lifetimes,
217
+ menuEndpoint,
218
+ otcContexts,
172
219
  parse,
173
220
  scopeLabels,
174
221
  scopeOptions,
175
222
  scopes,
223
+ tokenTypes,
176
224
  validate
177
225
  };
@@ -59,6 +59,27 @@ var compare = (a, b) => {
59
59
  };
60
60
 
61
61
  // lib/oauth/index.js
62
+ var lifetimes = {
63
+ access: 60 * 60,
64
+ // 1 hour
65
+ authorizationCode: 10 * 60,
66
+ // 10 minutes
67
+ code: 15 * 60,
68
+ // 15 minutes (email OTC)
69
+ refresh: 30 * 24 * 60 * 60
70
+ // 30 days
71
+ };
72
+ var tokenTypes = {
73
+ access: "access",
74
+ oauthState: "oauth.state",
75
+ pat: "pat",
76
+ refresh: "refresh"
77
+ };
78
+ var otcContexts = {
79
+ oauthAuthorize: "oauth.authorize",
80
+ signin: "signin",
81
+ signup: "signup"
82
+ };
62
83
  var scopes = [
63
84
  "profile:read",
64
85
  "profile:write",
@@ -125,9 +146,6 @@ var hashToken = (raw) => hash(raw, process.env.OAUTH_TOKEN_HMAC_KEY);
125
146
  var generateToken = () => generate(32, "base64url");
126
147
 
127
148
  // lib/oauth/server.js
128
- var ACCESS_TOKEN_LIFETIME_SECONDS = 60 * 60;
129
- var REFRESH_TOKEN_LIFETIME_SECONDS = 60 * 60 * 24 * 30;
130
- var AUTHORIZATION_CODE_LIFETIME_MS = 10 * 60 * 1e3;
131
149
  var createOAuthModel = ({ controller }) => ({
132
150
  getClient: async (clientId, clientSecret) => {
133
151
  var _a;
@@ -158,7 +176,7 @@ var createOAuthModel = ({ controller }) => ({
158
176
  saveAuthorizationCode: async (code, client, user) => {
159
177
  const rawCode = code.authorizationCode;
160
178
  const tokenHash = hashToken(rawCode);
161
- const expiresAt = new Date(Date.now() + AUTHORIZATION_CODE_LIFETIME_MS);
179
+ const expiresAt = new Date(Date.now() + lifetimes.authorizationCode * 1e3);
162
180
  await controller.create({
163
181
  collection: "otc",
164
182
  data: {
@@ -166,7 +184,7 @@ var createOAuthModel = ({ controller }) => ({
166
184
  codeChallenge: code.codeChallenge ?? null,
167
185
  codeChallengeMethod: code.codeChallengeMethod ?? null,
168
186
  consumedAt: null,
169
- context: "oauth.authorize",
187
+ context: otcContexts.oauthAuthorize,
170
188
  expiresAt,
171
189
  redirectUri: code.redirectUri ?? null,
172
190
  scopes: code.scope ?? [],
@@ -190,7 +208,7 @@ var createOAuthModel = ({ controller }) => ({
190
208
  collection: "otc",
191
209
  query: {
192
210
  consumedAt: null,
193
- context: "oauth.authorize",
211
+ context: otcContexts.oauthAuthorize,
194
212
  expiresAt: { $gt: now },
195
213
  tokenHash
196
214
  }
@@ -217,7 +235,7 @@ var createOAuthModel = ({ controller }) => ({
217
235
  }
218
236
  },
219
237
  query: {
220
- context: "oauth.authorize",
238
+ context: otcContexts.oauthAuthorize,
221
239
  tokenHash
222
240
  }
223
241
  });
@@ -227,7 +245,7 @@ var createOAuthModel = ({ controller }) => ({
227
245
  const now = /* @__PURE__ */ new Date();
228
246
  const accessRaw = token.accessToken;
229
247
  const accessHash = hashToken(accessRaw);
230
- const accessExpiresAt = token.accessTokenExpiresAt ?? new Date(now.getTime() + ACCESS_TOKEN_LIFETIME_SECONDS * 1e3);
248
+ const accessExpiresAt = token.accessTokenExpiresAt ?? new Date(now.getTime() + lifetimes.access * 1e3);
231
249
  await controller.create({
232
250
  collection: "token",
233
251
  data: {
@@ -243,7 +261,7 @@ var createOAuthModel = ({ controller }) => ({
243
261
  rotatedFrom: null,
244
262
  scopes: token.scope ?? [],
245
263
  tokenHash: accessHash,
246
- type: "access",
264
+ type: tokenTypes.access,
247
265
  user: (user == null ? void 0 : user.id) ?? null
248
266
  }
249
267
  });
@@ -257,7 +275,7 @@ var createOAuthModel = ({ controller }) => ({
257
275
  if (token.refreshToken) {
258
276
  const refreshRaw = token.refreshToken;
259
277
  const refreshHash = hashToken(refreshRaw);
260
- const refreshExpiresAt = token.refreshTokenExpiresAt ?? new Date(now.getTime() + REFRESH_TOKEN_LIFETIME_SECONDS * 1e3);
278
+ const refreshExpiresAt = token.refreshTokenExpiresAt ?? new Date(now.getTime() + lifetimes.refresh * 1e3);
261
279
  await controller.create({
262
280
  collection: "token",
263
281
  data: {
@@ -273,7 +291,7 @@ var createOAuthModel = ({ controller }) => ({
273
291
  rotatedFrom: null,
274
292
  scopes: token.scope ?? [],
275
293
  tokenHash: refreshHash,
276
- type: "refresh",
294
+ type: tokenTypes.refresh,
277
295
  user: (user == null ? void 0 : user.id) ?? null
278
296
  }
279
297
  });
@@ -292,7 +310,7 @@ var createOAuthModel = ({ controller }) => ({
292
310
  expiresAt: { $gt: now },
293
311
  revoked: false,
294
312
  tokenHash,
295
- type: "access"
313
+ type: tokenTypes.access
296
314
  }
297
315
  });
298
316
  if (!record) return false;
@@ -311,7 +329,7 @@ var createOAuthModel = ({ controller }) => ({
311
329
  query: {
312
330
  revoked: false,
313
331
  tokenHash,
314
- type: "refresh"
332
+ type: tokenTypes.refresh
315
333
  }
316
334
  });
317
335
  if (!record) return false;
@@ -346,10 +364,10 @@ var createOAuthModel = ({ controller }) => ({
346
364
  getUserFromClient: (client) => ({ id: client.id, type: "client" })
347
365
  });
348
366
  var createOAuthServer = ({ controller }) => new import_oauth2_server.default({
349
- accessTokenLifetime: ACCESS_TOKEN_LIFETIME_SECONDS,
367
+ accessTokenLifetime: lifetimes.access,
350
368
  allowBearerTokensInQueryString: false,
351
369
  model: createOAuthModel({ controller }),
352
- refreshTokenLifetime: REFRESH_TOKEN_LIFETIME_SECONDS,
370
+ refreshTokenLifetime: lifetimes.refresh,
353
371
  requireClientAuthentication: {
354
372
  authorization_code: true,
355
373
  client_credentials: true,
@@ -1,5 +1,5 @@
1
1
  import OAuth2Server from '@node-oauth/oauth2-server';
2
- import { developer, generateToken, hashToken, intersect } from './index.cjs';
2
+ import { developer, generateToken, hashToken, intersect, tokenTypes, lifetimes, otcContexts } from './index.cjs';
3
3
  import { compare } from '../token.cjs';
4
4
  import 'crypto';
5
5
 
@@ -25,10 +25,6 @@ import 'crypto';
25
25
  // { client, rawSecret } — secret is plaintext, return ONCE.
26
26
 
27
27
 
28
- const ACCESS_TOKEN_LIFETIME_SECONDS = 60 * 60; // 1 hour
29
- const REFRESH_TOKEN_LIFETIME_SECONDS = 60 * 60 * 24 * 30; // 30 days
30
- const AUTHORIZATION_CODE_LIFETIME_MS = 10 * 60 * 1000; // 10 minutes
31
-
32
28
  const createOAuthModel = ({ controller }) => ({
33
29
 
34
30
  getClient : async ( clientId, clientSecret ) => {
@@ -70,7 +66,7 @@ const createOAuthModel = ({ controller }) => ({
70
66
 
71
67
  const rawCode = code.authorizationCode;
72
68
  const tokenHash = hashToken( rawCode );
73
- const expiresAt = new Date( Date.now() + AUTHORIZATION_CODE_LIFETIME_MS );
69
+ const expiresAt = new Date( Date.now() + ( lifetimes.authorizationCode * 1000 ) );
74
70
 
75
71
  await controller.create({
76
72
  collection : 'otc',
@@ -79,7 +75,7 @@ const createOAuthModel = ({ controller }) => ({
79
75
  codeChallenge : code.codeChallenge ?? null,
80
76
  codeChallengeMethod : code.codeChallengeMethod ?? null,
81
77
  consumedAt : null,
82
- context : 'oauth.authorize',
78
+ context : otcContexts.oauthAuthorize,
83
79
  expiresAt,
84
80
  redirectUri : code.redirectUri ?? null,
85
81
  scopes : code.scope ?? [],
@@ -108,7 +104,7 @@ const createOAuthModel = ({ controller }) => ({
108
104
  collection : 'otc',
109
105
  query : {
110
106
  consumedAt : null,
111
- context : 'oauth.authorize',
107
+ context : otcContexts.oauthAuthorize,
112
108
  expiresAt : { $gt : now },
113
109
  tokenHash
114
110
  }
@@ -141,7 +137,7 @@ const createOAuthModel = ({ controller }) => ({
141
137
  }
142
138
  },
143
139
  query : {
144
- context : 'oauth.authorize',
140
+ context : otcContexts.oauthAuthorize,
145
141
  tokenHash
146
142
  }
147
143
  });
@@ -155,7 +151,7 @@ const createOAuthModel = ({ controller }) => ({
155
151
  const now = new Date();
156
152
  const accessRaw = token.accessToken;
157
153
  const accessHash = hashToken( accessRaw );
158
- const accessExpiresAt = token.accessTokenExpiresAt ?? new Date( now.getTime() + ACCESS_TOKEN_LIFETIME_SECONDS * 1000 );
154
+ const accessExpiresAt = token.accessTokenExpiresAt ?? new Date( now.getTime() + lifetimes.access * 1000 );
159
155
 
160
156
  await controller.create({
161
157
  collection : 'token',
@@ -172,7 +168,7 @@ const createOAuthModel = ({ controller }) => ({
172
168
  rotatedFrom : null,
173
169
  scopes : token.scope ?? [],
174
170
  tokenHash : accessHash,
175
- type : 'access',
171
+ type : tokenTypes.access,
176
172
  user : user?.id ?? null
177
173
  }
178
174
  });
@@ -189,7 +185,7 @@ const createOAuthModel = ({ controller }) => ({
189
185
 
190
186
  const refreshRaw = token.refreshToken;
191
187
  const refreshHash = hashToken( refreshRaw );
192
- const refreshExpiresAt = token.refreshTokenExpiresAt ?? new Date( now.getTime() + REFRESH_TOKEN_LIFETIME_SECONDS * 1000 );
188
+ const refreshExpiresAt = token.refreshTokenExpiresAt ?? new Date( now.getTime() + lifetimes.refresh * 1000 );
193
189
 
194
190
  await controller.create({
195
191
  collection : 'token',
@@ -206,7 +202,7 @@ const createOAuthModel = ({ controller }) => ({
206
202
  rotatedFrom : null,
207
203
  scopes : token.scope ?? [],
208
204
  tokenHash : refreshHash,
209
- type : 'refresh',
205
+ type : tokenTypes.refresh,
210
206
  user : user?.id ?? null
211
207
  }
212
208
  });
@@ -230,7 +226,7 @@ const createOAuthModel = ({ controller }) => ({
230
226
  expiresAt : { $gt : now },
231
227
  revoked : false,
232
228
  tokenHash,
233
- type : 'access'
229
+ type : tokenTypes.access
234
230
  }
235
231
  });
236
232
 
@@ -255,7 +251,7 @@ const createOAuthModel = ({ controller }) => ({
255
251
  query : {
256
252
  revoked : false,
257
253
  tokenHash,
258
- type : 'refresh'
254
+ type : tokenTypes.refresh
259
255
  }
260
256
  });
261
257
 
@@ -305,10 +301,10 @@ const createOAuthModel = ({ controller }) => ({
305
301
  });
306
302
 
307
303
  const createOAuthServer = ({ controller }) => new OAuth2Server({
308
- accessTokenLifetime : ACCESS_TOKEN_LIFETIME_SECONDS,
304
+ accessTokenLifetime : lifetimes.access,
309
305
  allowBearerTokensInQueryString : false,
310
306
  model : createOAuthModel({ controller }),
311
- refreshTokenLifetime : REFRESH_TOKEN_LIFETIME_SECONDS,
307
+ refreshTokenLifetime : lifetimes.refresh,
312
308
  requireClientAuthentication : {
313
309
  authorization_code : true,
314
310
  client_credentials : true,
@@ -1,5 +1,5 @@
1
1
  import OAuth2Server from '@node-oauth/oauth2-server';
2
- import { developer, generateToken, hashToken, intersect } from './index.js';
2
+ import { developer, generateToken, hashToken, intersect, tokenTypes, lifetimes, otcContexts } from './index.js';
3
3
  import { compare } from '../token.js';
4
4
  import 'crypto';
5
5
 
@@ -25,10 +25,6 @@ import 'crypto';
25
25
  // { client, rawSecret } — secret is plaintext, return ONCE.
26
26
 
27
27
 
28
- const ACCESS_TOKEN_LIFETIME_SECONDS = 60 * 60; // 1 hour
29
- const REFRESH_TOKEN_LIFETIME_SECONDS = 60 * 60 * 24 * 30; // 30 days
30
- const AUTHORIZATION_CODE_LIFETIME_MS = 10 * 60 * 1000; // 10 minutes
31
-
32
28
  const createOAuthModel = ({ controller }) => ({
33
29
 
34
30
  getClient : async ( clientId, clientSecret ) => {
@@ -70,7 +66,7 @@ const createOAuthModel = ({ controller }) => ({
70
66
 
71
67
  const rawCode = code.authorizationCode;
72
68
  const tokenHash = hashToken( rawCode );
73
- const expiresAt = new Date( Date.now() + AUTHORIZATION_CODE_LIFETIME_MS );
69
+ const expiresAt = new Date( Date.now() + ( lifetimes.authorizationCode * 1000 ) );
74
70
 
75
71
  await controller.create({
76
72
  collection : 'otc',
@@ -79,7 +75,7 @@ const createOAuthModel = ({ controller }) => ({
79
75
  codeChallenge : code.codeChallenge ?? null,
80
76
  codeChallengeMethod : code.codeChallengeMethod ?? null,
81
77
  consumedAt : null,
82
- context : 'oauth.authorize',
78
+ context : otcContexts.oauthAuthorize,
83
79
  expiresAt,
84
80
  redirectUri : code.redirectUri ?? null,
85
81
  scopes : code.scope ?? [],
@@ -108,7 +104,7 @@ const createOAuthModel = ({ controller }) => ({
108
104
  collection : 'otc',
109
105
  query : {
110
106
  consumedAt : null,
111
- context : 'oauth.authorize',
107
+ context : otcContexts.oauthAuthorize,
112
108
  expiresAt : { $gt : now },
113
109
  tokenHash
114
110
  }
@@ -141,7 +137,7 @@ const createOAuthModel = ({ controller }) => ({
141
137
  }
142
138
  },
143
139
  query : {
144
- context : 'oauth.authorize',
140
+ context : otcContexts.oauthAuthorize,
145
141
  tokenHash
146
142
  }
147
143
  });
@@ -155,7 +151,7 @@ const createOAuthModel = ({ controller }) => ({
155
151
  const now = new Date();
156
152
  const accessRaw = token.accessToken;
157
153
  const accessHash = hashToken( accessRaw );
158
- const accessExpiresAt = token.accessTokenExpiresAt ?? new Date( now.getTime() + ACCESS_TOKEN_LIFETIME_SECONDS * 1000 );
154
+ const accessExpiresAt = token.accessTokenExpiresAt ?? new Date( now.getTime() + lifetimes.access * 1000 );
159
155
 
160
156
  await controller.create({
161
157
  collection : 'token',
@@ -172,7 +168,7 @@ const createOAuthModel = ({ controller }) => ({
172
168
  rotatedFrom : null,
173
169
  scopes : token.scope ?? [],
174
170
  tokenHash : accessHash,
175
- type : 'access',
171
+ type : tokenTypes.access,
176
172
  user : user?.id ?? null
177
173
  }
178
174
  });
@@ -189,7 +185,7 @@ const createOAuthModel = ({ controller }) => ({
189
185
 
190
186
  const refreshRaw = token.refreshToken;
191
187
  const refreshHash = hashToken( refreshRaw );
192
- const refreshExpiresAt = token.refreshTokenExpiresAt ?? new Date( now.getTime() + REFRESH_TOKEN_LIFETIME_SECONDS * 1000 );
188
+ const refreshExpiresAt = token.refreshTokenExpiresAt ?? new Date( now.getTime() + lifetimes.refresh * 1000 );
193
189
 
194
190
  await controller.create({
195
191
  collection : 'token',
@@ -206,7 +202,7 @@ const createOAuthModel = ({ controller }) => ({
206
202
  rotatedFrom : null,
207
203
  scopes : token.scope ?? [],
208
204
  tokenHash : refreshHash,
209
- type : 'refresh',
205
+ type : tokenTypes.refresh,
210
206
  user : user?.id ?? null
211
207
  }
212
208
  });
@@ -230,7 +226,7 @@ const createOAuthModel = ({ controller }) => ({
230
226
  expiresAt : { $gt : now },
231
227
  revoked : false,
232
228
  tokenHash,
233
- type : 'access'
229
+ type : tokenTypes.access
234
230
  }
235
231
  });
236
232
 
@@ -255,7 +251,7 @@ const createOAuthModel = ({ controller }) => ({
255
251
  query : {
256
252
  revoked : false,
257
253
  tokenHash,
258
- type : 'refresh'
254
+ type : tokenTypes.refresh
259
255
  }
260
256
  });
261
257
 
@@ -305,10 +301,10 @@ const createOAuthModel = ({ controller }) => ({
305
301
  });
306
302
 
307
303
  const createOAuthServer = ({ controller }) => new OAuth2Server({
308
- accessTokenLifetime : ACCESS_TOKEN_LIFETIME_SECONDS,
304
+ accessTokenLifetime : lifetimes.access,
309
305
  allowBearerTokensInQueryString : false,
310
306
  model : createOAuthModel({ controller }),
311
- refreshTokenLifetime : REFRESH_TOKEN_LIFETIME_SECONDS,
307
+ refreshTokenLifetime : lifetimes.refresh,
312
308
  requireClientAuthentication : {
313
309
  authorization_code : true,
314
310
  client_credentials : true,
@@ -24,6 +24,27 @@ var compare = (a, b) => {
24
24
  };
25
25
 
26
26
  // lib/oauth/index.js
27
+ var lifetimes = {
28
+ access: 60 * 60,
29
+ // 1 hour
30
+ authorizationCode: 10 * 60,
31
+ // 10 minutes
32
+ code: 15 * 60,
33
+ // 15 minutes (email OTC)
34
+ refresh: 30 * 24 * 60 * 60
35
+ // 30 days
36
+ };
37
+ var tokenTypes = {
38
+ access: "access",
39
+ oauthState: "oauth.state",
40
+ pat: "pat",
41
+ refresh: "refresh"
42
+ };
43
+ var otcContexts = {
44
+ oauthAuthorize: "oauth.authorize",
45
+ signin: "signin",
46
+ signup: "signup"
47
+ };
27
48
  var scopes = [
28
49
  "profile:read",
29
50
  "profile:write",
@@ -90,9 +111,6 @@ var hashToken = (raw) => hash(raw, process.env.OAUTH_TOKEN_HMAC_KEY);
90
111
  var generateToken = () => generate(32, "base64url");
91
112
 
92
113
  // lib/oauth/server.js
93
- var ACCESS_TOKEN_LIFETIME_SECONDS = 60 * 60;
94
- var REFRESH_TOKEN_LIFETIME_SECONDS = 60 * 60 * 24 * 30;
95
- var AUTHORIZATION_CODE_LIFETIME_MS = 10 * 60 * 1e3;
96
114
  var createOAuthModel = ({ controller }) => ({
97
115
  getClient: async (clientId, clientSecret) => {
98
116
  var _a;
@@ -123,7 +141,7 @@ var createOAuthModel = ({ controller }) => ({
123
141
  saveAuthorizationCode: async (code, client, user) => {
124
142
  const rawCode = code.authorizationCode;
125
143
  const tokenHash = hashToken(rawCode);
126
- const expiresAt = new Date(Date.now() + AUTHORIZATION_CODE_LIFETIME_MS);
144
+ const expiresAt = new Date(Date.now() + lifetimes.authorizationCode * 1e3);
127
145
  await controller.create({
128
146
  collection: "otc",
129
147
  data: {
@@ -131,7 +149,7 @@ var createOAuthModel = ({ controller }) => ({
131
149
  codeChallenge: code.codeChallenge ?? null,
132
150
  codeChallengeMethod: code.codeChallengeMethod ?? null,
133
151
  consumedAt: null,
134
- context: "oauth.authorize",
152
+ context: otcContexts.oauthAuthorize,
135
153
  expiresAt,
136
154
  redirectUri: code.redirectUri ?? null,
137
155
  scopes: code.scope ?? [],
@@ -155,7 +173,7 @@ var createOAuthModel = ({ controller }) => ({
155
173
  collection: "otc",
156
174
  query: {
157
175
  consumedAt: null,
158
- context: "oauth.authorize",
176
+ context: otcContexts.oauthAuthorize,
159
177
  expiresAt: { $gt: now },
160
178
  tokenHash
161
179
  }
@@ -182,7 +200,7 @@ var createOAuthModel = ({ controller }) => ({
182
200
  }
183
201
  },
184
202
  query: {
185
- context: "oauth.authorize",
203
+ context: otcContexts.oauthAuthorize,
186
204
  tokenHash
187
205
  }
188
206
  });
@@ -192,7 +210,7 @@ var createOAuthModel = ({ controller }) => ({
192
210
  const now = /* @__PURE__ */ new Date();
193
211
  const accessRaw = token.accessToken;
194
212
  const accessHash = hashToken(accessRaw);
195
- const accessExpiresAt = token.accessTokenExpiresAt ?? new Date(now.getTime() + ACCESS_TOKEN_LIFETIME_SECONDS * 1e3);
213
+ const accessExpiresAt = token.accessTokenExpiresAt ?? new Date(now.getTime() + lifetimes.access * 1e3);
196
214
  await controller.create({
197
215
  collection: "token",
198
216
  data: {
@@ -208,7 +226,7 @@ var createOAuthModel = ({ controller }) => ({
208
226
  rotatedFrom: null,
209
227
  scopes: token.scope ?? [],
210
228
  tokenHash: accessHash,
211
- type: "access",
229
+ type: tokenTypes.access,
212
230
  user: (user == null ? void 0 : user.id) ?? null
213
231
  }
214
232
  });
@@ -222,7 +240,7 @@ var createOAuthModel = ({ controller }) => ({
222
240
  if (token.refreshToken) {
223
241
  const refreshRaw = token.refreshToken;
224
242
  const refreshHash = hashToken(refreshRaw);
225
- const refreshExpiresAt = token.refreshTokenExpiresAt ?? new Date(now.getTime() + REFRESH_TOKEN_LIFETIME_SECONDS * 1e3);
243
+ const refreshExpiresAt = token.refreshTokenExpiresAt ?? new Date(now.getTime() + lifetimes.refresh * 1e3);
226
244
  await controller.create({
227
245
  collection: "token",
228
246
  data: {
@@ -238,7 +256,7 @@ var createOAuthModel = ({ controller }) => ({
238
256
  rotatedFrom: null,
239
257
  scopes: token.scope ?? [],
240
258
  tokenHash: refreshHash,
241
- type: "refresh",
259
+ type: tokenTypes.refresh,
242
260
  user: (user == null ? void 0 : user.id) ?? null
243
261
  }
244
262
  });
@@ -257,7 +275,7 @@ var createOAuthModel = ({ controller }) => ({
257
275
  expiresAt: { $gt: now },
258
276
  revoked: false,
259
277
  tokenHash,
260
- type: "access"
278
+ type: tokenTypes.access
261
279
  }
262
280
  });
263
281
  if (!record) return false;
@@ -276,7 +294,7 @@ var createOAuthModel = ({ controller }) => ({
276
294
  query: {
277
295
  revoked: false,
278
296
  tokenHash,
279
- type: "refresh"
297
+ type: tokenTypes.refresh
280
298
  }
281
299
  });
282
300
  if (!record) return false;
@@ -311,10 +329,10 @@ var createOAuthModel = ({ controller }) => ({
311
329
  getUserFromClient: (client) => ({ id: client.id, type: "client" })
312
330
  });
313
331
  var createOAuthServer = ({ controller }) => new OAuth2Server({
314
- accessTokenLifetime: ACCESS_TOKEN_LIFETIME_SECONDS,
332
+ accessTokenLifetime: lifetimes.access,
315
333
  allowBearerTokensInQueryString: false,
316
334
  model: createOAuthModel({ controller }),
317
- refreshTokenLifetime: REFRESH_TOKEN_LIFETIME_SECONDS,
335
+ refreshTokenLifetime: lifetimes.refresh,
318
336
  requireClientAuthentication: {
319
337
  authorization_code: true,
320
338
  client_credentials: true,
package/package.json CHANGED
@@ -130,5 +130,5 @@
130
130
  "build": "tsup && npm publish"
131
131
  },
132
132
  "types": "dist/index.d.ts",
133
- "version": "0.0.45"
133
+ "version": "0.0.48"
134
134
  }