@opensaas/keystone-nextjs-auth 20.3.0 → 21.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.
@@ -5,15 +5,17 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var _objectSpread = require('@babel/runtime/helpers/objectSpread2');
6
6
  var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties');
7
7
  var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
8
+ var _indexOfInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/index-of');
9
+ var _Object$values = require('@babel/runtime-corejs3/core-js-stable/object/values');
8
10
  var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
9
11
  var _JSON$stringify = require('@babel/runtime-corejs3/core-js-stable/json/stringify');
10
- var _URL = require('@babel/runtime-corejs3/core-js-stable/url');
12
+ require('@babel/runtime-corejs3/core-js-stable/url');
11
13
  var url = require('url');
12
14
  var react = require('next-auth/react');
15
+ var jwt = require('next-auth/jwt');
13
16
  var cookie = require('cookie');
14
17
  var ejs = require('ejs');
15
18
  var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
16
- var graphql = require('graphql');
17
19
  var core = require('@keystone-6/core');
18
20
 
19
21
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
@@ -37,9 +39,10 @@ function _interopNamespace(e) {
37
39
  }
38
40
 
39
41
  var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
42
+ var _indexOfInstanceProperty__default = /*#__PURE__*/_interopDefault(_indexOfInstanceProperty);
43
+ var _Object$values__default = /*#__PURE__*/_interopDefault(_Object$values);
40
44
  var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
41
45
  var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
42
- var _URL__default = /*#__PURE__*/_interopDefault(_URL);
43
46
  var url__default = /*#__PURE__*/_interopDefault(url);
44
47
  var cookie__namespace = /*#__PURE__*/_interopNamespace(cookie);
45
48
  var ejs__default = /*#__PURE__*/_interopDefault(ejs);
@@ -54,6 +57,9 @@ module.exports = withPreconstruct({
54
57
  typescript: {
55
58
  ignoreBuildErrors: true,
56
59
  },
60
+ env: {
61
+ NEXTAUTH_URL: process.env.NEXTAUTH_URL || 'http://localhost:<%= process.env.PORT || 3000 %><%= keystonePath || '' %>/api/auth',
62
+ },
57
63
  eslint: {
58
64
  ignoreDuringBuilds: true,
59
65
  },
@@ -109,7 +115,6 @@ const nextConfigTemplate = ({
109
115
 
110
116
  function getBaseAuthSchema({
111
117
  listKey,
112
- gqlNames,
113
118
  base
114
119
  }) {
115
120
  const extension = {
@@ -149,22 +154,12 @@ function getBaseAuthSchema({
149
154
  }
150
155
 
151
156
  const getSchemaExtension = ({
152
- identityField,
153
- listKey,
154
- gqlNames
157
+ listKey
155
158
  }) => core.graphql.extend(base => {
156
159
  var _context;
157
160
 
158
- const uniqueWhereInputType = graphql.assertInputObjectType(base.schema.getType(`${listKey}WhereUniqueInput`));
159
- const identityFieldOnUniqueWhere = uniqueWhereInputType.getFields()[identityField];
160
-
161
- if ((identityFieldOnUniqueWhere === null || identityFieldOnUniqueWhere === void 0 ? void 0 : identityFieldOnUniqueWhere.type) !== graphql.GraphQLString && (identityFieldOnUniqueWhere === null || identityFieldOnUniqueWhere === void 0 ? void 0 : identityFieldOnUniqueWhere.type) !== graphql.GraphQLID) {
162
- throw new Error(`createAuth was called with an identityField of ${identityField} on the list ${listKey} ` + `but that field doesn't allow being searched uniquely with a String or ID. ` + `You should likely add \`isIndexed: 'unique'\` ` + `to the field at ${listKey}.${identityField}`);
163
- }
164
-
165
161
  const baseSchema = getBaseAuthSchema({
166
162
  listKey,
167
- gqlNames,
168
163
  base
169
164
  });
170
165
  return _filterInstanceProperty__default["default"](_context = [baseSchema.extension]).call(_context, x => x !== undefined);
@@ -176,44 +171,35 @@ import { query } from '.keystone/api';
176
171
  import keystoneConfig from '../../../../../keystone';
177
172
 
178
173
  export default getNextAuthPage({
174
+ autoCreate: <%= autoCreate %>,
179
175
  identityField: '<%= identityField %>',
180
- sessionData: '<%= sessionData %>',
181
176
  listKey: '<%= listKey %>',
182
- userMap: <%- JSON.stringify(userMap) %>,
183
- accountMap: <%- JSON.stringify(accountMap) %>,
184
- profileMap: <%- JSON.stringify(profileMap) %>,
185
- autoCreate: <%= autoCreate %>,
186
- sessionSecret: '<%= sessionSecret %>',
177
+ pages: keystoneConfig.pages,
187
178
  providers: keystoneConfig.providers,
188
179
  query,
180
+ resolver: keystoneConfig.resolver,
181
+ sessionData: '<%= sessionData %>',
182
+ sessionSecret: '<%= sessionSecret %>',
189
183
  });
190
184
  `;
191
185
  const authTemplate = ({
192
- gqlNames,
186
+ autoCreate,
193
187
  identityField,
194
- sessionData,
195
188
  listKey,
196
- autoCreate,
197
- userMap,
198
- accountMap,
199
- profileMap,
189
+ sessionData,
200
190
  sessionSecret
201
191
  }) => {
202
192
  const authOut = ejs__default["default"].render(template, {
203
- gqlNames,
204
193
  identityField,
205
194
  sessionData,
206
195
  listKey,
207
196
  autoCreate,
208
- userMap,
209
- accountMap,
210
- profileMap,
211
197
  sessionSecret
212
198
  });
213
199
  return authOut;
214
200
  };
215
201
 
216
- const _excluded = ["get"];
202
+ const _excluded = ["get", "start"];
217
203
  /**
218
204
  * createAuth function
219
205
  *
@@ -221,31 +207,21 @@ const _excluded = ["get"];
221
207
  */
222
208
 
223
209
  function createAuth({
224
- listKey,
225
- identityField,
226
- sessionData,
227
210
  autoCreate,
228
- userMap,
229
- accountMap,
230
- profileMap,
211
+ cookies,
212
+ identityField,
213
+ listKey,
231
214
  keystonePath,
215
+ pages,
216
+ resolver,
232
217
  providers,
218
+ sessionData,
233
219
  sessionSecret
234
220
  }) {
235
221
  // The protectIdentities flag is currently under review to see whether it should be
236
222
  // part of the createAuth API (in which case its use cases need to be documented and tested)
237
223
  // or whether always being true is what we want, in which case we can refactor our code
238
224
  // to match this. -TL
239
- const gqlNames = {
240
- // Core
241
- authenticateItemWithPassword: `authenticate${listKey}WithPassword`,
242
- ItemAuthenticationWithPasswordResult: `${listKey}AuthenticationWithPasswordResult`,
243
- ItemAuthenticationWithPasswordSuccess: `${listKey}AuthenticationWithPasswordSuccess`,
244
- ItemAuthenticationWithPasswordFailure: `${listKey}AuthenticationWithPasswordFailure`,
245
- // Initial data
246
- CreateInitialInput: `CreateInitial${listKey}Input`,
247
- createInitialItem: `createInitial${listKey}`
248
- };
249
225
  const customPath = !keystonePath || keystonePath === '/' ? '' : keystonePath;
250
226
  /**
251
227
  * pageMiddleware
@@ -262,16 +238,14 @@ function createAuth({
262
238
  context,
263
239
  isValidSession
264
240
  }) => {
241
+ var _context;
242
+
265
243
  const {
266
244
  req,
267
245
  session
268
246
  } = context;
269
247
  const pathname = url__default["default"].parse(req === null || req === void 0 ? void 0 : req.url).pathname;
270
248
 
271
- if (pathname === `${customPath}/api/__keystone_api_build`) {
272
- return;
273
- }
274
-
275
249
  if (isValidSession) {
276
250
  if (pathname === `${customPath}/api/auth/signin`) {
277
251
  return {
@@ -290,7 +264,11 @@ function createAuth({
290
264
  return;
291
265
  }
292
266
 
293
- if (!session && !_includesInstanceProperty__default["default"](pathname).call(pathname, `${customPath}/api/auth/`)) {
267
+ if (_includesInstanceProperty__default["default"](pathname).call(pathname, '/_next/') || _includesInstanceProperty__default["default"](pathname).call(pathname, '/api/auth/')) {
268
+ return;
269
+ }
270
+
271
+ if (!session && !_includesInstanceProperty__default["default"](pathname).call(pathname, `${customPath}/api/auth/`) && !(_indexOfInstanceProperty__default["default"](_context = _Object$values__default["default"](pages)).call(_context, pathname) > -1)) {
294
272
  return {
295
273
  kind: 'redirect',
296
274
  to: `${customPath}/api/auth/signin`
@@ -312,14 +290,10 @@ function createAuth({
312
290
  mode: 'write',
313
291
  outputPath: 'pages/api/auth/[...nextauth].js',
314
292
  src: authTemplate({
315
- gqlNames,
293
+ autoCreate,
316
294
  identityField,
317
- sessionData,
318
295
  listKey,
319
- autoCreate,
320
- userMap,
321
- accountMap,
322
- profileMap,
296
+ sessionData,
323
297
  sessionSecret
324
298
  })
325
299
  }, {
@@ -338,7 +312,8 @@ function createAuth({
338
312
  */
339
313
 
340
314
 
341
- const publicPages = [`${customPath}/api/auth/csrf`, `${customPath}/api/auth/signin`, `${customPath}/api/auth/callback`, `${customPath}/api/auth/session`, `${customPath}/api/auth/providers`, `${customPath}/api/auth/signout`];
315
+ const publicPages = [`${customPath}/api/__keystone_api_build`, `${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
316
+ // @ts-ignore
342
317
 
343
318
  function addPages(provider) {
344
319
  const name = provider.id;
@@ -356,8 +331,7 @@ function createAuth({
356
331
 
357
332
  const extendGraphqlSchema = getSchemaExtension({
358
333
  identityField,
359
- listKey,
360
- gqlNames
334
+ listKey
361
335
  });
362
336
  /**
363
337
  * validateConfig
@@ -371,7 +345,9 @@ function createAuth({
371
345
  if (listConfig === undefined) {
372
346
  const msg = `A createAuth() invocation specifies the list "${listKey}" but no list with that key has been defined.`;
373
347
  throw new Error(msg);
374
- } // TODO: Check for String-like typing for identityField? How?
348
+ } // TODO: Check if providers
349
+ // TODO: Check other required commands/data
350
+ // TODO: Check for String-like typing for identityField? How?
375
351
  // TODO: Validate that the identifyField is unique.
376
352
  // TODO: If this field isn't required, what happens if I try to log in as `null`?
377
353
 
@@ -379,9 +355,9 @@ function createAuth({
379
355
  const identityFieldConfig = listConfig.fields[identityField];
380
356
 
381
357
  if (identityFieldConfig === undefined) {
382
- const i = _JSON$stringify__default["default"](identityField);
358
+ const identityFieldName = _JSON$stringify__default["default"](identityField);
383
359
 
384
- const msg = `A createAuth() invocation for the "${listKey}" list specifies ${i} as its identityField but no field with that key exists on the list.`;
360
+ const msg = `A createAuth() invocation for the "${listKey}" list specifies ${identityFieldName} as its identityField but no field with that key exists on the list.`;
385
361
  throw new Error(msg);
386
362
  }
387
363
  };
@@ -397,18 +373,46 @@ function createAuth({
397
373
 
398
374
 
399
375
  const withItemData = _sessionStrategy => {
400
- const sessionStrategy = _objectWithoutProperties(_sessionStrategy, _excluded);
376
+ const {
377
+ get,
378
+ start
379
+ } = _sessionStrategy,
380
+ sessionStrategy = _objectWithoutProperties(_sessionStrategy, _excluded);
401
381
 
402
382
  return _objectSpread(_objectSpread({}, sessionStrategy), {}, {
383
+ start: async ({
384
+ res
385
+ }) => {
386
+ console.log('start');
387
+ const session = await start({
388
+ res
389
+ });
390
+ return session;
391
+ },
403
392
  get: async ({
404
393
  req
405
394
  }) => {
395
+ var _req$headers$authoriz;
396
+
406
397
  const pathname = url__default["default"].parse(req === null || req === void 0 ? void 0 : req.url).pathname;
407
398
 
408
399
  if (_includesInstanceProperty__default["default"](pathname).call(pathname, '/api/auth')) {
409
400
  return;
410
401
  }
411
402
 
403
+ if (((_req$headers$authoriz = req.headers.authorization) === null || _req$headers$authoriz === void 0 ? void 0 : _req$headers$authoriz.split(' ')[0]) === 'Bearer') {
404
+ var _token$data;
405
+
406
+ const token = await jwt.getToken({
407
+ req,
408
+ secret: sessionSecret
409
+ });
410
+
411
+ if (token !== null && token !== void 0 && (_token$data = token.data) !== null && _token$data !== void 0 && _token$data.id) {
412
+ return token;
413
+ }
414
+ }
415
+
412
416
  const nextSession = await react.getSession({
413
417
  req
414
418
  });
@@ -429,6 +433,7 @@ function createAuth({
429
433
  secure: "production" === 'production',
430
434
  path: '/',
431
435
  sameSite: 'lax',
436
+ // TODO: Update parse to URL
432
437
  domain: url__default["default"].parse(req.url).hostname
433
438
  }));
434
439
  }
@@ -465,15 +470,18 @@ function createAuth({
465
470
  },
466
471
  enableSessionItem: true,
467
472
  isAccessAllowed: async context => {
468
- var _context$req2, _keystoneConfig$ui3;
469
- // even if the user isn't logged in (which should always be the case if they're seeing /init)
473
+ var _keystoneConfig$ui3;
470
474
 
475
+ const {
476
+ req
477
+ } = context;
478
+ const pathname = url__default["default"].parse(req === null || req === void 0 ? void 0 : req.url).pathname; // Allow nextjs scripts and static files to be accessed without auth
471
479
 
472
- const headers = (_context$req2 = context.req) === null || _context$req2 === void 0 ? void 0 : _context$req2.headers;
473
- const host = headers ? headers['x-forwarded-host'] || headers.host : null;
474
- const thisUrl = headers !== null && headers !== void 0 && headers.referer ? new _URL__default["default"](headers.referer) : undefined;
475
- const accessingInitPage = (thisUrl === null || thisUrl === void 0 ? void 0 : thisUrl.pathname) === '/init' && (thisUrl === null || thisUrl === void 0 ? void 0 : thisUrl.host) === host && (await context.sudo().query[listKey].count({})) === 0;
476
- return accessingInitPage || ((_keystoneConfig$ui3 = keystoneConfig.ui) !== null && _keystoneConfig$ui3 !== void 0 && _keystoneConfig$ui3.isAccessAllowed ? keystoneConfig.ui.isAccessAllowed(context) : context.session !== undefined);
480
+ if (_includesInstanceProperty__default["default"](pathname).call(pathname, '/_next/')) {
481
+ return true;
482
+ } // Allow keystone to access /api/__keystone_api_build for hot reloading
483
+
484
+ return (_keystoneConfig$ui3 = keystoneConfig.ui) !== null && _keystoneConfig$ui3 !== void 0 && _keystoneConfig$ui3.isAccessAllowed ? keystoneConfig.ui.isAccessAllowed(context) : context.session !== undefined;
477
485
  }
478
486
  });
479
487
  }
@@ -483,8 +491,11 @@ function createAuth({
483
491
  const existingExtendGraphQLSchema = keystoneConfig.extendGraphqlSchema;
484
492
  return _objectSpread(_objectSpread({}, keystoneConfig), {}, {
485
493
  ui,
486
- session,
494
+ cookies,
487
495
  providers,
496
+ pages,
497
+ resolver,
498
+ session,
488
499
  lists: _objectSpread({}, keystoneConfig.lists),
489
500
  experimental: _objectSpread(_objectSpread({}, keystoneConfig.experimental), {}, {
490
501
  generateNodeAPI: true