1.0.0 • Published 4 years ago

knock-knock-knock v1.0.0

Weekly downloads
3
License
MIT
Repository
github
Last release
4 years ago

TOC

KKK abbr. knock-knock-knock

Description

An authorization framework!

Features

  • extremely lightweight
  • zero dependencies
  • compatible with express
  • RESTful design
  • easy use with openid and oauth 2.0
  • easy to customize

Install

  • yarn:
yarn add knock-knock

# install needed schemas
# yarn add knock-google-openid
# yarn add knock-jwt-schema
  • npm:
npm install knock-knock

# install needed schemas
# npm install knock-google-openid
# npm install knock-jwt-schema

Example

basic example

let express = require('express');
let app = express();

app.use(express.json());

const KKK = require('../');
const kkk = new KKK({});

const schemaForKKK=require('./test-schema');

kkk.enable('test',schemaForKKK ,true);

app.post('/login', kkk.knockLogin('test'), (req, res, next) => {
    res.send('okay');
});

module.exports = app;

a full example for google open-id login and jwt auth

let express = require('express');
let cookieParser = require('cookie-parser');
let app = express();

app.use(express.json());
app.use(cookieParser('yijiang'));
app.use(express.urlencoded({extended: false}));

const KKK = require('knock-knock-knock');
let kkk = new KKK();

let googleSchemaClass = require('knock-google-openid');
let jwtSchemaClass = require('knock-jwt-schema');

// openid discovery method
googleSchemaClass.discovery().then((googleSchema) => {
    kkk.enable('google', googleSchema);
    kkk.enable('jwt', new jwtSchemaClass({secret: 'top-secret'}));
}).catch((err) => {
    console.error(err);
});

// oauth request step
app.get('/login', kkk.oauthLogin('google', {
    authSession: true,
    authSchemaID: 'jwt'
}));

// oauth callback step
app.get('/oauthcallback', kkk.knockLogin('google'), (req, res) => {
    if (req.user) {
        res.send(req.user);
    }
});

// jwt authorization
app.get('/dashboard', kkk.knockAuth('jwt'), (req, res) => {
    if (req.user) {
        res.send(req.user);
    }
});


app.use(function (err, req, res, next) {
    //deal with KKK's error
    if (err instanceof KKK.UnauthorizedError) {
        console.error(err);
        res.status(err.status).send(err);
    } else {
        res.status(500).send('interal error');
    }
})

module.exports = app;

Custom Schemas

in KKK there is two types of schema: login and auth.

  • login schema used as login or authentication. use this to get a login method
app.post('/login', kkk.knockLogin('test'), (req, res, next) => {
    res.send('okay');
});
  • auth schema used as create/revoke session and authorization. use this to get a auth method
app.get('/dashboard', kkk.knockAuth(), (req, res, next) => {
    if (req.user) {
        res.send(req.user);
    }
});

here is an example: this example show how to implements a schema

module.exports = function () {
    //login schema must implement this
    this.knockLogin = this.login = async function (req, res) {
        //you should check the login request from req
        //and must set one of them:

        // req.user =...
        // or
        // req.unauthorizedError = new KnockKnock.unauthorizedError();
    };

    //auth schema must implement this
    this.knockAuth = this.auth = async function (req, res) {
        //you should verify a session here...
        //and must set one of them:

        // req.user =...
        // or
        // req.unauthorizedError = new KnockKnock.unauthorizedError();
    }

    //optional for auth schema
    this.createSession = async function (req, res) {
    }
    this.revoke = function (req, res) {
    }

    //optional for login schema
    this.oauthCallback = function (req, res) {
    }
    this.oauthLogin = function (req, res) {
    }

};

every function here has same signature: async func(req,res),so you can:

  • return a Promise
  • use req,res same as express
  • set req.user as user object if login/auth approved
  • set req.UnauthorizedError to a KKK.UnauthorizedError if login/auth fatal
  • get req.user to verify user info(e.g. query database) because KKK's login schema(e.g knock-password-schema) only check the request but not verify it.
  • get req.user._schemaID specified which schema created this user object

More Specific

this shows how KKK internal flow

kkk.knockLogin
    =>(internal)loginSchema.knockLogin
    =>(internal)user `verify` function
    =>(internal)authSchema.createSession
kkk.knockAuth
    =>(internal)authSchema.knockAuth
    =>(internal)user `verify` function

so you have to:

  • set verify option if you want to verify request when you call kkk.knockLogin/kkk.knockAuth
  • specify createSession option if you want to create session otherwise it going to be one time authentication/authorization

Interface

  • call kkk.knockLogin(schema) and kkk.knockAuth(schema) is the most common way.
  • if you omit the schema option, kkk will try to refer it from client request:
_getParamFromReq(req, param) {
return req.params[param] || req.query[param] || req.cookies[param] || req.body[param];
}
  • kkk has shortcuts to directly get schema's methods, so after that you are able to pass it to express: you are able to use these shortcuts to get schema's method
//for login-schemas
kkk.login('test-schema');
kkk.oauthCallback('test-schema');
kkk.oauthLogin('test-schema');

//for auth-schemas
kkk.auth('test-schema');
kkk.revoke('test-schema')

options

verify

set verify will be called after kkk.knockLogin is called

kkk.knockLogin(
    'schema',
    {
        verify: async (req, res) => {
            return await database.query(req.user);
        }
    }
)

//or set globally...
kkk.option.globalLoginVerify = async (req, res) => {
    //...
}

kkk option

  • globalLoginVerify:the global login verify function
  • globalAuthVerify:the global auth verify function
  • throwUnauthorizedError:should throw error when unauthorized-error occurs otherwise kkk just only set req.unauthorizedError

API

Classes

Functions

Interfaces

schemaInterface

Kind: global interface
Ee: ./doc/examples/all-schema.js

schemaInterface.interface

a schema must implement one of the interface's methods

Kind: static interface of schemaInterface

interface.knockLogin(req, res)

must implement for login-schema.

Kind: static method of interface
Ee: ./doc/examples/login-schema.js

ParamTypeDescription
reqObjectreq.user should be set if user authorized or req.unauthorizedError should be set if error
resObjectsame like express

interface.knockAuth(req, res)

must implement for auth schema.

Kind: static method of interface
Ee: ./doc/examples/auth-schema.js

ParamTypeDescription
reqObjectreq.user should be set if user authorized or req.unauthorizedError should be set if error
resObjectsame like express

schemaInterface.loginOptional

if the schema implemented this interface , it is able to use [schemaFunctions] to call this function in schema

Kind: static interface of schemaInterface

loginOptional.login(req, res)

Kind: static method of loginOptional

ParamTypeDescription
reqObjectreq.user should be set if user authorized or req.unauthorizedError should be set if error
resObjectsame like express

loginOptional.oauthLogin(req, res)

Kind: static method of loginOptional

ParamTypeDescription
reqObjectreq.user should be set if user authorized or req.unauthorizedError should be set if error
resObjectsame like express

loginOptional.oauthCallback(req, res)

Kind: static method of loginOptional

ParamTypeDescription
reqObjectreq.user should be set if user authorized or req.unauthorizedError should be set if error
resObjectsame like express

schemaInterface.authOptional

if the schema implemented this interface , it is able to use [schemaFunctions] to call this function in schema

Kind: static interface of schemaInterface

authOptional.createSession(req, res)

Kind: static method of authOptional

ParamTypeDescription
reqObjectreq.user should be set if user authorized or req.unauthorizedError should be set if error
resObjectsame like express

authOptional.auth(req, res)

Kind: static method of authOptional

ParamTypeDescription
reqObjectreq.user should be set if user authorized or req.unauthorizedError should be set if error
resObjectsame like express

authOptional.revoke(req, res)

Kind: static method of authOptional

ParamTypeDescription
reqObjectreq.user should be set if user authorized or req.unauthorizedError should be set if error
resObjectsame like express

UnauthorizedError ⇐ Error

A Unauthorized Error

Kind: global class
Extends: Error

unauthorizedError.schema

Kind: instance property of UnauthorizedError

unauthorizedError.rawError

Kind: instance property of UnauthorizedError

KnockKnockKnock

knock-knock-knock main class

Kind: global class
Ee: ./doc/examples/newKKK.js

new KnockKnockKnock(option)

ParamType
optionOption

knockKnockKnock.valid ⇒ boolean

check able to work available to work. it won't return true until least one login-schema are enabled

Kind: instance property of KnockKnockKnock

knockKnockKnock.enable(id, schema, setDefault)

enable a schema knock-knock-knock won't work until at least one login schema is enabled

Kind: instance method of KnockKnockKnock

ParamTypeDefaultDescription
idstringschama id
schemaschemaInterfaceschema
setDefaultbooleanfalsedefault use the schema if user won't specify a schema id

Example

kkk.enable('test',schemaForKKK ,true);

knockKnockKnock.disable(id)

disable a schema

Kind: instance method of KnockKnockKnock

ParamTypeDescription
idstringschema id

Example

kkk.disable('test');

knockKnockKnock.lazy(router)

Kind: instance method of KnockKnockKnock
Todo

  • implement this
Param
router

knockKnockKnock.knockLogin(id, option)

authenticate a request

Kind: instance method of KnockKnockKnock
Ee: ./doc/examples/knockLogin.js

ParamTypeDefaultDescription
idstringnullschema id
optionactionOptions{}

knockKnockKnock.knockAuth(id, option)

authorize a request

Kind: instance method of KnockKnockKnock
Ee: ./doc/examples/knockAuth.js

ParamTypeDefaultDescription
idstringnullschema id
optionactionOptions{}

knockKnockKnock.schemaFunctions(id, options)

return the functions from schema who implemented the interface loginOptional and authOptional

e.g if a schema which implements oauthLogin it could call knockKnockKnock.oauthLogin(id,option)

Kind: instance method of KnockKnockKnock
Ee: ./doc/examples/KKKLazy.js

ParamTypeDescription
idstringschema id enable
optionsactionOptions

KnockKnockKnock~Option

Kind: inner typedef of KnockKnockKnock
Properties

NameTypeDefaultDescription
globalLoginVerifyuserVerifyFunctionthe global login verify function
globalAuthVerifyuserVerifyFunctionthe global auth verify function
throwUnauthorizedErrorbooleantrueshould throw error when unauthorized-error occurs otherwise kkk just only set req.unauthorizedError

KnockKnockKnock~actionOptions

Kind: inner typedef of KnockKnockKnock
Properties

NameTypeDefaultDescription
verifyuserVerifyFunctionverify function for current user object in req.user
authSessionbooleantrueshould invoke authSchema to create session after login
authSchemaIDstring | undefinedauth-schema id to create session after login. undefined to use default schema

userVerifyFunction(req, res)

Kind: global function
Ee: ./doc/examples/kkkverify.js

ParamTypeDescription
reqObjectreq.user should be set if user authorized or req.unauthorizedError should be set if error
resObjectsame like express

License

MIT