@opensaas/keystone-nextjs-auth 26.0.0 → 27.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }