1- import { KeystoneConfig , SessionStrategy } from '@keystone-6/core/types' ;
21import { config } from '@keystone-6/core' ;
32import { statelessSessions } from '@keystone-6/auth/session' ;
3+ import { SessionStrategy } from '@keystone-6/auth/types' ;
44import { createAuth } from '@keystone-6/auth' ;
55import { 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) ;
0 commit comments