fastify-koda v0.3.2
Fastify Koda
Making authentication super easy. Focuses on Fastify, MongoDB, and using promises.then(k => making your life easier.)
Fastify-Koda is wrapper for MongoDB that provides pre-built and clean user management functions.
While this will work for other platforms, this package takes use of fastify to reduce code needed for writing. You can with small effort write code to make it compatible.
Features
- Built with Promises / ES6 Classes & Syntax.
- Simple User Authentication modules returning one promise on result.
- Built for MongoDB using Mongoose.
- Create users easily by passing a JSON Schema. Bcrypt passwords automatically.
- Simplified JSON response objects.
- Modify user data safely.
Contents
Install
npm i fastify-koda@latest
Usage
Koda can be run in one of two ways: Local / Remote.
Local Ready to use
You can directly use the library locally to connect to your database and perform the authentication within the process. This is ideal for small setups that are running on one server.
Remote Ready to use
You want to use an endpoint to receive authentication requests from servers running the Koda Libary. You can use any way of sending requests to this endpoint using predefined request constructors, or use the included Axios wrapper to do this for you. The remote server will then process the authentication and send back replies with predictable responses in JSON.
A Local
Require the fastify-koda package:
const prototype = require('fastify-koda')
Define options for the MongoDB Connection:
//Example
let host = "mongodb://localhost/koda"
let collection = "newusers"
let options = {useNewUrlParser: true,useUnifiedTopology: true}
let myschema = premadeSchema // An object defining your JSON schema, required for creating new users.
let kodaOptions = {searchBy: "email"} // default is already email.
Create a new instance of Koda:
const koda = new prototype.KODA({
connectionString:host,
connectionCollection:collection,
schema:myschema
},options,kodaOptions)
Create a POST route:
fastify.post('/auth', async(request, response) => {
})
Setup the route behavior:
fastify.post('/auth', async(request, response) => {
const userData = request.body
koda.find(userData.email)
.then(k => koda.auth(userData.password,k.userInfo.password,k))
.then(k => k.state ? response.send({"state":true,"data":k) : response.send({"state":false,"data":k}))
.catch(k => {console.log(k);response.send({"state":false,"data":k})})
})
Variables contexts and explaination.
koda.find
k - Response document from find(). Null if not existing.
k.userInfo.password - Example location of hashed password in document.
koda.auth
k - Response object from Koda.
k.state - Boolean success state.
k.data - If k.state is true, the response object will return a data key
with document data. It will also be sent during an error.
The request body in this example was:
{
email: "test@mail.com",
password: "password"
}
B Remote
On the server you will receive the client request from, create a POST route:
// This is an example, and not a required layout.
const prototype = require('fastify-koda')
const koda = new prototype.KODA({
connectionString:host,
connectionCollection:collection,
schema:myschema
},options,kodaOptions)
...
fastify.post('/auth', async(request, response) => {
const kx = request.body
console.log(kx)
const kr = [null,null] // Success States, null is used in this example to provide a "third" state. Null is falsey, but while unchanged means the task was not actually attempted.
var kro; // Response obj
//Optional Recaptcha
await koda.recaptcha(kx.verifyChallenge,kx.siteKey)
.then(k => k.data.success ? kr[0] = true : kr[0] = false)
.catch(k => console.log(k))
await koda.find(kx.username)
.then(k => koda.auth(kx.password,k.auth.password,k.expose))
.then(k => {
if(k.state){
kro = k.data
kr[1] = true
}else{
kr[1] = false
}
})
.catch(k => console.log(k))
if(kr.every(Boolean)){
response.send({"state":true,"data":kro})
}else{
response.send({"state":false,"data":JSON.stringify(kr)})
}
})
For the client, here's how you can request the remote KODA server to validate a request.
const prototype = require('fastify-koda')
const koda = new prototype.KODAREMOTE('https://myauthsever')
...
fastify.post('/api/auth', async(request, response) => {
const kx = request.body
const session = request.session
const formatRequest = {
username: kx.email,
password: kx.password,
path: '/auth',
bearerToken: "TOKEN", // Optional, use upstream instead of upstreamBearer for no token.
siteKey: 'KEY' // Optional
verifyChallenge: kx.recapv // Optional
}
koda.upstreamBearer(formatRequest)
.then(k => {
if(k.state){
session.loggedin = true;
session.username = kx.email;
response.send(k)
}else{
response.send(k)
}
})
.catch(err => {console.log(err);response.send(err)})
})
Wrapping this up:
const formatRequest = {
username: kx.email,
password: kx.password,
path: '/auth',
bearerToken: "TOKEN", // Optional, use upstream instead of upstreamBearer for no token.
siteKey: 'KEY' // Optional
verifyChallenge: kx.recapv // Optional
}
Is your request obj, which contains all the necessary details for a remote KODA library to act upon.
KODA will return an object like this:
{state: BOOLEAN, data: STRING}
API reference
new Koda(connectionObj,options,kodaOptions)
Overview
Name | Value | Description | Required
------ | ----- | ----------- | --------
connectionObj | Object | Connection Details | YES
options | Object | Connection Options | NO
kodaOptions | Object | Koda Options | NO
Object - connectionObj
Name | Value | Description | Required |
---|---|---|---|
connectionString | String | Connection string to MongoDB in New URL format | YES |
collectionName | String | Name of collection to use for accessing and storing data. | YES |
schema | Object | JSON Schema defining document structure. | YES |
Example:
{connectionString:'mongodb://localhost/koda',collectionName:'newusers',schema:myschema}
Object - options
Mongoose connection parameters, refer to their wiki here.
Object - kodaOptions
Key | Value | Description | Required |
---|---|---|---|
searchBy | String | JSON Key to search for users with. | NO, Default: "email" |
koda.find(username)
Overview Name | Value | Description | Required ------ | ----- | ----------- | -------- username | String | String to search for users by. | YES
Example:
koda.find("john@doe.com")
Returns - Object Returns an object representing the User Data from MongoDB if successful.
{"state": BOOLEAN, "data": STRING}
//If Successful
{"state": true, "data": { ... some JSON document ... }}
//If Unsuccessful
{"state": false}
//If Unsuccessful by virtue of an error
{"state":false, "data": ... some Error ... }
koda.auth(password,hash,passthrough)
Overview Name | Value | Description | Required ------ | ----- | ----------- | -------- password | String | Password sent by the user, to be challenged. | YES hash | String | Hash of user account. Pass from result of koda.find(). | YES passthrough | Object | Passthrough of user document from Promise Chaining. | YES
Returns - Object
Returns an object representing the success of bcrypt.compare, and the passthrough paramater.
{"state":BOOLEAN, "data":STRING}
//If Successful
{"state":true, "data": ... passthrough objected passed from koda.find ... }
//If Unsuccessful (Password mismatch)
{"state":false, "data":"We didn't find an account matching that email and password combination!"}
//If Unsuccessful by virtue of an error
{"state":false, "data": ... some Error ... }
koda.createUser(kx)
Overview Name | Value | Description | Required ------ | ----- | ----------- | -------- kx | Object | Object containing new document details in line with your defined Schema for creating a new document. | YES
Object - kx
Required Layout:
const formatRequest = {
config: {
passPath: ... Nested or otherwise, location of your password key in the scheme. E.G. "secret.details.password"
}
createUser: {
... Schema specific layout can go here ...
}
}
Required Layout when using KODAREMOTE:
const formatRequest = {
path: ... URL path to your auth endpoint
bearerToken: ... BearerToken if using fastiy-bearer-auth
config: {
passPath: ... Nested or otherwise, location of your password key in the scheme. E.G. "secret.details.password"
}
createUser: {
... Schema specific layout can go here ...
}
}
Returns - Object
{"state":BOOLEAN, "data":STRING}
//If Successful
{"state":true, "data": ... The new Document ... }
//If Unsuccessful (Duplicate keys)
{"state":false, "data":"We already have a user registered with that information!"}
//If Unsuccessful by virtue of an error
{"state":false, "data": ... some Error ... }
Hooking
You can attach any new feature you need at any time by using the Hook method to attach to mongoose.
var polyfill = koda.hook()
// Destroy the connection manually
polyfill.connection.close()
// Creating a new method with the collection 'users'.
polyfill.connection.collections.users ...
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago