Last active
June 4, 2023 02:05
-
-
Save madhums/789ba349b005aa2de75d5983990fa7d8 to your computer and use it in GitHub Desktop.
An example app using keystonejs and magic-link passport auth using jwt
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
require('dotenv').config(); | |
const { Keystone } = require('@keystonejs/keystone'); | |
const { GraphQLApp } = require('@keystonejs/app-graphql'); | |
const { AdminUIApp } = require('@keystonejs/app-admin-ui'); | |
const { KnexAdapter: Adapter } = require('@keystonejs/adapter-knex'); | |
const { PasswordAuthStrategy } = require('@keystonejs/auth-password'); | |
const MagicLinkStrategy = require('passport-magic-link').Strategy; | |
const passport = require('passport'); | |
const session = require('express-session'); | |
const { signin } = require('./emails'); | |
const gql = require('graphql-tag'); | |
const { User } = require('./schema'); | |
const PROJECT_NAME = 'keystone-magic-link-example'; | |
const knexOptions = require('./knexfile'); | |
const adapterConfig = { knexOptions }; | |
const KnexSessionStore = require('connect-session-knex')(session); | |
const isProduction = process.env.NODE_ENV === 'production'; | |
const keystone = new Keystone({ | |
name: PROJECT_NAME, | |
cookieSecret: process.env.COOKIE_SECRET, | |
cookie: { | |
secure: isProduction, | |
}, | |
adapter: new Adapter(adapterConfig), | |
sessionStore: new KnexSessionStore({ | |
knex: require('knex')(knexOptions), | |
tablename: 'user_sessions', // optional. Defaults to 'sessions' | |
}), | |
}); | |
// user schema | |
keystone.createList('User', User); | |
const authStrategy = keystone.createAuthStrategy({ | |
type: PasswordAuthStrategy, | |
list: 'User', | |
}); | |
function sendToken(user, token) { | |
const url = process.env.SERVER_URL || 'http://localhost:4000'; | |
signin({ | |
to: user.email, | |
subject: 'Sign in', | |
name: user.name, | |
magicLink: `${url}/auth?token=${token}`, | |
}); | |
} | |
async function verifyUser(user) { | |
const context = keystone.createContext({ skipAccessControl: true }); | |
const { data, errors } = await keystone.executeGraphQL({ | |
context, | |
query: gql` | |
query findUser($email: String) { | |
allUsers(where: { email: $email }) { | |
id | |
name | |
} | |
} | |
`, | |
variables: { email: user.email }, | |
}); | |
const msg = 'Cannot find the user with given email'; | |
if (errors || !data) { | |
console.error(errors); | |
return Promise.reject(msg); | |
} | |
const [usr] = data.allUsers || []; | |
if (!usr) return Promise.reject(msg); | |
console.log(usr); | |
return Promise.resolve(usr); | |
} | |
passport.use( | |
new MagicLinkStrategy( | |
{ | |
secret: process.env.TOKEN_SECRET, | |
userFields: ['email'], | |
tokenField: 'token', | |
ttl: process.env.AUTH_TOKEN_EXPIRY, | |
}, | |
sendToken, | |
verifyUser | |
) | |
); | |
module.exports = { | |
keystone, | |
apps: [ | |
new GraphQLApp(), | |
new AdminUIApp({ | |
enableDefaultRoute: false, | |
authStrategy, | |
isAccessAllowed: ({ authentication: { item: user } }) => | |
!!user && !!user.isAdmin, | |
}), | |
], | |
configureExpress: (app) => { | |
app.set('trust proxy', 1); | |
app.use(passport.initialize()); | |
app.use(passport.session()); | |
passport.serializeUser((user, done) => done(null, user)); | |
passport.deserializeUser((user, done) => done(null, user)); | |
app.post( | |
'/auth/magiclink', | |
passport.authenticate('magiclink', { action: 'requestToken' }), | |
(req, res) => res.json({ ok: true }) | |
); | |
app.get( | |
'/auth/magiclink/callback', | |
passport.authenticate('magiclink', { action: 'acceptToken' }), | |
(req, res) => res.json({ ok: true }) | |
); | |
// How can this sort of authorisation be used in GraphQLApp? | |
app.get( | |
'/authorized', | |
passport.authenticate('magiclink', { | |
action: 'acceptToken', | |
allowReuse: true, | |
}), | |
(req, res) => { | |
res.json({ | |
user: req.user, | |
query: req.query, | |
}); | |
} | |
); | |
}, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment