Skip to content

Commit a403cfe

Browse files
author
Josh Calder
committed
change core from sessionStrategy to getSession
1 parent 51ae55c commit a403cfe

File tree

32 files changed

+275
-253
lines changed

32 files changed

+275
-253
lines changed

examples/auth/keystone.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,16 @@ const { withAuth } = createAuth({
4040
// isEnabled: true,
4141
},
4242
},
43+
sessionStrategy:
44+
// Stateless sessions will store the listKey and itemId of the signed-in user in a cookie
45+
statelessSessions({
46+
data: 'name isAdmin',
47+
// The maxAge option controls how long session cookies are valid for before they expire
48+
maxAge: sessionMaxAge,
49+
// The session secret is used to encrypt cookie data (should be an environment variable)
50+
secret: sessionSecret,
51+
}),
4352
// Populate session.data based on the authed user
44-
sessionData: 'name isAdmin',
4553
/* TODO -- complete the UI for these features and enable them
4654
passwordResetLink: {
4755
sendToken(args) {
@@ -65,13 +73,5 @@ export default withAuth(
6573
},
6674
lists,
6775
ui: {},
68-
session:
69-
// Stateless sessions will store the listKey and itemId of the signed-in user in a cookie
70-
statelessSessions({
71-
// The maxAge option controls how long session cookies are valid for before they expire
72-
maxAge: sessionMaxAge,
73-
// The session secret is used to encrypt cookie data (should be an environment variable)
74-
secret: sessionSecret,
75-
}),
7676
})
7777
);

examples/basic/keystone.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ const auth = createAuth({
1717
isAdmin: true,
1818
},
1919
},
20-
sessionData: 'name isAdmin',
20+
sessionStrategy: statelessSessions({
21+
data: 'name isAdmin',
22+
// The session secret is used to encrypt cookie data (should be an environment variable)
23+
maxAge: sessionMaxAge,
24+
secret: sessionSecret,
25+
}),
2126
});
2227

2328
// TODO -- Create a separate example for access control in the Admin UI
@@ -56,12 +61,5 @@ export default auth.withAuth(
5661
},
5762
lists,
5863
extendGraphqlSchema,
59-
session: statelessSessions({ maxAge: sessionMaxAge, secret: sessionSecret }),
60-
// TODO -- Create a separate example for stored/redis sessions
61-
// session: storedSessions({
62-
// store: new Map(),
63-
// // store: redisSessionStore({ client: redis.createClient() }),
64-
// secret: sessionSecret,
65-
// }),
6664
})
6765
);
Lines changed: 61 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,32 @@
1-
import { KeystoneConfig, SessionStrategy } from '@keystone-6/core/types';
21
import { config } from '@keystone-6/core';
32
import { statelessSessions } from '@keystone-6/auth/session';
3+
import { SessionStrategy } from '@keystone-6/auth/types';
44
import { createAuth } from '@keystone-6/auth';
55
import { lists } from './schema';
6+
import { Context, TypeInfo } from '.keystone/types';
7+
8+
const withTimeData = (
9+
_sessionStrategy: SessionStrategy<Record<string, any>>
10+
): SessionStrategy<Record<string, any>> => {
11+
const { start, ...sessionStrategy } = _sessionStrategy;
12+
return {
13+
...sessionStrategy,
14+
start: async ({ data, context }) => {
15+
// Add the current time to the session data
16+
const withTimeData = {
17+
...data,
18+
startTime: new Date(),
19+
};
20+
// Start the keystone session and include the startTime
21+
return await start({ data: withTimeData, context });
22+
},
23+
};
24+
};
25+
26+
const maxSessionAge = 60 * 60 * 8; // 8 hours, in seconds
27+
// Stateless sessions will store the listKey and itemId of the signed-in user in a cookie.
28+
// This session object will be made available on the context object used in hooks, access-control,
29+
// resolvers, etc.
630

731
// createAuth configures signin functionality based on the config below. Note this only implements
832
// authentication, i.e signing in as an item using identity and secret fields in a list. Session
@@ -22,79 +46,46 @@ const { withAuth } = createAuth({
2246
fields: ['name', 'email', 'password'],
2347
},
2448
// Make passwordChangedAt available on the sesssion data
25-
sessionData: 'id passwordChangedAt',
49+
sessionStrategy: withTimeData(
50+
statelessSessions({
51+
data: 'id passwordChangedAt',
52+
// The session secret is used to encrypt cookie data (should be an environment variable)
53+
maxAge: maxSessionAge,
54+
secret: '-- EXAMPLE COOKIE SECRET; CHANGE ME --',
55+
})
56+
),
2657
});
2758

28-
const maxSessionAge = 60 * 60 * 8; // 8 hours, in seconds
29-
// Stateless sessions will store the listKey and itemId of the signed-in user in a cookie.
30-
// This session object will be made available on the context object used in hooks, access-control,
31-
// resolvers, etc.
59+
async function getSession({ context }: { context: Context }): Promise<unknown> {
60+
// Get the session from the cookie stored by keystone
61+
const { session } = context;
62+
// If there is no session returned from keystone or there is no startTime on the session return an invalid session
63+
// If session.startTime is null session.data.passwordChangedAt > session.startTime will always be true and therefore
64+
// the session will never be invalid until the maxSessionAge is reached.
65+
if (!session || !session.startTime) return;
66+
//if the password hasn't changed (and isn't missing), then the session is OK
67+
if (session.data.passwordChangedAt === null) return session;
68+
// If passwordChangeAt is undefined, then sessionData is missing the passwordChangedAt field
69+
// Or something is wrong with the session configuration so throw and error
70+
if (session.data.passwordChangedAt === undefined) {
71+
throw new TypeError('passwordChangedAt is not listed in sessionData');
72+
}
73+
if (session.data.passwordChangedAt > session.startTime) {
74+
return;
75+
}
3276

33-
const withTimeData = (
34-
_sessionStrategy: SessionStrategy<Record<string, any>>
35-
): SessionStrategy<Record<string, any>> => {
36-
const { get, start, ...sessionStrategy } = _sessionStrategy;
37-
return {
38-
...sessionStrategy,
39-
get: async ({ context }) => {
40-
// Get the session from the cookie stored by keystone
41-
const session = await get({ context });
42-
// If there is no session returned from keystone or there is no startTime on the session return an invalid session
43-
// If session.startTime is null session.data.passwordChangedAt > session.startTime will always be true and therefore
44-
// the session will never be invalid until the maxSessionAge is reached.
45-
if (!session || !session.startTime) return;
46-
//if the password hasn't changed (and isn't missing), then the session is OK
47-
if (session.data.passwordChangedAt === null) return session;
48-
// If passwordChangeAt is undefined, then sessionData is missing the passwordChangedAt field
49-
// Or something is wrong with the session configuration so throw and error
50-
if (session.data.passwordChangedAt === undefined) {
51-
throw new TypeError('passwordChangedAt is not listed in sessionData');
52-
}
53-
if (session.data.passwordChangedAt > session.startTime) {
54-
return;
55-
}
56-
57-
return session;
58-
},
59-
start: async ({ data, context }) => {
60-
// Add the current time to the session data
61-
const withTimeData = {
62-
...data,
63-
startTime: new Date(),
64-
};
65-
// Start the keystone session and include the startTime
66-
return await start({ data: withTimeData, context });
67-
},
68-
};
69-
};
70-
71-
const myAuth = (keystoneConfig: KeystoneConfig): KeystoneConfig => {
72-
// Add the session strategy to the config
73-
if (!keystoneConfig.session) throw new TypeError('Missing .session configuration');
74-
return {
75-
...keystoneConfig,
76-
session: withTimeData(keystoneConfig.session),
77-
};
78-
};
79-
80-
const session = statelessSessions({
81-
// The session secret is used to encrypt cookie data (should be an environment variable)
82-
maxAge: maxSessionAge,
83-
secret: '-- EXAMPLE COOKIE SECRET; CHANGE ME --',
84-
});
77+
return session;
78+
}
8579

8680
// We wrap our config using the withAuth function. This will inject all
8781
// the extra config required to add support for authentication in our system.
88-
export default myAuth(
89-
withAuth(
90-
config({
91-
db: {
92-
provider: 'sqlite',
93-
url: process.env.DATABASE_URL || 'file:./keystone-example.db',
94-
},
95-
lists,
96-
// We add our session configuration to the system here.
97-
session,
98-
})
99-
)
82+
export default withAuth<TypeInfo>(
83+
config({
84+
db: {
85+
provider: 'sqlite',
86+
url: process.env.DATABASE_URL || 'file:./keystone-example.db',
87+
},
88+
lists,
89+
getSession,
90+
})
10091
);

examples/ecommerce/keystone.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const databaseURL = process.env.DATABASE_URL || 'file:./keystone.db';
2020
const sessionConfig = {
2121
maxAge: 60 * 60 * 24 * 360, // How long they stay signed in?
2222
secret: process.env.COOKIE_SECRET || 'this secret should only be used in testing',
23+
data: `id name email role { ${permissionsList.join(' ')} }`,
2324
};
2425

2526
const { withAuth } = createAuth({
@@ -36,7 +37,7 @@ const { withAuth } = createAuth({
3637
await sendPasswordResetEmail(args.token, args.identity);
3738
},
3839
},
39-
sessionData: `id name email role { ${permissionsList.join(' ')} }`,
40+
sessionStrategy: statelessSessions(sessionConfig),
4041
});
4142

4243
export default withAuth(
@@ -71,6 +72,5 @@ export default withAuth(
7172
// Show the UI only for poeple who pass this test
7273
isAccessAllowed: ({ session }) => !!session,
7374
},
74-
session: statelessSessions(sessionConfig),
7575
})
7676
);

examples/redis-session-store/keystone.ts

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,8 @@ import { createAuth } from '@keystone-6/auth';
44
import { createClient } from '@redis/client';
55
import { lists } from './schema';
66

7-
// createAuth configures signin functionality based on the config below. Note this only implements
8-
// authentication, i.e signing in as an item using identity and secret fields in a list. Session
9-
// management and access control are controlled independently in the main keystone config.
10-
const { withAuth } = createAuth({
11-
// This is the list that contains items people can sign in as
12-
listKey: 'Person',
13-
// The identity field is typically a username or email address
14-
identityField: 'email',
15-
// The secret field must be a password type field
16-
secretField: 'password',
17-
18-
// initFirstItem turns on the "First User" experience, which prompts you to create a new user
19-
// when there are no items in the list yet
20-
initFirstItem: {
21-
// These fields are collected in the "Create First User" form
22-
fields: ['name', 'email', 'password'],
23-
},
24-
});
25-
267
const redis = createClient();
27-
28-
const session = storedSessions({
8+
const sessionStrategy = storedSessions({
299
store: ({ maxAge }) => ({
3010
async get(key) {
3111
let result = await redis.get(key);
@@ -44,6 +24,26 @@ const session = storedSessions({
4424
secret: '-- EXAMPLE COOKIE SECRET; CHANGE ME --',
4525
});
4626

27+
// createAuth configures signin functionality based on the config below. Note this only implements
28+
// authentication, i.e signing in as an item using identity and secret fields in a list. Session
29+
// management and access control are controlled independently in the main keystone config.
30+
const { withAuth } = createAuth({
31+
// This is the list that contains items people can sign in as
32+
listKey: 'Person',
33+
// The identity field is typically a username or email address
34+
identityField: 'email',
35+
// The secret field must be a password type field
36+
secretField: 'password',
37+
38+
// initFirstItem turns on the "First User" experience, which prompts you to create a new user
39+
// when there are no items in the list yet
40+
initFirstItem: {
41+
// These fields are collected in the "Create First User" form
42+
fields: ['name', 'email', 'password'],
43+
},
44+
sessionStrategy,
45+
});
46+
4747
// We wrap our config using the withAuth function. This will inject all
4848
// the extra config required to add support for authentication in our system.
4949
export default withAuth(
@@ -56,7 +56,5 @@ export default withAuth(
5656
},
5757
},
5858
lists,
59-
// We add our session configuration to the system here.
60-
session,
6159
})
6260
);

examples/roles/keystone.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ const sessionMaxAge = 60 * 60 * 24 * 30; // 30 days
1010
const sessionConfig = {
1111
maxAge: sessionMaxAge,
1212
secret: sessionSecret,
13+
/* This loads the related role for the current user, including all permissions */
14+
data: `
15+
name role {
16+
id
17+
name
18+
canCreateTodos
19+
canManageAllTodos
20+
canSeeOtherPeople
21+
canEditOtherPeople
22+
canManagePeople
23+
canManageRoles
24+
}`,
1325
};
1426

1527
const { withAuth } = createAuth({
@@ -36,18 +48,7 @@ const { withAuth } = createAuth({
3648
},
3749
},
3850
},
39-
/* This loads the related role for the current user, including all permissions */
40-
sessionData: `
41-
name role {
42-
id
43-
name
44-
canCreateTodos
45-
canManageAllTodos
46-
canSeeOtherPeople
47-
canEditOtherPeople
48-
canManagePeople
49-
canManageRoles
50-
}`,
51+
sessionStrategy: statelessSessions(sessionConfig),
5152
});
5253

5354
export default withAuth(
@@ -61,6 +62,5 @@ export default withAuth(
6162
/* Everyone who is signed in can access the Admin UI */
6263
isAccessAllowed: isSignedIn,
6364
},
64-
session: statelessSessions(sessionConfig),
6565
})
6666
);

examples/testing/keystone.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ import { createAuth } from '@keystone-6/auth';
44
import { lists } from './schema';
55
import { TypeInfo } from '.keystone/types';
66

7+
// Stateless sessions will store the listKey and itemId of the signed-in user in a cookie.
8+
// This session object will be made available on the context object used in hooks, access-control,
9+
// resolvers, etc.
10+
const sessionStrategy = statelessSessions({
11+
// The session secret is used to encrypt cookie data (should be an environment variable)
12+
secret: '-- EXAMPLE COOKIE SECRET; CHANGE ME --',
13+
});
14+
715
// createAuth configures signin functionality based on the config below. Note this only implements
816
// authentication, i.e signing in as an item using identity and secret fields in a list. Session
917
// management and access control are controlled independently in the main keystone config.
@@ -21,14 +29,8 @@ const { withAuth } = createAuth({
2129
// These fields are collected in the "Create First User" form
2230
fields: ['name', 'email', 'password'],
2331
},
24-
});
25-
26-
// Stateless sessions will store the listKey and itemId of the signed-in user in a cookie.
27-
// This session object will be made available on the context object used in hooks, access-control,
28-
// resolvers, etc.
29-
const session = statelessSessions({
30-
// The session secret is used to encrypt cookie data (should be an environment variable)
31-
secret: '-- EXAMPLE COOKIE SECRET; CHANGE ME --',
32+
// We add our session configuration to the system here.
33+
sessionStrategy,
3234
});
3335

3436
// We wrap our config using the withAuth function. This will inject all
@@ -40,7 +42,5 @@ export default withAuth(
4042
url: process.env.DATABASE_URL || 'file:./keystone-example.db',
4143
},
4244
lists,
43-
// We add our session configuration to the system here.
44-
session,
4545
})
4646
);

0 commit comments

Comments
 (0)