-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add example for custom session strategy using JWTs (#8640)
Co-authored-by: Daniel Cousens <dcousens@users.noreply.github.com> Co-authored-by: Josh Calder <josh.calder@thinkmill.com.au>
- Loading branch information
1 parent
19bb460
commit 0dc2865
Showing
15 changed files
with
536 additions
and
20 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import jwt from 'jsonwebtoken'; | ||
import { config } from '@keystone-6/core'; | ||
import { fixPrismaPath } from '../example-utils'; | ||
import { lists, Session } from './schema'; | ||
import type { Context, TypeInfo } from '.keystone/types'; | ||
|
||
// WARNING: this example is for demonstration purposes only | ||
// as with each of our examples, it has not been vetted | ||
// or tested for any particular usage | ||
|
||
// WARNING: you need to change this | ||
const jwtSessionSecret = '-- DEV COOKIE SECRET; CHANGE ME --'; | ||
|
||
type OurJWTClaims = { | ||
id: string; | ||
}; | ||
|
||
async function jwtSign(claims: OurJWTClaims) { | ||
return new Promise((resolve, reject) => { | ||
jwt.sign( | ||
claims, | ||
jwtSessionSecret, | ||
{ | ||
algorithm: 'HS256', // HMAC-SHA256 | ||
}, | ||
(err, token) => { | ||
if (err) return reject(err); | ||
return resolve(token); | ||
} | ||
); | ||
}); | ||
} | ||
|
||
async function jwtVerify(token: string): Promise<OurJWTClaims | null> { | ||
return new Promise(resolve => { | ||
jwt.verify( | ||
token, | ||
jwtSessionSecret, | ||
{ | ||
algorithms: ['HS256'], | ||
maxAge: '1h', // we use an expiry of 1 hour for this example | ||
}, | ||
(err, result) => { | ||
if (err || typeof result !== 'object') return resolve(null); | ||
if (typeof result.id !== 'string') return resolve(null); | ||
return resolve(result as OurJWTClaims); | ||
} | ||
); | ||
}); | ||
} | ||
|
||
const jwtSessionStrategy = { | ||
async get({ context }: { context: Context }): Promise<Session | undefined> { | ||
if (!context.req) return; | ||
|
||
const { cookie = '' } = context.req.headers; | ||
const [cookieName, jwt] = cookie.split('='); | ||
if (cookieName !== 'user') return; | ||
|
||
const jwtResult = await jwtVerify(jwt); | ||
if (!jwtResult) return; | ||
|
||
const { id } = jwtResult; | ||
const who = await context.sudo().db.User.findOne({ where: { id } }); | ||
if (!who) return; | ||
return { | ||
id, | ||
admin: who.admin, | ||
}; | ||
}, | ||
|
||
// we don't need these unless we want to support the functions | ||
// context.sessionStrategy.start | ||
// context.sessionStrategy.end | ||
// | ||
async start() {}, | ||
async end() {}, | ||
}; | ||
|
||
export default config<TypeInfo>({ | ||
db: { | ||
provider: 'sqlite', | ||
url: process.env.DATABASE_URL || 'file:./keystone-example.db', | ||
|
||
// WARNING: this is only needed for our monorepo examples, dont do this | ||
...fixPrismaPath, | ||
|
||
onConnect: async () => { | ||
// WARNING: remove this | ||
console.error( | ||
'Use any of the following tokens as your `user={token}` cookie for testing this session strategy', | ||
{ | ||
Alice: await jwtSign({ id: 'clh9v6pcn0000sbhm9u0j6in0' }), // admin | ||
Bob: await jwtSign({ id: 'clh9v762w0002sbhmhhyc0340' }), | ||
Eve: await jwtSign({ id: 'clh9v7ahs0004sbhmpx30w85n' }), | ||
} | ||
); | ||
}, | ||
}, | ||
lists, | ||
session: jwtSessionStrategy, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"name": "@keystone-6/example-custom-session-jwt", | ||
"version": "0.0.1", | ||
"private": true, | ||
"license": "MIT", | ||
"scripts": { | ||
"dev": "keystone dev", | ||
"start": "keystone start", | ||
"build": "keystone build", | ||
"postinstall": "keystone postinstall" | ||
}, | ||
"dependencies": { | ||
"@keystone-6/auth": "^7.0.0", | ||
"@keystone-6/core": "^5.0.0", | ||
"@prisma/client": "^4.15.0", | ||
"jsonwebtoken": "^9.0.0" | ||
}, | ||
"devDependencies": { | ||
"@types/jsonwebtoken": "^9.0.2", | ||
"prisma": "^4.15.0", | ||
"typescript": "~5.0.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"template": "node", | ||
"container": { | ||
"startScript": "keystone dev", | ||
"node": "16" | ||
} | ||
} |
Oops, something went wrong.