@opensaas/keystone-nextjs-auth 20.3.0 → 21.0.0

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