0.3.2 • Published 5 years ago

fastify-koda v0.3.2

Weekly downloads
1
License
MIT
Repository
github
Last release
5 years ago

Fastify Koda

npm npm deepscan

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

NameValueDescriptionRequired
connectionStringStringConnection string to MongoDB in New URL formatYES
collectionNameStringName of collection to use for accessing and storing data.YES
schemaObjectJSON 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

KeyValueDescriptionRequired
searchByStringJSON 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 ...
0.3.2

5 years ago

0.3.1

5 years ago

0.3.0

5 years ago

0.2.12

5 years ago

0.2.11

5 years ago

0.2.10

5 years ago

0.2.9

5 years ago

0.2.8

5 years ago

0.2.7

5 years ago

0.2.6

5 years ago

0.2.3

5 years ago

0.2.5

5 years ago

0.2.4

5 years ago

0.2.1

5 years ago

0.2.0

5 years ago

0.2.2

5 years ago

0.1.64

5 years ago

0.1.66

5 years ago

0.1.67

5 years ago

0.1.63

5 years ago

0.1.62

5 years ago

0.1.61

5 years ago

0.1.60

5 years ago

0.1.59

5 years ago

0.1.58

5 years ago

0.1.57

5 years ago

0.1.55

5 years ago

0.1.56

5 years ago

0.1.54

5 years ago

0.1.52

5 years ago

0.1.53

5 years ago

0.1.51

5 years ago

0.1.50

5 years ago

0.1.49

5 years ago

0.1.48

5 years ago

0.1.45

5 years ago

0.1.46

5 years ago

0.1.43

5 years ago

0.1.44

5 years ago

0.1.42

5 years ago

0.1.41

5 years ago

0.1.40

5 years ago

0.1.39

5 years ago

0.1.38

5 years ago

0.1.37

5 years ago

0.1.36

5 years ago

0.1.35

5 years ago

0.1.31

5 years ago

0.1.32

5 years ago

0.1.33

5 years ago

0.1.34

5 years ago

0.1.30

5 years ago

0.1.27

5 years ago

0.1.28

5 years ago

0.1.29

5 years ago

0.1.26

5 years ago

0.1.13

5 years ago

0.1.14

5 years ago

0.1.15

5 years ago

0.1.20

5 years ago

0.1.21

5 years ago

0.1.22

5 years ago

0.1.23

5 years ago

0.1.24

5 years ago

0.1.25

5 years ago

0.1.16

5 years ago

0.1.17

5 years ago

0.1.18

5 years ago

0.1.19

5 years ago

0.1.12

5 years ago

0.1.11

5 years ago

0.1.10

5 years ago

0.1.9

5 years ago

0.1.8

5 years ago

0.1.7

5 years ago

0.1.4

5 years ago

0.1.3

5 years ago

0.1.6

5 years ago

0.1.5

5 years ago

0.1.0

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.0.62

5 years ago

0.0.60

5 years ago

0.0.61

5 years ago

0.0.59

5 years ago

0.0.58

5 years ago

0.0.57

5 years ago

0.0.56

5 years ago

0.0.55

5 years ago

0.0.54

5 years ago

0.0.52

5 years ago

0.0.53

5 years ago

0.0.51

5 years ago

0.0.50

5 years ago

0.0.48

5 years ago

0.0.49

5 years ago

0.0.47

5 years ago

0.0.46

5 years ago

0.0.44

5 years ago

0.0.45

5 years ago

0.0.43

5 years ago

0.0.42

5 years ago

0.0.41

5 years ago

0.0.40

5 years ago

0.0.39

5 years ago

0.0.38

5 years ago

0.0.37

5 years ago

0.0.36

5 years ago

0.0.35

5 years ago

0.0.34

5 years ago

0.0.33

5 years ago

0.0.32

5 years ago

0.0.31

5 years ago

0.0.30

5 years ago

0.0.29

5 years ago

0.0.28

5 years ago

0.0.26

5 years ago

0.0.27

5 years ago

0.0.25

5 years ago

0.0.23

5 years ago

0.0.24

5 years ago

0.0.21

5 years ago

0.0.22

5 years ago

0.0.20

5 years ago

0.0.19

5 years ago

0.0.17

5 years ago

0.0.18

5 years ago

0.0.16

5 years ago

0.0.13

5 years ago

0.0.14

5 years ago

0.0.15

5 years ago

0.0.10

5 years ago

0.0.11

5 years ago

0.0.12

5 years ago

0.0.9

5 years ago

0.0.8

5 years ago

0.0.7

5 years ago

0.0.6

5 years ago

0.0.5

5 years ago

0.0.4

5 years ago

0.0.3

5 years ago

1.0.3

5 years ago

1.0.2

5 years ago

1.0.1

5 years ago

1.0.0

5 years ago