@opensaas/keystone-nextjs-auth 26.0.0 → 27.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.
@@ -42,17 +42,14 @@ function getBaseAuthSchema(_ref) {
42
42
  types: [base.object(listKey)],
43
43
  resolveType: (root, context) => {
44
44
  var _context$session;
45
-
46
45
  return (_context$session = context.session) === null || _context$session === void 0 ? void 0 : _context$session.listKey;
47
46
  }
48
47
  }),
49
-
50
48
  resolve(root, args, _ref2) {
51
49
  let {
52
50
  session,
53
51
  db
54
52
  } = _ref2;
55
-
56
53
  if (typeof (session === null || session === void 0 ? void 0 : session.itemId) === 'string' && typeof session.listKey === 'string') {
57
54
  return db[session.listKey].findOne({
58
55
  where: {
@@ -60,10 +57,8 @@ function getBaseAuthSchema(_ref) {
60
57
  }
61
58
  });
62
59
  }
63
-
64
60
  return null;
65
61
  }
66
-
67
62
  })
68
63
  }
69
64
  };
@@ -78,7 +73,6 @@ const getSchemaExtension = _ref => {
78
73
  } = _ref;
79
74
  return graphql.extend(base => {
80
75
  var _context;
81
-
82
76
  const baseSchema = getBaseAuthSchema({
83
77
  listKey,
84
78
  base
@@ -128,6 +122,7 @@ const authTemplate = _ref => {
128
122
  };
129
123
 
130
124
  const _excluded = ["get", "end"];
125
+
131
126
  /**
132
127
  * createAuth function
133
128
  *
@@ -151,6 +146,7 @@ function createAuth(_ref) {
151
146
  // part of the createAuth API (in which case its use cases need to be documented and tested)
152
147
  // or whether always being true is what we want, in which case we can refactor our code
153
148
  // to match this. -TL
149
+
154
150
  const customPath = !keystonePath || keystonePath === '/' ? '' : keystonePath;
155
151
  /**
156
152
  * pageMiddleware
@@ -162,29 +158,25 @@ function createAuth(_ref) {
162
158
  * - to the init page when initFirstItem is configured, and there are no user in the database
163
159
  * - to the signin page when no valid session is present
164
160
  */
165
-
166
161
  const authMiddleware = async _ref2 => {
167
162
  let {
168
163
  context,
169
- isValidSession
164
+ wasAccessAllowed
170
165
  } = _ref2;
171
166
  const {
172
167
  req,
173
168
  session
174
169
  } = context;
175
170
  const pathname = url.parse(req === null || req === void 0 ? void 0 : req.url).pathname;
176
-
177
- if (isValidSession) {
171
+ if (wasAccessAllowed) {
178
172
  if (customPath !== '' && pathname === '/') {
179
173
  return {
180
174
  kind: 'redirect',
181
175
  to: `${customPath}`
182
176
  };
183
177
  }
184
-
185
178
  return;
186
179
  }
187
-
188
180
  if (!session && !_includesInstanceProperty(pathname).call(pathname, `${customPath}/api/auth/`)) {
189
181
  return {
190
182
  kind: 'redirect',
@@ -192,6 +184,7 @@ function createAuth(_ref) {
192
184
  };
193
185
  }
194
186
  };
187
+
195
188
  /**
196
189
  * authGetAdditionalFiles
197
190
  *
@@ -200,8 +193,6 @@ function createAuth(_ref) {
200
193
  *
201
194
  * The signin page is always included, and the init page is included when initFirstItem is set
202
195
  */
203
-
204
-
205
196
  const authGetAdditionalFiles = () => {
206
197
  const filesToWrite = [{
207
198
  mode: 'write',
@@ -222,84 +213,75 @@ function createAuth(_ref) {
222
213
  }];
223
214
  return filesToWrite;
224
215
  };
216
+
225
217
  /**
226
218
  * publicAuthPages
227
219
  *
228
220
  * Must be added to the ui.publicPages config
229
221
  */
230
-
231
-
232
- const authPublicPages = [`${customPath}/api/auth/csrf`, `${customPath}/api/auth/signin`, `${customPath}/api/auth/callback`, `${customPath}/api/auth/session`, `${customPath}/api/auth/providers`, `${customPath}/api/auth/signout`, `${customPath}/api/auth/error`]; // TODO: Add Provider Types
222
+ const authPublicPages = [`${customPath}/api/auth/csrf`, `${customPath}/api/auth/signin`, `${customPath}/api/auth/callback`, `${customPath}/api/auth/session`, `${customPath}/api/auth/providers`, `${customPath}/api/auth/signout`, `${customPath}/api/auth/error`];
223
+ // TODO: Add Provider Types
233
224
  // @ts-ignore
234
-
235
225
  function addPages(provider) {
236
226
  const name = provider.id;
237
227
  authPublicPages.push(`${customPath}/api/auth/signin/${name}`);
238
228
  authPublicPages.push(`${customPath}/api/auth/callback/${name}`);
239
229
  }
240
-
241
230
  _mapInstanceProperty(providers).call(providers, addPages);
231
+
242
232
  /**
243
233
  * extendGraphqlSchema
244
234
  *
245
235
  * Must be added to the extendGraphqlSchema config. Can be composed.
246
236
  */
247
-
248
-
249
237
  const extendGraphqlSchema = getSchemaExtension({
250
238
  identityField,
251
239
  listKey
252
240
  });
241
+
253
242
  /**
254
243
  * validateConfig
255
244
  *
256
245
  * Validates the provided auth config; optional step when integrating auth
257
246
  */
258
-
259
247
  const validateConfig = keystoneConfig => {
260
248
  const listConfig = keystoneConfig.lists[listKey];
261
-
262
249
  if (listConfig === undefined) {
263
250
  const msg = `A createAuth() invocation specifies the list "${listKey}" but no list with that key has been defined.`;
264
251
  throw new Error(msg);
265
- } // TODO: Check if providers
252
+ }
253
+
254
+ // TODO: Check if providers
266
255
  // TODO: Check other required commands/data
256
+
267
257
  // TODO: Check for String-like typing for identityField? How?
268
258
  // TODO: Validate that the identifyField is unique.
269
259
  // TODO: If this field isn't required, what happens if I try to log in as `null`?
270
-
271
-
272
260
  const identityFieldConfig = listConfig.fields[identityField];
273
-
274
261
  if (identityFieldConfig === undefined) {
275
262
  const identityFieldName = _JSON$stringify(identityField);
276
-
277
263
  const msg = `A createAuth() invocation for the "${listKey}" list specifies ${identityFieldName} as its identityField but no field with that key exists on the list.`;
278
264
  throw new Error(msg);
279
265
  }
280
266
  };
267
+
281
268
  /**
282
269
  * withItemData
283
270
  *
284
271
  * Automatically injects a session.data value with the authenticated item
285
272
  */
286
-
287
273
  /* TODO:
288
274
  - [ ] We could support additional where input to validate item sessions (e.g an isEnabled boolean)
289
275
  */
290
-
291
-
292
276
  const withItemData = _sessionStrategy => {
293
277
  const {
294
- get,
295
- end
296
- } = _sessionStrategy,
297
- sessionStrategy = _objectWithoutProperties(_sessionStrategy, _excluded);
298
-
278
+ get,
279
+ end
280
+ } = _sessionStrategy,
281
+ sessionStrategy = _objectWithoutProperties(_sessionStrategy, _excluded);
299
282
  return _objectSpread(_objectSpread({}, sessionStrategy), {}, {
300
283
  get: async _ref3 => {
301
284
  var _req$headers, _req$headers$authoriz;
302
-
303
285
  let {
304
286
  context
305
287
  } = _ref3;
@@ -309,13 +291,10 @@ function createAuth(_ref) {
309
291
  const pathname = url.parse(req === null || req === void 0 ? void 0 : req.url).pathname;
310
292
  let nextSession;
311
293
  if (!req) return;
312
-
313
294
  if (_includesInstanceProperty(pathname).call(pathname, '/api/auth')) {
314
295
  return;
315
296
  }
316
-
317
297
  const sudoContext = context.sudo();
318
-
319
298
  if (((_req$headers = req.headers) === null || _req$headers === void 0 ? void 0 : (_req$headers$authoriz = _req$headers.authorization) === null || _req$headers$authoriz === void 0 ? void 0 : _req$headers$authoriz.split(' ')[0]) === 'Bearer') {
320
299
  nextSession = await getToken({
321
300
  req: req,
@@ -326,11 +305,9 @@ function createAuth(_ref) {
326
305
  req
327
306
  });
328
307
  }
329
-
330
308
  if (!nextSession || !nextSession.listKey || nextSession.listKey !== listKey || !nextSession.itemId || !sudoContext.query[listKey] || !nextSession.itemId) {
331
309
  return;
332
310
  }
333
-
334
311
  const reqWithUser = req;
335
312
  reqWithUser.user = {
336
313
  istKey: nextSession.listKey,
@@ -372,7 +349,6 @@ function createAuth(_ref) {
372
349
  }
373
350
  });
374
351
  };
375
-
376
352
  function defaultIsAccessAllowed(_ref5) {
377
353
  let {
378
354
  session
@@ -389,16 +365,12 @@ function createAuth(_ref) {
389
365
  * It validates the auth config against the provided keystone config, and preserves existing
390
366
  * config by composing existing extendGraphqlSchema functions and ui config.
391
367
  */
392
-
393
-
394
368
  const withAuth = keystoneConfig => {
395
369
  var _ui;
396
-
397
370
  validateConfig(keystoneConfig);
398
371
  let {
399
372
  ui
400
373
  } = keystoneConfig;
401
-
402
374
  if (!((_ui = ui) !== null && _ui !== void 0 && _ui.isDisabled)) {
403
375
  const {
404
376
  getAdditionalFiles = [],
@@ -410,13 +382,10 @@ function createAuth(_ref) {
410
382
  publicPages: [...publicPages, ...authPublicPages],
411
383
  isAccessAllowed: async context => {
412
384
  var _context$req;
413
-
414
385
  const pathname = url.parse((_context$req = context.req) === null || _context$req === void 0 ? void 0 : _context$req.url).pathname;
415
-
416
386
  if (_startsWithInstanceProperty(pathname).call(pathname, `${customPath}/_next`) || _startsWithInstanceProperty(pathname).call(pathname, `${customPath}/__next`) || _startsWithInstanceProperty(pathname).call(pathname, `${customPath}/api/auth/`) || pages !== null && pages !== void 0 && pages.signIn && _includesInstanceProperty(pathname).call(pathname, pages === null || pages === void 0 ? void 0 : pages.signIn) || pages !== null && pages !== void 0 && pages.error && _includesInstanceProperty(pathname).call(pathname, pages === null || pages === void 0 ? void 0 : pages.error) || pages !== null && pages !== void 0 && pages.signOut && _includesInstanceProperty(pathname).call(pathname, pages === null || pages === void 0 ? void 0 : pages.signOut)) {
417
387
  return true;
418
388
  }
419
-
420
389
  return await isAccessAllowed(context);
421
390
  },
422
391
  getAdditionalFiles: [...getAdditionalFiles, authGetAdditionalFiles],
@@ -427,7 +396,6 @@ function createAuth(_ref) {
427
396
  }
428
397
  });
429
398
  }
430
-
431
399
  if (!keystoneConfig.session) throw new TypeError('Missing .session configuration');
432
400
  const session = withItemData(keystoneConfig.session);
433
401
  const existingExtendGraphQLSchema = keystoneConfig.extendGraphqlSchema;
@@ -442,16 +410,15 @@ function createAuth(_ref) {
442
410
  extendGraphqlSchema: existingExtendGraphQLSchema ? schema => existingExtendGraphQLSchema(extendGraphqlSchema(schema)) : extendGraphqlSchema
443
411
  });
444
412
  };
445
-
446
413
  return {
447
- withAuth // In the future we may want to return the following so that developers can
414
+ withAuth
415
+ // In the future we may want to return the following so that developers can
448
416
  // roll their own. This is pending a review of the use cases this might be
449
417
  // appropriate for, along with documentation and testing.
450
418
  // ui: { enableSessionItem: true, pageMiddleware, getAdditionalFiles, publicPages },
451
419
  // fields,
452
420
  // extendGraphqlSchema,
453
421
  // validateConfig,
454
-
455
422
  };
456
423
  }
457
424
 
package/package.json CHANGED
@@ -1,26 +1,26 @@
1
1
  {
2
2
  "name": "@opensaas/keystone-nextjs-auth",
3
- "version": "26.0.0",
3
+ "version": "27.0.0",
4
4
  "repository": "https://github.com/opensaasau/keystone-nextjs-auth",
5
5
  "license": "MIT",
6
6
  "main": "dist/opensaas-keystone-nextjs-auth.cjs.js",
7
7
  "module": "dist/opensaas-keystone-nextjs-auth.esm.js",
8
8
  "dependencies": {
9
- "@babel/runtime": "^7.17.9",
10
- "@babel/runtime-corejs3": "^7.17.9",
11
- "@types/ejs": "^3.1.1",
9
+ "@babel/runtime": "^7.21.0",
10
+ "@babel/runtime-corejs3": "^7.21.0",
11
+ "@types/ejs": "^3.1.2",
12
12
  "cookie": "^0.5.0",
13
13
  "cross-fetch": "^3.1.5",
14
14
  "ejs": "^3.1.8",
15
15
  "fast-deep-equal": "^3.1.3",
16
- "next-auth": "^4.18.0"
16
+ "next-auth": "^4.19.2"
17
17
  },
18
18
  "devDependencies": {
19
- "@keystone-6/core": "4.0.1",
19
+ "@keystone-6/core": "5.0.0",
20
20
  "react": "^18.2.0"
21
21
  },
22
22
  "peerDependencies": {
23
- "@keystone-6/core": "4.0.1",
23
+ "@keystone-6/core": "5.0.0",
24
24
  "react": "^18.2.0"
25
25
  },
26
26
  "publishConfig": {
@@ -14,21 +14,18 @@ async function findMatchingIdentity(identityField, identity, queryAPI) {
14
14
  where: {
15
15
  [identityField]: identity
16
16
  }
17
- }); // Identity failures with helpful errors
18
-
17
+ });
18
+ // Identity failures with helpful errors
19
19
  let code;
20
-
21
20
  if (!item) {
22
21
  code = 'IDENTITY_NOT_FOUND';
23
22
  }
24
-
25
23
  if (code) {
26
24
  return {
27
25
  success: false,
28
26
  code
29
27
  };
30
28
  }
31
-
32
29
  return {
33
30
  success: true,
34
31
  item
@@ -40,14 +37,12 @@ async function validateNextAuth(identityField, identity, protectIdentities, item
40
37
  const {
41
38
  item
42
39
  } = match;
43
-
44
40
  if (item) {
45
41
  return {
46
42
  success: true,
47
43
  item
48
44
  };
49
45
  }
50
-
51
46
  return {
52
47
  success: false,
53
48
  code: protectIdentities ? 'FAILURE' : 'SUBJECT_NOT_FOUND'
@@ -69,17 +64,14 @@ function NextAuthPage(props) {
69
64
  sessionData,
70
65
  sessionSecret
71
66
  } = props;
72
-
73
67
  if (!query) {
74
68
  console.error('NextAuthPage got no query.');
75
69
  return null;
76
70
  }
77
-
78
71
  if (!providers || !providers.length) {
79
72
  console.error('You need to provide at least one provider.');
80
73
  return null;
81
74
  }
82
-
83
75
  const list = query[listKey];
84
76
  const protectIdentities = true;
85
77
  return NextAuth__default["default"]({
@@ -97,7 +89,6 @@ function NextAuthPage(props) {
97
89
  profile
98
90
  } = _ref;
99
91
  let identity;
100
-
101
92
  if (typeof user.id === 'string') {
102
93
  identity = user.id;
103
94
  } else if (typeof user.id === 'number') {
@@ -105,23 +96,20 @@ function NextAuthPage(props) {
105
96
  } else {
106
97
  identity = 0;
107
98
  }
108
-
109
99
  const userInput = resolver ? await resolver({
110
100
  user,
111
101
  account,
112
102
  profile
113
103
  }) : {};
114
- const result = await validateNextAuth(identityField, identity, protectIdentities, list); // ID
115
-
104
+ const result = await validateNextAuth(identityField, identity, protectIdentities, list);
105
+ // ID
116
106
  const data = _objectSpread({
117
107
  [identityField]: identity
118
108
  }, userInput);
119
-
120
109
  if (!result.success) {
121
110
  if (!autoCreate) {
122
111
  return false;
123
112
  }
124
-
125
113
  const createUser = await list.createOne({
126
114
  data
127
115
  }).then(returned => {
@@ -135,7 +123,6 @@ function NextAuthPage(props) {
135
123
  });
136
124
  return createUser.success;
137
125
  }
138
-
139
126
  const updateUser = await list.updateOne({
140
127
  where: {
141
128
  id: result.item.id
@@ -152,21 +139,18 @@ function NextAuthPage(props) {
152
139
  });
153
140
  return updateUser.success;
154
141
  },
155
-
156
142
  async redirect(_ref2) {
157
143
  let {
158
144
  url
159
145
  } = _ref2;
160
146
  return url;
161
147
  },
162
-
163
148
  async session(_ref3) {
164
149
  let {
165
150
  session,
166
151
  token
167
152
  } = _ref3;
168
153
  let returnSession = session;
169
-
170
154
  if (!token.itemId) {
171
155
  return session;
172
156
  } else {
@@ -177,22 +161,17 @@ function NextAuthPage(props) {
177
161
  itemId: token.itemId
178
162
  });
179
163
  }
180
-
181
164
  return returnSession;
182
165
  },
183
-
184
166
  async jwt(_ref4) {
185
167
  let {
186
168
  token
187
169
  } = _ref4;
188
170
  const identity = token.sub;
189
-
190
171
  if (!identity) {
191
172
  return token;
192
173
  }
193
-
194
174
  const result = await validateNextAuth(identityField, identity, protectIdentities, list);
195
-
196
175
  if (!result.success) {
197
176
  token.itemId = undefined;
198
177
  } else {
@@ -205,15 +184,12 @@ function NextAuthPage(props) {
205
184
  });
206
185
  token.data = data;
207
186
  }
208
-
209
187
  const returnToken = _objectSpread(_objectSpread({}, token), {}, {
210
188
  subject: token.sub,
211
189
  listKey
212
190
  });
213
-
214
191
  return returnToken;
215
192
  }
216
-
217
193
  }
218
194
  });
219
195
  }
@@ -14,21 +14,18 @@ async function findMatchingIdentity(identityField, identity, queryAPI) {
14
14
  where: {
15
15
  [identityField]: identity
16
16
  }
17
- }); // Identity failures with helpful errors
18
-
17
+ });
18
+ // Identity failures with helpful errors
19
19
  let code;
20
-
21
20
  if (!item) {
22
21
  code = 'IDENTITY_NOT_FOUND';
23
22
  }
24
-
25
23
  if (code) {
26
24
  return {
27
25
  success: false,
28
26
  code
29
27
  };
30
28
  }
31
-
32
29
  return {
33
30
  success: true,
34
31
  item
@@ -40,14 +37,12 @@ async function validateNextAuth(identityField, identity, protectIdentities, item
40
37
  const {
41
38
  item
42
39
  } = match;
43
-
44
40
  if (item) {
45
41
  return {
46
42
  success: true,
47
43
  item
48
44
  };
49
45
  }
50
-
51
46
  return {
52
47
  success: false,
53
48
  code: protectIdentities ? 'FAILURE' : 'SUBJECT_NOT_FOUND'
@@ -69,17 +64,14 @@ function NextAuthPage(props) {
69
64
  sessionData,
70
65
  sessionSecret
71
66
  } = props;
72
-
73
67
  if (!query) {
74
68
  console.error('NextAuthPage got no query.');
75
69
  return null;
76
70
  }
77
-
78
71
  if (!providers || !providers.length) {
79
72
  console.error('You need to provide at least one provider.');
80
73
  return null;
81
74
  }
82
-
83
75
  const list = query[listKey];
84
76
  const protectIdentities = true;
85
77
  return NextAuth__default["default"]({
@@ -97,7 +89,6 @@ function NextAuthPage(props) {
97
89
  profile
98
90
  } = _ref;
99
91
  let identity;
100
-
101
92
  if (typeof user.id === 'string') {
102
93
  identity = user.id;
103
94
  } else if (typeof user.id === 'number') {
@@ -105,23 +96,20 @@ function NextAuthPage(props) {
105
96
  } else {
106
97
  identity = 0;
107
98
  }
108
-
109
99
  const userInput = resolver ? await resolver({
110
100
  user,
111
101
  account,
112
102
  profile
113
103
  }) : {};
114
- const result = await validateNextAuth(identityField, identity, protectIdentities, list); // ID
115
-
104
+ const result = await validateNextAuth(identityField, identity, protectIdentities, list);
105
+ // ID
116
106
  const data = _objectSpread({
117
107
  [identityField]: identity
118
108
  }, userInput);
119
-
120
109
  if (!result.success) {
121
110
  if (!autoCreate) {
122
111
  return false;
123
112
  }
124
-
125
113
  const createUser = await list.createOne({
126
114
  data
127
115
  }).then(returned => {
@@ -135,7 +123,6 @@ function NextAuthPage(props) {
135
123
  });
136
124
  return createUser.success;
137
125
  }
138
-
139
126
  const updateUser = await list.updateOne({
140
127
  where: {
141
128
  id: result.item.id
@@ -152,21 +139,18 @@ function NextAuthPage(props) {
152
139
  });
153
140
  return updateUser.success;
154
141
  },
155
-
156
142
  async redirect(_ref2) {
157
143
  let {
158
144
  url
159
145
  } = _ref2;
160
146
  return url;
161
147
  },
162
-
163
148
  async session(_ref3) {
164
149
  let {
165
150
  session,
166
151
  token
167
152
  } = _ref3;
168
153
  let returnSession = session;
169
-
170
154
  if (!token.itemId) {
171
155
  return session;
172
156
  } else {
@@ -177,22 +161,17 @@ function NextAuthPage(props) {
177
161
  itemId: token.itemId
178
162
  });
179
163
  }
180
-
181
164
  return returnSession;
182
165
  },
183
-
184
166
  async jwt(_ref4) {
185
167
  let {
186
168
  token
187
169
  } = _ref4;
188
170
  const identity = token.sub;
189
-
190
171
  if (!identity) {
191
172
  return token;
192
173
  }
193
-
194
174
  const result = await validateNextAuth(identityField, identity, protectIdentities, list);
195
-
196
175
  if (!result.success) {
197
176
  token.itemId = undefined;
198
177
  } else {
@@ -205,15 +184,12 @@ function NextAuthPage(props) {
205
184
  });
206
185
  token.data = data;
207
186
  }
208
-
209
187
  const returnToken = _objectSpread(_objectSpread({}, token), {}, {
210
188
  subject: token.sub,
211
189
  listKey
212
190
  });
213
-
214
191
  return returnToken;
215
192
  }
216
-
217
193
  }
218
194
  });
219
195
  }