@opensaas/keystone-nextjs-auth 20.5.0 → 21.1.1
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.
- package/CHANGELOG.md +20 -0
- package/README.md +5 -3
- package/dist/declarations/src/gql/getBaseAuthSchema.d.ts +1 -3
- package/dist/declarations/src/index.d.ts +5 -5
- package/dist/declarations/src/pages/NextAuthPage.d.ts +16 -9
- package/dist/declarations/src/schema.d.ts +1 -3
- package/dist/declarations/src/templates/auth.d.ts +4 -12
- package/dist/declarations/src/types.d.ts +17 -20
- package/dist/opensaas-keystone-nextjs-auth.cjs.dev.js +77 -92
- package/dist/opensaas-keystone-nextjs-auth.cjs.prod.js +75 -92
- package/dist/opensaas-keystone-nextjs-auth.esm.js +77 -92
- package/package.json +8 -7
- package/pages/NextAuthPage/dist/opensaas-keystone-nextjs-auth-pages-NextAuthPage.cjs.dev.js +37 -32
- package/pages/NextAuthPage/dist/opensaas-keystone-nextjs-auth-pages-NextAuthPage.cjs.prod.js +37 -32
- package/pages/NextAuthPage/dist/opensaas-keystone-nextjs-auth-pages-NextAuthPage.esm.js +37 -32
- package/src/gql/getBaseAuthSchema.ts +0 -4
- package/src/index.ts +96 -94
- package/src/pages/NextAuthPage.tsx +59 -38
- package/src/schema.ts +0 -22
- package/src/templates/auth.ts +11 -28
- package/src/templates/next-config.ts +3 -0
- package/src/types.ts +20 -21
- package/src/gql/getInitFirstItemSchema.ts +0 -81
@@ -49,23 +49,42 @@ async function validateNextAuth(identityField, identity, protectIdentities, item
|
|
49
49
|
|
50
50
|
function NextAuthPage(props) {
|
51
51
|
const {
|
52
|
+
autoCreate,
|
53
|
+
cookies,
|
54
|
+
events,
|
55
|
+
identityField,
|
56
|
+
jwt,
|
57
|
+
listKey,
|
58
|
+
pages,
|
52
59
|
providers,
|
53
60
|
query,
|
54
|
-
|
61
|
+
resolver,
|
55
62
|
sessionData,
|
56
|
-
listKey,
|
57
|
-
autoCreate,
|
58
|
-
userMap,
|
59
|
-
accountMap,
|
60
|
-
profileMap,
|
61
63
|
sessionSecret
|
62
|
-
} = props;
|
64
|
+
} = props; // TODO: (v1.1). https://github.com/ijsto/keystone-6-oauth/projects/1#card-78602004
|
65
|
+
|
66
|
+
console.log('NextAuthPages... ', pages);
|
67
|
+
|
68
|
+
if (!query) {
|
69
|
+
console.error('NextAuthPage got no query.');
|
70
|
+
return null;
|
71
|
+
}
|
72
|
+
|
73
|
+
if (!providers || !providers.length) {
|
74
|
+
console.error('You need to provide at least one provider.');
|
75
|
+
return null;
|
76
|
+
}
|
77
|
+
|
63
78
|
const list = query[listKey];
|
64
79
|
const queryAPI = query[listKey];
|
65
80
|
const protectIdentities = true;
|
66
81
|
return NextAuth({
|
67
|
-
|
82
|
+
cookies,
|
68
83
|
providers,
|
84
|
+
pages: pages || {},
|
85
|
+
events: events || {},
|
86
|
+
jwt: jwt || {},
|
87
|
+
secret: sessionSecret,
|
69
88
|
callbacks: {
|
70
89
|
async signIn({
|
71
90
|
user,
|
@@ -82,28 +101,16 @@ function NextAuthPage(props) {
|
|
82
101
|
identity = 0;
|
83
102
|
}
|
84
103
|
|
85
|
-
const
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
}
|
92
|
-
} // eslint-disable-next-line no-restricted-syntax
|
93
|
-
|
104
|
+
const userInput = resolver ? await resolver({
|
105
|
+
user,
|
106
|
+
account,
|
107
|
+
profile
|
108
|
+
}) : {};
|
109
|
+
const result = await validateNextAuth(identityField, identity, protectIdentities, queryAPI); // ID
|
94
110
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
}
|
99
|
-
} // eslint-disable-next-line no-restricted-syntax
|
100
|
-
|
101
|
-
|
102
|
-
for (const key in profileMap) {
|
103
|
-
if (Object.prototype.hasOwnProperty.call(profileMap, key)) {
|
104
|
-
data[key] = profile[profileMap[key]];
|
105
|
-
}
|
106
|
-
}
|
111
|
+
const data = _objectSpread({
|
112
|
+
[identityField]: identity
|
113
|
+
}, userInput);
|
107
114
|
|
108
115
|
if (!result.success) {
|
109
116
|
if (!autoCreate) {
|
@@ -158,9 +165,7 @@ function NextAuthPage(props) {
|
|
158
165
|
const result = await validateNextAuth(identityField, identity, protectIdentities, queryAPI);
|
159
166
|
|
160
167
|
if (!result.success) {
|
161
|
-
return
|
162
|
-
result: false
|
163
|
-
};
|
168
|
+
return token;
|
164
169
|
}
|
165
170
|
|
166
171
|
token.itemId = result.item.id;
|
@@ -1,15 +1,11 @@
|
|
1
1
|
import type { BaseItem } from '@keystone-6/core/types';
|
2
2
|
import { graphql } from '@keystone-6/core';
|
3
3
|
|
4
|
-
import { AuthGqlNames } from '../types';
|
5
|
-
|
6
4
|
export function getBaseAuthSchema({
|
7
5
|
listKey,
|
8
|
-
gqlNames,
|
9
6
|
base,
|
10
7
|
}: {
|
11
8
|
listKey: string;
|
12
|
-
gqlNames: AuthGqlNames;
|
13
9
|
base: graphql.BaseSchemaMeta;
|
14
10
|
}) {
|
15
11
|
const extension = {
|
package/src/index.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import url from
|
1
|
+
import url from "url";
|
2
2
|
import {
|
3
3
|
AdminFileToWrite,
|
4
4
|
BaseListTypeInfo,
|
@@ -7,23 +7,19 @@ import {
|
|
7
7
|
AdminUIConfig,
|
8
8
|
SessionStrategy,
|
9
9
|
BaseKeystoneTypeInfo,
|
10
|
-
} from
|
11
|
-
import { getSession } from
|
12
|
-
import { getToken } from
|
13
|
-
import
|
14
|
-
|
15
|
-
import
|
16
|
-
|
10
|
+
} from "@keystone-6/core/types";
|
11
|
+
import { getSession } from "next-auth/react";
|
12
|
+
import { getToken } from "next-auth/jwt";
|
13
|
+
import { Provider } from "next-auth/providers";
|
14
|
+
|
15
|
+
import * as cookie from "cookie";
|
16
|
+
|
17
|
+
import { nextConfigTemplate } from "./templates/next-config";
|
17
18
|
// import * as Path from 'path';
|
18
19
|
|
19
|
-
import {
|
20
|
-
|
21
|
-
|
22
|
-
KeystoneAuthConfig,
|
23
|
-
NextAuthSession,
|
24
|
-
} from './types';
|
25
|
-
import { getSchemaExtension } from './schema';
|
26
|
-
import { authTemplate } from './templates/auth';
|
20
|
+
import { AuthConfig, KeystoneOAuthConfig, NextAuthSession } from "./types";
|
21
|
+
import { getSchemaExtension } from "./schema";
|
22
|
+
import { authTemplate } from "./templates/auth";
|
27
23
|
|
28
24
|
/**
|
29
25
|
* createAuth function
|
@@ -31,35 +27,25 @@ import { authTemplate } from './templates/auth';
|
|
31
27
|
* Generates config for Keystone to implement standard auth features.
|
32
28
|
*/
|
33
29
|
|
34
|
-
export type { NextAuthProviders,
|
30
|
+
export type { NextAuthProviders, KeystoneOAuthConfig } from "./types";
|
35
31
|
export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
|
36
|
-
listKey,
|
37
|
-
identityField,
|
38
|
-
sessionData,
|
39
32
|
autoCreate,
|
40
|
-
|
41
|
-
|
42
|
-
|
33
|
+
cookies,
|
34
|
+
identityField,
|
35
|
+
listKey,
|
43
36
|
keystonePath,
|
37
|
+
pages,
|
38
|
+
resolver,
|
44
39
|
providers,
|
40
|
+
sessionData,
|
45
41
|
sessionSecret,
|
46
42
|
}: AuthConfig<GeneratedListTypes>) {
|
47
43
|
// The protectIdentities flag is currently under review to see whether it should be
|
48
44
|
// part of the createAuth API (in which case its use cases need to be documented and tested)
|
49
45
|
// or whether always being true is what we want, in which case we can refactor our code
|
50
46
|
// to match this. -TL
|
51
|
-
const gqlNames: AuthGqlNames = {
|
52
|
-
// Core
|
53
|
-
authenticateItemWithPassword: `authenticate${listKey}WithPassword`,
|
54
|
-
ItemAuthenticationWithPasswordResult: `${listKey}AuthenticationWithPasswordResult`,
|
55
|
-
ItemAuthenticationWithPasswordSuccess: `${listKey}AuthenticationWithPasswordSuccess`,
|
56
|
-
ItemAuthenticationWithPasswordFailure: `${listKey}AuthenticationWithPasswordFailure`,
|
57
|
-
// Initial data
|
58
|
-
CreateInitialInput: `CreateInitial${listKey}Input`,
|
59
|
-
createInitialItem: `createInitial${listKey}`,
|
60
|
-
};
|
61
47
|
|
62
|
-
const customPath = !keystonePath || keystonePath ===
|
48
|
+
const customPath = !keystonePath || keystonePath === "/" ? "" : keystonePath;
|
63
49
|
/**
|
64
50
|
* pageMiddleware
|
65
51
|
*
|
@@ -70,25 +56,34 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
|
|
70
56
|
* - to the init page when initFirstItem is configured, and there are no user in the database
|
71
57
|
* - to the signin page when no valid session is present
|
72
58
|
*/
|
73
|
-
const pageMiddleware: AdminUIConfig<BaseKeystoneTypeInfo>[
|
59
|
+
const pageMiddleware: AdminUIConfig<BaseKeystoneTypeInfo>["pageMiddleware"] =
|
74
60
|
async ({ context, isValidSession }) => {
|
75
61
|
const { req, session } = context;
|
76
62
|
const pathname = url.parse(req?.url!).pathname!;
|
77
|
-
|
78
|
-
return;
|
79
|
-
}
|
63
|
+
|
80
64
|
if (isValidSession) {
|
81
65
|
if (pathname === `${customPath}/api/auth/signin`) {
|
82
|
-
return { kind:
|
66
|
+
return { kind: "redirect", to: `${customPath}` };
|
83
67
|
}
|
84
|
-
if (customPath !==
|
85
|
-
return { kind:
|
68
|
+
if (customPath !== "" && pathname === "/") {
|
69
|
+
return { kind: "redirect", to: `${customPath}` };
|
86
70
|
}
|
87
71
|
return;
|
88
72
|
}
|
89
|
-
|
73
|
+
if (
|
74
|
+
pathname.includes("/_next/") ||
|
75
|
+
pathname.includes("/api/auth/") ||
|
76
|
+
pathname.includes(pages?.signIn) ||
|
77
|
+
pathname.includes(pages?.error) ||
|
78
|
+
pathname.includes(pages?.signOut)
|
79
|
+
) {
|
80
|
+
return;
|
81
|
+
}
|
90
82
|
if (!session && !pathname.includes(`${customPath}/api/auth/`)) {
|
91
|
-
return {
|
83
|
+
return {
|
84
|
+
kind: "redirect",
|
85
|
+
to: pages?.signIn || `${customPath}/api/auth/signin`,
|
86
|
+
};
|
92
87
|
}
|
93
88
|
};
|
94
89
|
|
@@ -103,23 +98,19 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
|
|
103
98
|
const getAdditionalFiles = () => {
|
104
99
|
const filesToWrite: AdminFileToWrite[] = [
|
105
100
|
{
|
106
|
-
mode:
|
107
|
-
outputPath:
|
101
|
+
mode: "write",
|
102
|
+
outputPath: "pages/api/auth/[...nextauth].js",
|
108
103
|
src: authTemplate({
|
109
|
-
|
104
|
+
autoCreate,
|
110
105
|
identityField,
|
111
|
-
sessionData,
|
112
106
|
listKey,
|
113
|
-
|
114
|
-
userMap,
|
115
|
-
accountMap,
|
116
|
-
profileMap,
|
107
|
+
sessionData,
|
117
108
|
sessionSecret,
|
118
109
|
}),
|
119
110
|
},
|
120
111
|
{
|
121
|
-
mode:
|
122
|
-
outputPath:
|
112
|
+
mode: "write",
|
113
|
+
outputPath: "next.config.js",
|
123
114
|
src: nextConfigTemplate({ keystonePath: customPath }),
|
124
115
|
},
|
125
116
|
];
|
@@ -132,13 +123,17 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
|
|
132
123
|
* Must be added to the ui.publicPages config
|
133
124
|
*/
|
134
125
|
const publicPages = [
|
126
|
+
`${customPath}/api/__keystone_api_build`,
|
135
127
|
`${customPath}/api/auth/csrf`,
|
136
128
|
`${customPath}/api/auth/signin`,
|
137
129
|
`${customPath}/api/auth/callback`,
|
138
130
|
`${customPath}/api/auth/session`,
|
139
131
|
`${customPath}/api/auth/providers`,
|
140
132
|
`${customPath}/api/auth/signout`,
|
133
|
+
`${customPath}/api/auth/error`,
|
141
134
|
];
|
135
|
+
// TODO: Add Provider Types
|
136
|
+
// @ts-ignore
|
142
137
|
function addPages(provider: Provider) {
|
143
138
|
const name = provider.id;
|
144
139
|
publicPages.push(`${customPath}/api/auth/signin/${name}`);
|
@@ -154,7 +149,6 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
|
|
154
149
|
const extendGraphqlSchema = getSchemaExtension({
|
155
150
|
identityField,
|
156
151
|
listKey,
|
157
|
-
gqlNames,
|
158
152
|
});
|
159
153
|
|
160
154
|
/**
|
@@ -169,13 +163,16 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
|
|
169
163
|
throw new Error(msg);
|
170
164
|
}
|
171
165
|
|
166
|
+
// TODO: Check if providers
|
167
|
+
// TODO: Check other required commands/data
|
168
|
+
|
172
169
|
// TODO: Check for String-like typing for identityField? How?
|
173
170
|
// TODO: Validate that the identifyField is unique.
|
174
171
|
// TODO: If this field isn't required, what happens if I try to log in as `null`?
|
175
172
|
const identityFieldConfig = listConfig.fields[identityField];
|
176
173
|
if (identityFieldConfig === undefined) {
|
177
|
-
const
|
178
|
-
const msg = `A createAuth() invocation for the "${listKey}" list specifies ${
|
174
|
+
const identityFieldName = JSON.stringify(identityField);
|
175
|
+
const msg = `A createAuth() invocation for the "${listKey}" list specifies ${identityFieldName} as its identityField but no field with that key exists on the list.`;
|
179
176
|
throw new Error(msg);
|
180
177
|
}
|
181
178
|
};
|
@@ -194,18 +191,25 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
|
|
194
191
|
const { get, start, ...sessionStrategy } = _sessionStrategy;
|
195
192
|
return {
|
196
193
|
...sessionStrategy,
|
197
|
-
start
|
194
|
+
start: async ({ res }) => {
|
195
|
+
console.log("start");
|
196
|
+
|
197
|
+
const session = await start({ res });
|
198
|
+
return session;
|
199
|
+
},
|
198
200
|
get: async ({ req }) => {
|
199
201
|
const pathname = url.parse(req?.url!).pathname!;
|
200
|
-
if (pathname.includes(
|
202
|
+
if (pathname.includes("/api/auth")) {
|
201
203
|
return;
|
202
204
|
}
|
203
|
-
if (req.headers.authorization?.split(
|
204
|
-
const
|
205
|
-
|
205
|
+
if (req.headers.authorization?.split(" ")[0] === "Bearer") {
|
206
|
+
const token = (await getToken({
|
207
|
+
req,
|
208
|
+
secret: sessionSecret,
|
209
|
+
})) as NextAuthSession;
|
206
210
|
|
207
211
|
if (token?.data?.id) {
|
208
|
-
return token
|
212
|
+
return token;
|
209
213
|
}
|
210
214
|
}
|
211
215
|
const nextSession: unknown = await getSession({ req });
|
@@ -216,18 +220,19 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
|
|
216
220
|
},
|
217
221
|
end: async ({ res, req }) => {
|
218
222
|
const TOKEN_NAME =
|
219
|
-
process.env.NODE_ENV ===
|
220
|
-
?
|
221
|
-
:
|
223
|
+
process.env.NODE_ENV === "production"
|
224
|
+
? "__Secure-next-auth.session-token"
|
225
|
+
: "next-auth.session-token";
|
222
226
|
res.setHeader(
|
223
|
-
|
224
|
-
cookie.serialize(TOKEN_NAME,
|
227
|
+
"Set-Cookie",
|
228
|
+
cookie.serialize(TOKEN_NAME, "", {
|
225
229
|
maxAge: 0,
|
226
230
|
expires: new Date(),
|
227
231
|
httpOnly: true,
|
228
|
-
secure: process.env.NODE_ENV ===
|
229
|
-
path:
|
230
|
-
sameSite:
|
232
|
+
secure: process.env.NODE_ENV === "production",
|
233
|
+
path: "/",
|
234
|
+
sameSite: "lax",
|
235
|
+
// TODO: Update parse to URL
|
231
236
|
domain: url.parse(req.url as string).hostname as string,
|
232
237
|
})
|
233
238
|
);
|
@@ -245,7 +250,7 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
|
|
245
250
|
* It validates the auth config against the provided keystone config, and preserves existing
|
246
251
|
* config by composing existing extendGraphqlSchema functions and ui config.
|
247
252
|
*/
|
248
|
-
const withAuth = (keystoneConfig: KeystoneConfig):
|
253
|
+
const withAuth = (keystoneConfig: KeystoneConfig): KeystoneOAuthConfig => {
|
249
254
|
validateConfig(keystoneConfig);
|
250
255
|
let { ui } = keystoneConfig;
|
251
256
|
if (keystoneConfig.ui) {
|
@@ -261,47 +266,44 @@ export function createAuth<GeneratedListTypes extends BaseListTypeInfo>({
|
|
261
266
|
keystoneConfig?.ui?.pageMiddleware?.(args),
|
262
267
|
enableSessionItem: true,
|
263
268
|
isAccessAllowed: async (context: KeystoneContext) => {
|
269
|
+
const { req } = context;
|
270
|
+
const pathname = url.parse(req?.url!).pathname!;
|
271
|
+
|
272
|
+
// Allow nextjs scripts and static files to be accessed without auth
|
273
|
+
if (pathname.includes("/_next/")) {
|
274
|
+
return true;
|
275
|
+
}
|
276
|
+
|
277
|
+
// Allow keystone to access /api/__keystone_api_build for hot reloading
|
264
278
|
if (
|
265
|
-
process.env.NODE_ENV !==
|
279
|
+
process.env.NODE_ENV !== "production" &&
|
266
280
|
context.req?.url !== undefined &&
|
267
|
-
new URL(context.req.url,
|
281
|
+
new URL(context.req.url, "http://example.com").pathname ===
|
268
282
|
`${customPath}/api/__keystone_api_build`
|
269
283
|
) {
|
270
284
|
return true;
|
271
285
|
}
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
? headers['x-forwarded-host'] || headers.host
|
277
|
-
: null;
|
278
|
-
const thisUrl = headers?.referer
|
279
|
-
? new URL(headers.referer)
|
280
|
-
: undefined;
|
281
|
-
const accessingInitPage =
|
282
|
-
thisUrl?.pathname === '/init' &&
|
283
|
-
thisUrl?.host === host &&
|
284
|
-
(await context.sudo().query[listKey].count({})) === 0;
|
285
|
-
return (
|
286
|
-
accessingInitPage ||
|
287
|
-
(keystoneConfig.ui?.isAccessAllowed
|
288
|
-
? keystoneConfig.ui.isAccessAllowed(context)
|
289
|
-
: context.session !== undefined)
|
290
|
-
);
|
286
|
+
|
287
|
+
return keystoneConfig.ui?.isAccessAllowed
|
288
|
+
? keystoneConfig.ui.isAccessAllowed(context)
|
289
|
+
: context.session !== undefined;
|
291
290
|
},
|
292
291
|
};
|
293
292
|
}
|
294
293
|
|
295
294
|
if (!keystoneConfig.session)
|
296
|
-
throw new TypeError(
|
295
|
+
throw new TypeError("Missing .session configuration");
|
297
296
|
const session = withItemData(keystoneConfig.session);
|
298
297
|
|
299
298
|
const existingExtendGraphQLSchema = keystoneConfig.extendGraphqlSchema;
|
300
299
|
return {
|
301
300
|
...keystoneConfig,
|
302
301
|
ui,
|
303
|
-
|
302
|
+
cookies,
|
304
303
|
providers,
|
304
|
+
pages,
|
305
|
+
resolver,
|
306
|
+
session,
|
305
307
|
lists: {
|
306
308
|
...keystoneConfig.lists,
|
307
309
|
},
|
@@ -1,43 +1,74 @@
|
|
1
|
-
import NextAuth
|
1
|
+
import NextAuth, {
|
2
|
+
CookiesOptions,
|
3
|
+
EventCallbacks,
|
4
|
+
PagesOptions,
|
5
|
+
} from 'next-auth';
|
2
6
|
import type { KeystoneListsAPI } from '@keystone-6/core/types';
|
3
7
|
import { Provider } from 'next-auth/providers';
|
8
|
+
import { JWTOptions } from 'next-auth/jwt';
|
4
9
|
import { validateNextAuth } from '../lib/validateNextAuth';
|
5
10
|
|
6
|
-
//
|
7
|
-
type
|
11
|
+
// TODO: See if possible to merge with `type AuthConfig`
|
12
|
+
type CoreNextAuthPageProps = {
|
13
|
+
autoCreate: boolean;
|
14
|
+
cookies?: Partial<CookiesOptions>;
|
15
|
+
events?: Partial<EventCallbacks>;
|
8
16
|
identityField: string;
|
9
|
-
|
10
|
-
providers: Provider[];
|
11
|
-
query: KeystoneListsAPI<any>;
|
12
|
-
sessionData: string;
|
17
|
+
jwt?: Partial<JWTOptions>;
|
13
18
|
listKey: string;
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
19
|
+
pages?: Partial<PagesOptions>;
|
20
|
+
providers?: Provider[];
|
21
|
+
resolver?: Function | undefined;
|
22
|
+
sessionData: string | undefined;
|
18
23
|
sessionSecret: string;
|
19
24
|
};
|
20
25
|
|
26
|
+
type NextAuthGglProps = {
|
27
|
+
mutationName?: string;
|
28
|
+
query?: KeystoneListsAPI<any>;
|
29
|
+
};
|
30
|
+
|
31
|
+
export type NextAuthPageProps = CoreNextAuthPageProps & NextAuthGglProps;
|
32
|
+
|
21
33
|
export default function NextAuthPage(props: NextAuthPageProps) {
|
22
34
|
const {
|
35
|
+
autoCreate,
|
36
|
+
cookies,
|
37
|
+
events,
|
38
|
+
identityField,
|
39
|
+
jwt,
|
40
|
+
listKey,
|
41
|
+
pages,
|
23
42
|
providers,
|
24
43
|
query,
|
25
|
-
|
44
|
+
resolver,
|
26
45
|
sessionData,
|
27
|
-
listKey,
|
28
|
-
autoCreate,
|
29
|
-
userMap,
|
30
|
-
accountMap,
|
31
|
-
profileMap,
|
32
46
|
sessionSecret,
|
33
47
|
} = props;
|
48
|
+
// TODO: (v1.1). https://github.com/ijsto/keystone-6-oauth/projects/1#card-78602004
|
49
|
+
console.log('NextAuthPages... ', pages);
|
50
|
+
|
51
|
+
if (!query) {
|
52
|
+
console.error('NextAuthPage got no query.');
|
53
|
+
return null;
|
54
|
+
}
|
55
|
+
|
56
|
+
if (!providers || !providers.length) {
|
57
|
+
console.error('You need to provide at least one provider.');
|
58
|
+
return null;
|
59
|
+
}
|
60
|
+
|
34
61
|
const list = query[listKey];
|
35
62
|
const queryAPI = query[listKey];
|
36
63
|
const protectIdentities = true;
|
37
64
|
|
38
65
|
return NextAuth({
|
39
|
-
|
66
|
+
cookies,
|
40
67
|
providers,
|
68
|
+
pages: pages || {},
|
69
|
+
events: events || {},
|
70
|
+
jwt: jwt || {},
|
71
|
+
secret: sessionSecret,
|
41
72
|
callbacks: {
|
42
73
|
async signIn({ user, account, profile }) {
|
43
74
|
let identity;
|
@@ -48,31 +79,21 @@ export default function NextAuthPage(props: NextAuthPageProps) {
|
|
48
79
|
} else {
|
49
80
|
identity = 0;
|
50
81
|
}
|
82
|
+
const userInput = resolver
|
83
|
+
? await resolver({ user, account, profile })
|
84
|
+
: {};
|
85
|
+
|
51
86
|
const result = await validateNextAuth(
|
52
87
|
identityField,
|
53
88
|
identity,
|
54
89
|
protectIdentities,
|
55
90
|
queryAPI
|
56
91
|
);
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
}
|
63
|
-
}
|
64
|
-
// eslint-disable-next-line no-restricted-syntax
|
65
|
-
for (const key in accountMap) {
|
66
|
-
if (Object.prototype.hasOwnProperty.call(accountMap, key)) {
|
67
|
-
data[key] = account[accountMap[key]];
|
68
|
-
}
|
69
|
-
}
|
70
|
-
// eslint-disable-next-line no-restricted-syntax
|
71
|
-
for (const key in profileMap) {
|
72
|
-
if (Object.prototype.hasOwnProperty.call(profileMap, key)) {
|
73
|
-
data[key] = profile[profileMap[key]];
|
74
|
-
}
|
75
|
-
}
|
92
|
+
// ID
|
93
|
+
const data: any = {
|
94
|
+
[identityField]: identity,
|
95
|
+
...userInput,
|
96
|
+
};
|
76
97
|
|
77
98
|
if (!result.success) {
|
78
99
|
if (!autoCreate) {
|
@@ -125,7 +146,7 @@ export default function NextAuthPage(props: NextAuthPageProps) {
|
|
125
146
|
);
|
126
147
|
|
127
148
|
if (!result.success) {
|
128
|
-
return
|
149
|
+
return token;
|
129
150
|
}
|
130
151
|
token.itemId = result.item.id;
|
131
152
|
}
|
package/src/schema.ts
CHANGED
@@ -1,39 +1,17 @@
|
|
1
1
|
import { ExtendGraphqlSchema } from '@keystone-6/core/types';
|
2
2
|
|
3
|
-
import { assertInputObjectType, GraphQLString, GraphQLID } from 'graphql';
|
4
3
|
import { graphql } from '@keystone-6/core';
|
5
|
-
import { AuthGqlNames } from './types';
|
6
4
|
import { getBaseAuthSchema } from './gql/getBaseAuthSchema';
|
7
5
|
|
8
6
|
export const getSchemaExtension = ({
|
9
|
-
identityField,
|
10
7
|
listKey,
|
11
|
-
gqlNames,
|
12
8
|
}: {
|
13
9
|
identityField: string;
|
14
10
|
listKey: string;
|
15
|
-
gqlNames: AuthGqlNames;
|
16
11
|
}): ExtendGraphqlSchema =>
|
17
12
|
graphql.extend((base) => {
|
18
|
-
const uniqueWhereInputType = assertInputObjectType(
|
19
|
-
base.schema.getType(`${listKey}WhereUniqueInput`)
|
20
|
-
);
|
21
|
-
const identityFieldOnUniqueWhere =
|
22
|
-
uniqueWhereInputType.getFields()[identityField];
|
23
|
-
if (
|
24
|
-
identityFieldOnUniqueWhere?.type !== GraphQLString &&
|
25
|
-
identityFieldOnUniqueWhere?.type !== GraphQLID
|
26
|
-
) {
|
27
|
-
throw new Error(
|
28
|
-
`createAuth was called with an identityField of ${identityField} on the list ${listKey} ` +
|
29
|
-
`but that field doesn't allow being searched uniquely with a String or ID. ` +
|
30
|
-
`You should likely add \`isIndexed: 'unique'\` ` +
|
31
|
-
`to the field at ${listKey}.${identityField}`
|
32
|
-
);
|
33
|
-
}
|
34
13
|
const baseSchema = getBaseAuthSchema({
|
35
14
|
listKey,
|
36
|
-
gqlNames,
|
37
15
|
base,
|
38
16
|
});
|
39
17
|
|