@opensaas/keystone-nextjs-auth 25.0.0 → 27.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @opensaas-keystone/nextjs-auth
2
2
 
3
+ ## 27.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - ec29144: Update dependency @keystone-6/core to v5
8
+
9
+ ### Patch Changes
10
+
11
+ - 0a8ea8e: Update patch dependencies (patch)
12
+
13
+ ## 26.0.0
14
+
15
+ ### Major Changes
16
+
17
+ - fac7086: Upgrade to `keystone-6/core@4.0.0`
18
+
19
+ ### Minor Changes
20
+
21
+ - ed67215: Update dependency next-auth to ^4.17.0
22
+ - 9643191: Upgrade next-auth and fix types
23
+ - b9dbb77: Upgrade to keystone `3.1.0`
24
+
25
+ ### Patch Changes
26
+
27
+ - b9dbb77: Resolve error when `isAccessAllowed` is not defined
28
+ - 5b0af33: Simplify NextJS config of Keystone path and resolve redirect loops
29
+
3
30
  ## 25.0.0
4
31
 
5
32
  ### Major Changes
package/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Keystone next auth
2
+
2
3
  This package enables the addition of social auth to keystone-6.
3
4
 
4
5
  ## Contents
@@ -9,6 +10,7 @@ This package enables the addition of social auth to keystone-6.
9
10
  - [Contributing](#contributing)
10
11
 
11
12
  ## About
13
+
12
14
  This uses NextAuth.js (https://next-auth.js.org/) project to add social auth to Keystone-6 (https://keystonejs.com/). Primary testing has been done with Auth0, happy for others to test other providers/give feedback or send through a PR.
13
15
 
14
16
  ## Adding to your project
@@ -20,7 +22,6 @@ Add import...
20
22
  ```javascript
21
23
  import { createAuth } from '@opensaas/keystone-nextjs-auth';
22
24
  import Auth0 from '@opensaas/keystone-nextjs-auth/providers/auth0';
23
-
24
25
  ```
25
26
 
26
27
  Add you Auth configuration including providers
@@ -60,7 +61,8 @@ const auth = createAuth({
60
61
  ]
61
62
  });
62
63
  ```
63
- Wrap your keystone config in `auth.withAuth`. Note that `generateNodeAPI` is required.
64
+
65
+ Wrap your keystone config in `auth.withAuth`.
64
66
 
65
67
  ```javascript
66
68
  export default auth.withAuth(
@@ -69,32 +71,32 @@ export default auth.withAuth(
69
71
  db: {},
70
72
  ui: {},
71
73
  lists,
72
- experimental: {
73
- generateNodeAPI: true,
74
- },
75
74
  ...
76
75
  });
77
76
  ```
78
77
 
79
78
  ## Configuration
79
+
80
80
  Provider configuration see https://next-auth.js.org/configuration/providers.
81
81
  For Keystone-6 Configuration see https://keystonejs.com/
82
82
  for example see the example [backend](./backend)
83
83
 
84
- - listKey - the list for authentication (generally `'User'`). Make sure any required fields are set using the `*Map` fields, see note below.
85
- - identityField - The field that stores the identity/subjectId in keystone (generally `'subjectId'`). You will need to add this field to your list schema specified by `listKey`. An example can be found [here](./backend/schemas/User.ts).
86
- - sessionData - Data to be stored in the session ( something like `'id name email'`),
87
- - autoCreate - boolean to autocreate a user when they log in
88
- - userMap: `key:value` pairs that define what is copied from the User object returned from NextAuth in the SignIn callback (https://next-auth.js.org/configuration/callbacks#sign-in-callback) Left side is Keystone side, right is what comes from NextAuth eg: `{ subjectId: 'id', name: 'name' }`
89
- - accountMap - As Above but for the Account object
90
- - profileMap - As Above but for the Profile object
91
- - keystonePath - the path you want to access keystone from your frontend app (if required).
84
+ - listKey - the list for authentication (generally `'User'`). Make sure any required fields are set using the `*Map` fields, see note below.
85
+ - identityField - The field that stores the identity/subjectId in keystone (generally `'subjectId'`). You will need to add this field to your list schema specified by `listKey`. An example can be found [here](./backend/schemas/User.ts).
86
+ - sessionData - Data to be stored in the session ( something like `'id name email'`),
87
+ - autoCreate - boolean to autocreate a user when they log in
88
+ - userMap: `key:value` pairs that define what is copied from the User object returned from NextAuth in the SignIn callback (https://next-auth.js.org/configuration/callbacks#sign-in-callback) Left side is Keystone side, right is what comes from NextAuth eg: `{ subjectId: 'id', name: 'name' }`
89
+ - accountMap - As Above but for the Account object
90
+ - profileMap - As Above but for the Profile object
91
+ - keystonePath - the path you want to access keystone from your frontend app (if required).
92
92
 
93
93
  Note: The Keystone `create-keystone-app` CLI app (generally run with `yarn create keystone-app`/`npm init keystone-app`) will set a required `password` field on the `User` list. If you've used this to set up your project you will need to modify your list schema to set the field as not required, or remove it entirely if you don't plan to use the default Keystone auth system at all.
94
94
 
95
95
  ## Contributing
96
+
96
97
  If you want to run this package locally
97
98
  After cloning run `yarn install` and either:
99
+
98
100
  - `yarn dev` to run both the frontend and backend or
99
101
  - `yarn dev:backend` for just the backend
100
102
 
@@ -2,14 +2,14 @@ import { CookiesOptions, EventCallbacks, PagesOptions } from 'next-auth';
2
2
  import type { KeystoneListsAPI } from '@keystone-6/core/types';
3
3
  import { Provider } from 'next-auth/providers';
4
4
  import { JWTOptions } from 'next-auth/jwt';
5
- export declare type NextAuthTemplateProps = {
5
+ export type NextAuthTemplateProps = {
6
6
  autoCreate: boolean;
7
7
  identityField: string;
8
8
  listKey: string;
9
9
  sessionData: string | undefined;
10
10
  sessionSecret: string;
11
11
  };
12
- export declare type CoreNextAuthPageProps = {
12
+ export type CoreNextAuthPageProps = {
13
13
  cookies?: Partial<CookiesOptions>;
14
14
  events?: Partial<EventCallbacks>;
15
15
  jwt?: Partial<JWTOptions>;
@@ -23,7 +23,7 @@ export declare type CoreNextAuthPageProps = {
23
23
  [key: string]: boolean | string | number;
24
24
  }>;
25
25
  } & NextAuthTemplateProps;
26
- export declare type NextAuthPageProps = CoreNextAuthPageProps & {
26
+ export type NextAuthPageProps = CoreNextAuthPageProps & {
27
27
  query: KeystoneListsAPI<any>;
28
28
  };
29
29
  export default function NextAuthPage(props: NextAuthPageProps): any;
@@ -1,37 +1,29 @@
1
- /// <reference types="node" />
2
- import type { ServerResponse, IncomingMessage } from 'http';
3
- import type { NextRequest } from 'next/server';
4
1
  import { Provider } from 'next-auth/providers';
5
2
  import { CookiesOptions, PagesOptions } from 'next-auth';
6
- import { BaseListTypeInfo, KeystoneConfig, CreateContext } from '@keystone-6/core/types';
7
- declare type NextAuthResponse = IncomingMessage & NextRequest;
3
+ import { BaseListTypeInfo, KeystoneConfig, KeystoneContext } from '@keystone-6/core/types';
8
4
  export declare type AuthSessionStrategy<StoredSessionData> = {
9
5
  start: (args: {
10
- res: ServerResponse;
11
6
  data: any;
12
- createContext: CreateContext;
13
- }) => Promise<string>;
7
+ context: KeystoneContext;
8
+ }) => Promise<unknown>;
14
9
  end: (args: {
15
- req: IncomingMessage;
16
- res: ServerResponse;
17
- createContext: CreateContext;
18
- }) => Promise<void>;
10
+ context: KeystoneContext;
11
+ }) => Promise<unknown>;
19
12
  get: (args: {
20
- req: NextAuthResponse;
21
- createContext: CreateContext;
13
+ context: KeystoneContext;
22
14
  }) => Promise<StoredSessionData | undefined>;
23
15
  };
24
- export declare type NextAuthProviders = Provider[];
25
- declare type KeytoneOAuthOptions = {
16
+ export type NextAuthProviders = Provider[];
17
+ type KeytoneOAuthOptions = {
26
18
  providers: NextAuthProviders;
27
19
  pages?: Partial<PagesOptions>;
28
20
  };
29
- declare type NextAuthOptions = {
21
+ type NextAuthOptions = {
30
22
  cookies?: Partial<CookiesOptions>;
31
23
  resolver: any;
32
24
  };
33
- export declare type KeystoneOAuthConfig = KeystoneConfig & KeytoneOAuthOptions & NextAuthOptions;
34
- export declare type AuthConfig<GeneratedListTypes extends BaseListTypeInfo> = {
25
+ export type KeystoneOAuthConfig = KeystoneConfig & KeytoneOAuthOptions & NextAuthOptions;
26
+ export type AuthConfig<GeneratedListTypes extends BaseListTypeInfo> = {
35
27
  /** Auth Create users in Keystone DB from Auth Provider */
36
28
  autoCreate: boolean;
37
29
  /** Adds ability to customize cookie options, for example, to facilitate cross-subdomain functionality */
@@ -58,8 +50,8 @@ export declare type AuthConfig<GeneratedListTypes extends BaseListTypeInfo> = {
58
50
  /** Next-Auth Session Secret */
59
51
  sessionSecret: string;
60
52
  };
61
- export declare type AuthTokenRequestErrorCode = 'IDENTITY_NOT_FOUND' | 'MULTIPLE_IDENTITY_MATCHES';
62
- export declare type PasswordAuthErrorCode = AuthTokenRequestErrorCode | 'FAILURE' | 'SECRET_NOT_SET' | 'SECRET_MISMATCH';
63
- export declare type NextAuthErrorCode = AuthTokenRequestErrorCode | 'FAILURE' | 'SUBJECT_NOT_FOUND';
64
- export declare type AuthTokenRedemptionErrorCode = AuthTokenRequestErrorCode | 'FAILURE' | 'TOKEN_NOT_SET' | 'TOKEN_MISMATCH' | 'TOKEN_EXPIRED' | 'TOKEN_REDEEMED';
53
+ export type AuthTokenRequestErrorCode = 'IDENTITY_NOT_FOUND' | 'MULTIPLE_IDENTITY_MATCHES';
54
+ export type PasswordAuthErrorCode = AuthTokenRequestErrorCode | 'FAILURE' | 'SECRET_NOT_SET' | 'SECRET_MISMATCH';
55
+ export type NextAuthErrorCode = AuthTokenRequestErrorCode | 'FAILURE' | 'SUBJECT_NOT_FOUND';
56
+ export type AuthTokenRedemptionErrorCode = AuthTokenRequestErrorCode | 'FAILURE' | 'TOKEN_NOT_SET' | 'TOKEN_MISMATCH' | 'TOKEN_EXPIRED' | 'TOKEN_REDEEMED';
65
57
  export {};
@@ -7,7 +7,7 @@ var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProp
7
7
  var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
8
8
  var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
9
9
  var _JSON$stringify = require('@babel/runtime-corejs3/core-js-stable/json/stringify');
10
- var _URL = require('@babel/runtime-corejs3/core-js-stable/url');
10
+ var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
11
11
  var url = require('url');
12
12
  var react = require('next-auth/react');
13
13
  var jwt = require('next-auth/jwt');
@@ -39,68 +39,19 @@ function _interopNamespace(e) {
39
39
  var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
40
40
  var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
41
41
  var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
42
- var _URL__default = /*#__PURE__*/_interopDefault(_URL);
42
+ var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
43
43
  var url__default = /*#__PURE__*/_interopDefault(url);
44
44
  var cookie__namespace = /*#__PURE__*/_interopNamespace(cookie);
45
45
  var ejs__default = /*#__PURE__*/_interopDefault(ejs);
46
46
  var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
47
47
 
48
48
  const template$1 = `
49
- const Path = require('path');
50
- // @ts-ignore
51
- const withPreconstruct = require('@preconstruct/next');
49
+ const keystoneConfig = require('@keystone-6/core/___internal-do-not-use-will-break-in-patch/admin-ui/next-config').config;
52
50
 
53
- module.exports = withPreconstruct({
54
- typescript: {
55
- ignoreBuildErrors: true,
56
- },
57
- env: {
58
- NEXTAUTH_URL: process.env.NEXTAUTH_URL || 'http://localhost:<%= process.env.PORT || 3000 %><%= keystonePath || '' %>/api/auth',
59
- },
60
- eslint: {
61
- ignoreDuringBuilds: true,
62
- },
63
- webpack(config, { isServer }) {
64
- config.resolve.alias = {
65
- ...config.resolve.alias,
66
- react: Path.dirname(require.resolve('react/package.json')),
67
- 'react-dom': Path.dirname(require.resolve('react-dom/package.json')),
68
- '@keystone-6/core': Path.dirname(
69
- require.resolve('@keystone-6/core/package.json')
70
- ),
71
- };
72
- if (isServer) {
73
- config.externals = [
74
- ...config.externals,
75
- /@keystone-6\\/core(?!\\/___internal-do-not-use-will-break-in-patch\\/admin-ui\\/id-field-view|\\/fields\\/types\\/[^\\/]+\\/views)/,
76
- /.prisma\\/client/
77
- ];
78
- // we need to set these to true so that when __dirname/__filename is used
79
- // to resolve the location of field views, we will get a path that we can use
80
- // rather than just the __dirname/__filename of the generated file.
81
- // https://webpack.js.org/configuration/node/#node__filename
82
- (_config$node = config.node) !== null && _config$node !== void 0 ? _config$node : config.node = {};
83
- config.node.__dirname = true;
84
- config.node.__filename = true;
85
- }
86
- return config;
87
- },
88
- <% if (keystonePath) { %>
89
- <% if (process.env.NODE_ENV != 'production') { %>
90
- async rewrites() {
91
- return [
92
- {
93
- source: '/api/__keystone_api_build',
94
- destination: 'http://localhost:<%= process.env.PORT || 3000 %><%= keystonePath || '' %>/api/__keystone_api_build',
95
- basePath: false
96
- }
97
- ];
98
- },
99
- <% }%>
100
- basePath: '<%= keystonePath || '' %>'
101
- <% } %>
102
- });
103
- `;
51
+ module.exports = {
52
+ ...keystoneConfig,
53
+ basePath: '<%= keystonePath || '' %>'
54
+ };`;
104
55
  const nextConfigTemplate = _ref => {
105
56
  let {
106
57
  keystonePath
@@ -124,17 +75,14 @@ function getBaseAuthSchema(_ref) {
124
75
  types: [base.object(listKey)],
125
76
  resolveType: (root, context) => {
126
77
  var _context$session;
127
-
128
78
  return (_context$session = context.session) === null || _context$session === void 0 ? void 0 : _context$session.listKey;
129
79
  }
130
80
  }),
131
-
132
81
  resolve(root, args, _ref2) {
133
82
  let {
134
83
  session,
135
84
  db
136
85
  } = _ref2;
137
-
138
86
  if (typeof (session === null || session === void 0 ? void 0 : session.itemId) === 'string' && typeof session.listKey === 'string') {
139
87
  return db[session.listKey].findOne({
140
88
  where: {
@@ -142,10 +90,8 @@ function getBaseAuthSchema(_ref) {
142
90
  }
143
91
  });
144
92
  }
145
-
146
93
  return null;
147
94
  }
148
-
149
95
  })
150
96
  }
151
97
  };
@@ -160,7 +106,6 @@ const getSchemaExtension = _ref => {
160
106
  } = _ref;
161
107
  return core.graphql.extend(base => {
162
108
  var _context;
163
-
164
109
  const baseSchema = getBaseAuthSchema({
165
110
  listKey,
166
111
  base
@@ -210,6 +155,7 @@ const authTemplate = _ref => {
210
155
  };
211
156
 
212
157
  const _excluded = ["get", "end"];
158
+
213
159
  /**
214
160
  * createAuth function
215
161
  *
@@ -233,6 +179,7 @@ function createAuth(_ref) {
233
179
  // part of the createAuth API (in which case its use cases need to be documented and tested)
234
180
  // or whether always being true is what we want, in which case we can refactor our code
235
181
  // to match this. -TL
182
+
236
183
  const customPath = !keystonePath || keystonePath === '/' ? '' : keystonePath;
237
184
  /**
238
185
  * pageMiddleware
@@ -244,40 +191,25 @@ function createAuth(_ref) {
244
191
  * - to the init page when initFirstItem is configured, and there are no user in the database
245
192
  * - to the signin page when no valid session is present
246
193
  */
247
-
248
- const pageMiddleware = async _ref2 => {
194
+ const authMiddleware = async _ref2 => {
249
195
  let {
250
196
  context,
251
- isValidSession
197
+ wasAccessAllowed
252
198
  } = _ref2;
253
199
  const {
254
200
  req,
255
201
  session
256
202
  } = context;
257
203
  const pathname = url__default["default"].parse(req === null || req === void 0 ? void 0 : req.url).pathname;
258
-
259
- if (isValidSession) {
260
- if (pathname === `${customPath}/api/auth/signin` || pages !== null && pages !== void 0 && pages.signIn && _includesInstanceProperty__default["default"](pathname).call(pathname, pages === null || pages === void 0 ? void 0 : pages.signIn)) {
261
- return {
262
- kind: 'redirect',
263
- to: `${customPath}`
264
- };
265
- }
266
-
204
+ if (wasAccessAllowed) {
267
205
  if (customPath !== '' && pathname === '/') {
268
206
  return {
269
207
  kind: 'redirect',
270
208
  to: `${customPath}`
271
209
  };
272
210
  }
273
-
274
211
  return;
275
212
  }
276
-
277
- if (_includesInstanceProperty__default["default"](pathname).call(pathname, '/_next/') || _includesInstanceProperty__default["default"](pathname).call(pathname, '/api/auth/') || pages !== null && pages !== void 0 && pages.signIn && _includesInstanceProperty__default["default"](pathname).call(pathname, pages === null || pages === void 0 ? void 0 : pages.signIn) || pages !== null && pages !== void 0 && pages.error && _includesInstanceProperty__default["default"](pathname).call(pathname, pages === null || pages === void 0 ? void 0 : pages.error) || pages !== null && pages !== void 0 && pages.signOut && _includesInstanceProperty__default["default"](pathname).call(pathname, pages === null || pages === void 0 ? void 0 : pages.signOut)) {
278
- return;
279
- }
280
-
281
213
  if (!session && !_includesInstanceProperty__default["default"](pathname).call(pathname, `${customPath}/api/auth/`)) {
282
214
  return {
283
215
  kind: 'redirect',
@@ -285,17 +217,16 @@ function createAuth(_ref) {
285
217
  };
286
218
  }
287
219
  };
220
+
288
221
  /**
289
- * getAdditionalFiles
222
+ * authGetAdditionalFiles
290
223
  *
291
224
  * This function adds files to be generated into the Admin UI build. Must be added to the
292
225
  * ui.getAdditionalFiles config.
293
226
  *
294
227
  * The signin page is always included, and the init page is included when initFirstItem is set
295
228
  */
296
-
297
-
298
- const getAdditionalFiles = () => {
229
+ const authGetAdditionalFiles = () => {
299
230
  const filesToWrite = [{
300
231
  mode: 'write',
301
232
  outputPath: 'pages/api/auth/[...nextauth].js',
@@ -315,102 +246,91 @@ function createAuth(_ref) {
315
246
  }];
316
247
  return filesToWrite;
317
248
  };
249
+
318
250
  /**
319
251
  * publicAuthPages
320
252
  *
321
253
  * Must be added to the ui.publicPages config
322
254
  */
323
-
324
-
325
- 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
255
+ 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`];
256
+ // TODO: Add Provider Types
326
257
  // @ts-ignore
327
-
328
258
  function addPages(provider) {
329
259
  const name = provider.id;
330
- publicPages.push(`${customPath}/api/auth/signin/${name}`);
331
- publicPages.push(`${customPath}/api/auth/callback/${name}`);
260
+ authPublicPages.push(`${customPath}/api/auth/signin/${name}`);
261
+ authPublicPages.push(`${customPath}/api/auth/callback/${name}`);
332
262
  }
333
-
334
263
  _mapInstanceProperty__default["default"](providers).call(providers, addPages);
264
+
335
265
  /**
336
266
  * extendGraphqlSchema
337
267
  *
338
268
  * Must be added to the extendGraphqlSchema config. Can be composed.
339
269
  */
340
-
341
-
342
270
  const extendGraphqlSchema = getSchemaExtension({
343
271
  identityField,
344
272
  listKey
345
273
  });
274
+
346
275
  /**
347
276
  * validateConfig
348
277
  *
349
278
  * Validates the provided auth config; optional step when integrating auth
350
279
  */
351
-
352
280
  const validateConfig = keystoneConfig => {
353
281
  const listConfig = keystoneConfig.lists[listKey];
354
-
355
282
  if (listConfig === undefined) {
356
283
  const msg = `A createAuth() invocation specifies the list "${listKey}" but no list with that key has been defined.`;
357
284
  throw new Error(msg);
358
- } // TODO: Check if providers
285
+ }
286
+
287
+ // TODO: Check if providers
359
288
  // TODO: Check other required commands/data
289
+
360
290
  // TODO: Check for String-like typing for identityField? How?
361
291
  // TODO: Validate that the identifyField is unique.
362
292
  // TODO: If this field isn't required, what happens if I try to log in as `null`?
363
-
364
-
365
293
  const identityFieldConfig = listConfig.fields[identityField];
366
-
367
294
  if (identityFieldConfig === undefined) {
368
295
  const identityFieldName = _JSON$stringify__default["default"](identityField);
369
-
370
296
  const msg = `A createAuth() invocation for the "${listKey}" list specifies ${identityFieldName} as its identityField but no field with that key exists on the list.`;
371
297
  throw new Error(msg);
372
298
  }
373
299
  };
300
+
374
301
  /**
375
302
  * withItemData
376
303
  *
377
304
  * Automatically injects a session.data value with the authenticated item
378
305
  */
379
-
380
306
  /* TODO:
381
307
  - [ ] We could support additional where input to validate item sessions (e.g an isEnabled boolean)
382
308
  */
383
-
384
-
385
309
  const withItemData = _sessionStrategy => {
386
310
  const {
387
- get,
388
- end
389
- } = _sessionStrategy,
390
- sessionStrategy = _objectWithoutProperties(_sessionStrategy, _excluded);
391
-
311
+ get,
312
+ end
313
+ } = _sessionStrategy,
314
+ sessionStrategy = _objectWithoutProperties(_sessionStrategy, _excluded);
392
315
  return _objectSpread(_objectSpread({}, sessionStrategy), {}, {
393
316
  get: async _ref3 => {
394
317
  var _req$headers, _req$headers$authoriz;
395
-
396
318
  let {
397
- req,
398
- createContext
319
+ context
399
320
  } = _ref3;
321
+ const {
322
+ req
323
+ } = context;
400
324
  const pathname = url__default["default"].parse(req === null || req === void 0 ? void 0 : req.url).pathname;
401
325
  let nextSession;
402
-
326
+ if (!req) return;
403
327
  if (_includesInstanceProperty__default["default"](pathname).call(pathname, '/api/auth')) {
404
328
  return;
405
329
  }
406
-
407
- const sudoContext = createContext({
408
- sudo: true
409
- });
410
-
330
+ const sudoContext = context.sudo();
411
331
  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') {
412
332
  nextSession = await jwt.getToken({
413
- req,
333
+ req: req,
414
334
  secret: sessionSecret
415
335
  });
416
336
  } else {
@@ -418,11 +338,9 @@ function createAuth(_ref) {
418
338
  req
419
339
  });
420
340
  }
421
-
422
341
  if (!nextSession || !nextSession.listKey || nextSession.listKey !== listKey || !nextSession.itemId || !sudoContext.query[listKey] || !nextSession.itemId) {
423
342
  return;
424
343
  }
425
-
426
344
  const reqWithUser = req;
427
345
  reqWithUser.user = {
428
346
  istKey: nextSession.listKey,
@@ -430,8 +348,7 @@ function createAuth(_ref) {
430
348
  data: nextSession.data
431
349
  };
432
350
  const userSession = await get({
433
- req: reqWithUser,
434
- createContext
351
+ context
435
352
  });
436
353
  return _objectSpread(_objectSpread(_objectSpread({}, userSession), nextSession), {}, {
437
354
  data: nextSession.data,
@@ -441,16 +358,17 @@ function createAuth(_ref) {
441
358
  },
442
359
  end: async _ref4 => {
443
360
  let {
444
- res,
445
- req,
446
- createContext
361
+ context
447
362
  } = _ref4;
448
363
  await end({
449
- res,
450
- req,
451
- createContext
364
+ context
452
365
  });
453
366
  const TOKEN_NAME = process.env.NODE_ENV === 'production' ? '__Secure-next-auth.session-token' : 'next-auth.session-token';
367
+ const {
368
+ req,
369
+ res
370
+ } = context;
371
+ if (!req || !res) return;
454
372
  res.setHeader('Set-Cookie', cookie__namespace.serialize(TOKEN_NAME, '', {
455
373
  maxAge: 0,
456
374
  expires: new Date(),
@@ -464,6 +382,12 @@ function createAuth(_ref) {
464
382
  }
465
383
  });
466
384
  };
385
+ function defaultIsAccessAllowed(_ref5) {
386
+ let {
387
+ session
388
+ } = _ref5;
389
+ return session !== undefined;
390
+ }
467
391
  /**
468
392
  * withAuth
469
393
  *
@@ -474,47 +398,37 @@ function createAuth(_ref) {
474
398
  * It validates the auth config against the provided keystone config, and preserves existing
475
399
  * config by composing existing extendGraphqlSchema functions and ui config.
476
400
  */
477
-
478
-
479
401
  const withAuth = keystoneConfig => {
402
+ var _ui;
480
403
  validateConfig(keystoneConfig);
481
404
  let {
482
405
  ui
483
406
  } = keystoneConfig;
484
-
485
- if (keystoneConfig.ui) {
486
- var _keystoneConfig$ui;
487
-
488
- ui = _objectSpread(_objectSpread({}, keystoneConfig.ui), {}, {
489
- publicPages: [...(keystoneConfig.ui.publicPages || []), ...publicPages],
490
- getAdditionalFiles: [...(((_keystoneConfig$ui = keystoneConfig.ui) === null || _keystoneConfig$ui === void 0 ? void 0 : _keystoneConfig$ui.getAdditionalFiles) || []), getAdditionalFiles],
491
- pageMiddleware: async args => {
492
- var _keystoneConfig$ui2, _keystoneConfig$ui2$p;
493
-
494
- return (await pageMiddleware(args)) ?? (keystoneConfig === null || keystoneConfig === void 0 ? void 0 : (_keystoneConfig$ui2 = keystoneConfig.ui) === null || _keystoneConfig$ui2 === void 0 ? void 0 : (_keystoneConfig$ui2$p = _keystoneConfig$ui2.pageMiddleware) === null || _keystoneConfig$ui2$p === void 0 ? void 0 : _keystoneConfig$ui2$p.call(_keystoneConfig$ui2, args));
495
- },
407
+ if (!((_ui = ui) !== null && _ui !== void 0 && _ui.isDisabled)) {
408
+ const {
409
+ getAdditionalFiles = [],
410
+ isAccessAllowed = defaultIsAccessAllowed,
411
+ pageMiddleware,
412
+ publicPages = []
413
+ } = ui || {};
414
+ ui = _objectSpread(_objectSpread({}, ui), {}, {
415
+ publicPages: [...publicPages, ...authPublicPages],
496
416
  isAccessAllowed: async context => {
497
- var _context$req, _keystoneConfig$ui3;
498
-
499
- const {
500
- req
501
- } = context;
502
- 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
503
-
504
- if (_includesInstanceProperty__default["default"](pathname).call(pathname, '/_next/')) {
505
- return true;
506
- } // Allow keystone to access /api/__keystone_api_build for hot reloading
507
-
508
-
509
- if (process.env.NODE_ENV !== 'production' && ((_context$req = context.req) === null || _context$req === void 0 ? void 0 : _context$req.url) !== undefined && new _URL__default["default"](context.req.url, 'http://example.com').pathname === `${customPath}/api/__keystone_api_build`) {
417
+ var _context$req;
418
+ const pathname = url__default["default"].parse((_context$req = context.req) === null || _context$req === void 0 ? void 0 : _context$req.url).pathname;
419
+ if (_startsWithInstanceProperty__default["default"](pathname).call(pathname, `${customPath}/_next`) || _startsWithInstanceProperty__default["default"](pathname).call(pathname, `${customPath}/__next`) || _startsWithInstanceProperty__default["default"](pathname).call(pathname, `${customPath}/api/auth/`) || pages !== null && pages !== void 0 && pages.signIn && _includesInstanceProperty__default["default"](pathname).call(pathname, pages === null || pages === void 0 ? void 0 : pages.signIn) || pages !== null && pages !== void 0 && pages.error && _includesInstanceProperty__default["default"](pathname).call(pathname, pages === null || pages === void 0 ? void 0 : pages.error) || pages !== null && pages !== void 0 && pages.signOut && _includesInstanceProperty__default["default"](pathname).call(pathname, pages === null || pages === void 0 ? void 0 : pages.signOut)) {
510
420
  return true;
511
421
  }
512
-
513
- return (_keystoneConfig$ui3 = keystoneConfig.ui) !== null && _keystoneConfig$ui3 !== void 0 && _keystoneConfig$ui3.isAccessAllowed ? keystoneConfig.ui.isAccessAllowed(context) : context.session !== undefined;
422
+ return await isAccessAllowed(context);
423
+ },
424
+ getAdditionalFiles: [...getAdditionalFiles, authGetAdditionalFiles],
425
+ pageMiddleware: async args => {
426
+ const shouldRedirect = await authMiddleware(args);
427
+ if (shouldRedirect) return shouldRedirect;
428
+ return pageMiddleware === null || pageMiddleware === void 0 ? void 0 : pageMiddleware(args);
514
429
  }
515
430
  });
516
431
  }
517
-
518
432
  if (!keystoneConfig.session) throw new TypeError('Missing .session configuration');
519
433
  const session = withItemData(keystoneConfig.session);
520
434
  const existingExtendGraphQLSchema = keystoneConfig.extendGraphqlSchema;
@@ -529,16 +443,15 @@ function createAuth(_ref) {
529
443
  extendGraphqlSchema: existingExtendGraphQLSchema ? schema => existingExtendGraphQLSchema(extendGraphqlSchema(schema)) : extendGraphqlSchema
530
444
  });
531
445
  };
532
-
533
446
  return {
534
- withAuth // In the future we may want to return the following so that developers can
447
+ withAuth
448
+ // In the future we may want to return the following so that developers can
535
449
  // roll their own. This is pending a review of the use cases this might be
536
450
  // appropriate for, along with documentation and testing.
537
451
  // ui: { enableSessionItem: true, pageMiddleware, getAdditionalFiles, publicPages },
538
452
  // fields,
539
453
  // extendGraphqlSchema,
540
454
  // validateConfig,
541
-
542
455
  };
543
456
  }
544
457