You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
4.5 KiB
180 lines
4.5 KiB
'use strict'
|
|
/*
|
|
Register a user:
|
|
|
|
curl -i 'http://127.0.0.1:3000/register' -H 'content-type: application/json' --data '{"user": "myuser","password":"mypass"}'
|
|
Will return:
|
|
{"token":"YOUR_JWT_TOKEN"}
|
|
|
|
The application then:
|
|
1. generates a JWT token (from 'supersecret') and adds to the response headers
|
|
1. inserts user in the leveldb
|
|
|
|
Check it's all working by using one or the other auth mechanisms:
|
|
1. Auth using username and password (you can also use JWT on this endpoint)
|
|
curl 'http://127.0.0.1:3000/auth-multiple' -H 'content-type: application/json' --data '{"user": "myuser","password":"mypass"}'
|
|
{"hello":"world"}
|
|
|
|
1. Auth using JWT token
|
|
curl -i 'http://127.0.0.1:3000/auth' -H 'content-type: application/json' -H "auth: YOUR_JWT_TOKEN"
|
|
*/
|
|
|
|
const Fastify = require('fastify')
|
|
|
|
function build (opts) {
|
|
const fastify = Fastify(opts)
|
|
|
|
fastify.register(require('fastify-jwt'), { secret: 'supersecret' })
|
|
fastify.register(require('fastify-leveldb'), { name: 'authdb' })
|
|
fastify.register(require('./auth')) // just 'fastify-auth' IRL
|
|
fastify.after(routes)
|
|
|
|
fastify.decorate('verifyJWTandLevelDB', verifyJWTandLevelDB)
|
|
fastify.decorate('verifyUserAndPassword', verifyUserAndPassword)
|
|
|
|
function verifyJWTandLevelDB (request, reply, done) {
|
|
const jwt = this.jwt
|
|
const level = this.level.authdb
|
|
|
|
if (request.body && request.body.failureWithReply) {
|
|
reply.code(401).send({ error: 'Unauthorized' })
|
|
return done(new Error())
|
|
}
|
|
|
|
if (!request.raw.headers.auth) {
|
|
return done(new Error('Missing token header'))
|
|
}
|
|
|
|
jwt.verify(request.raw.headers.auth, onVerify)
|
|
|
|
function onVerify (err, decoded) {
|
|
if (err || !decoded.user || !decoded.password) {
|
|
return done(new Error('Token not valid'))
|
|
}
|
|
|
|
level.get(decoded.user, onUser)
|
|
|
|
function onUser (err, password) {
|
|
if (err) {
|
|
if (err.notFound) {
|
|
return done(new Error('Token not valid'))
|
|
}
|
|
return done(err)
|
|
}
|
|
|
|
if (!password || password !== decoded.password) {
|
|
return done(new Error('Token not valid'))
|
|
}
|
|
|
|
done()
|
|
}
|
|
}
|
|
}
|
|
|
|
function verifyUserAndPassword (request, reply, done) {
|
|
const level = this.level.authdb
|
|
|
|
if (!request.body || !request.body.user) {
|
|
return done(new Error('Missing user in request body'))
|
|
}
|
|
|
|
level.get(request.body.user, onUser)
|
|
|
|
function onUser (err, password) {
|
|
if (err) {
|
|
if (err.notFound) {
|
|
return done(new Error('Password not valid'))
|
|
}
|
|
return done(err)
|
|
}
|
|
|
|
if (!password || password !== request.body.password) {
|
|
return done(new Error('Password not valid'))
|
|
}
|
|
|
|
done()
|
|
}
|
|
}
|
|
|
|
function routes () {
|
|
fastify.route({
|
|
method: 'POST',
|
|
url: '/register',
|
|
schema: {
|
|
body: {
|
|
type: 'object',
|
|
properties: {
|
|
user: { type: 'string' },
|
|
password: { type: 'string' }
|
|
},
|
|
required: ['user', 'password']
|
|
}
|
|
},
|
|
handler: (req, reply) => {
|
|
req.log.info('Creating new user')
|
|
fastify.level.authdb.put(req.body.user, req.body.password, onPut)
|
|
|
|
function onPut (err) {
|
|
if (err) return reply.send(err)
|
|
fastify.jwt.sign(req.body, onToken)
|
|
}
|
|
|
|
function onToken (err, token) {
|
|
if (err) return reply.send(err)
|
|
req.log.info('User created')
|
|
reply.send({ token })
|
|
}
|
|
}
|
|
})
|
|
|
|
fastify.route({
|
|
method: 'GET',
|
|
url: '/no-auth',
|
|
handler: (req, reply) => {
|
|
req.log.info('Auth free route')
|
|
reply.send({ hello: 'world' })
|
|
}
|
|
})
|
|
|
|
fastify.route({
|
|
method: 'GET',
|
|
url: '/auth',
|
|
preHandler: fastify.auth([fastify.verifyJWTandLevelDB]),
|
|
handler: (req, reply) => {
|
|
req.log.info('Auth route')
|
|
reply.send({ hello: 'world' })
|
|
}
|
|
})
|
|
|
|
fastify.route({
|
|
method: 'POST',
|
|
url: '/auth-multiple',
|
|
preHandler: fastify.auth([
|
|
// Only one of these has to pass
|
|
fastify.verifyJWTandLevelDB,
|
|
fastify.verifyUserAndPassword
|
|
]),
|
|
handler: (req, reply) => {
|
|
req.log.info('Auth route')
|
|
reply.send({ hello: 'world' })
|
|
}
|
|
})
|
|
}
|
|
|
|
return fastify
|
|
}
|
|
|
|
if (require.main === module) {
|
|
const fastify = build({
|
|
logger: {
|
|
level: 'info'
|
|
}
|
|
})
|
|
fastify.listen(3000, err => {
|
|
if (err) throw err
|
|
console.log(`Server listening at http://localhost:${fastify.server.address().port}`)
|
|
})
|
|
}
|
|
|
|
module.exports = build
|