feathers-authentication-signed
v2.0.9
Published
[![Build Status](https://travis-ci.org/feathersjs/feathers-authentication-signed.png?branch=master)](https://travis-ci.org/feathersjs/feathers-authentication-signed) [![Code Climate](https://codeclimate.com/github/feathersjs/feathers-authentication-signed
Downloads
4
Readme
feathers-authentication-signed
High-security local authentication & request signing / verification for FeathersJS.
The benefits of using the package include
- More secure local (username & password) authentication. The user does not have to send his or her password - in any form - across the wire to login. It is transmitted only during signup or password changes.
- Mitigation of man-in-the-middle attacks through the use of request signing & verification. When a request arrives at the Feathers server and passes signature verification, it is guaranteed to contain the exact same payload as what was sent from the client device.
This package includes both server and client utilities that assist with
- Secure, local (username & password) authentication
- Sending and verifying signed requests to a Feathers API server.
Installation
npm install feathers-authentication-signed --save
The Client Utils
The client utils consist of
- The initial plugin setup function and utilities. (required)
- A Feathers hook for signing requests.
- An
authenticate
method for login from any client framework. - A
can-connect
Session
behavior for assisting with login/logout.
The Initial Plugin Setup Function
Because the browser does come pre-packaged with a crypto
library like Node.js does, you have to provide one. It must provide at least the createHmac
, pbkdf2
, and createHash
methods. A browser build of the [crypto-browserify
][https://www.npmjs.com/package/crypto-browserify] module will work. You can also use the @equibit/wallet-crypto
package, which includes the needed methods.
feathers-signed.js
import signed from 'feathers-authentication-signed/client';
import crypto from '@equibit/wallet-crypto/dist/wallet-crypto';
export default signed(options);
The following utils are now ready for use in other modules:
signed.generateSecret(password, salt)
password
{String} - the password used to generate the secretsalt
{String} - the salt used to generate the secret.
generateSecret
uses the pbkdf2
crypto method to create a sha512
hash of the password using the provided salt.
`signed.sign(data, secret)
data
{Object} - The data to be signed. It will receive asignature
property.secret
{String} - The secret that will be used to sign the request.
sign
adds a signature
property onto the provided data. The signature is a hex representation of a hash using crypto.createHmac
and sha512
.
signed.createHash(str)
str
{String} - the string to be hashed
Uses crypto.createHash()
to create a hex hash representation of the provided str
.
A Feathers Hook for Signing Requests
A single hook is included on the client for signing requests. It comes in the same object as the rest of the utilities. See setup instructions in the previous section.
signed.hooks.sign(options)
options
{Object} - an object with astrict
property. optionalstrict
{Boolean} - If set to true, the hook will throw an error if there's no secret present on the FeathersClient instance. (using feathersClient.get('secret')) default: false
The signing hook to be used as a before hook on any Feathers services requiring signature validation.
import signed from './feathers-signed';
// Use the signHook in your service
feathersClient.service('some-service').hooks({
before: {
all: [
signed.hooks.sign({ strict: true })
]
}
})
Authenticating with any Client-side Framework
The signed.authenticate
method simplifies the multi-step login process. You'll first need a working Feathers client. See the Feathers client docs.
signed.authenticate(feathersClient, data)
#### signed.authenticate(feathersClient, data)
feathersClient
{FeathersClient} - the Feathers client object. It must already have thefeathers-authentication-client
plugin configured.data
{Object} - Request data containing theemail
andpassword
. These field names are currently hard coded.
Example usage:
import feathersClient from './feathers-client';
import signed from './feathers-signed';
signed.authenticate(feathersClient, {
email: '[email protected]',
password: 'my-password'
})
The can-connect
Behavior
A behavior for can-connect
is included to assist with data modeling. It must be imported separately. Here's an example of how to use it in a Session
model:
import connect from 'can-connect';
import dataParse from 'can-connect/data/parse/';
import construct from 'can-connect/constructor/';
import constructStore from 'can-connect/constructor/store/';
import constructOnce from 'can-connect/constructor/callbacks-once/';
import canMap from 'can-connect/can/map/';
import canRef from 'can-connect/can/ref/';
import dataCallbacks from 'can-connect/data/callbacks/';
// Bring in the behavior
import feathersAuthenticationSignedSession from 'feathers-authentication-signed/behavior';
// Bring in the feathersClient that we configured separately.
import feathersClient from '../feathers-client';
// Bring in the signed utils that we configured separately.
import signed from '~/models/feathers-signed';
import DefineMap from 'can-define/map/';
import User from '~/models/user/user';
const behaviors = [
feathersAuthenticationSignedSession,
dataParse,
construct,
constructStore,
constructOnce,
canMap,
canRef,
dataCallbacks
];
const Session = DefineMap.extend('Session', {
user: {
Type: User
},
usingTempPassword: 'boolean',
secret: 'string',
get email () {
return this.user && this.user.email;
},
get isNewAccount () {
return this.user && this.user.isNewUser;
}
});
Session.connection = connect(behaviors, {
// These options are required
feathersClient,
Map: Session,
utils: signed
});
export default Session;
The Server Plugin
On the Feathers server, this package consists of
- Two custom, local (username & password) authentication strategies.
- Hooks for verifying request signatures.
- General utilities needed for auth & signature verification
Secure Local Authentication Strategies
There are two strategies in this package that assist with authentication: the challenge-request
strategy and the challenge
strategy. These strategy plugins build on top of the functionality provided by feathers-authentication
and feathers-authentication-local
. There is a wrapper plugin that combines both plugins into a single plugin. The example below shows how to setup the server.
Basic Example
Here's an example of a Feathers server that uses feathers-authentication-signed
.
const feathers = require('feathers');
const rest = require('feathers-rest');
const socketio = require('feathers-socketio');
const hooks = require('feathers-hooks');
const bodyParser = require('body-parser');
const errorHandler = require('feathers-errors/handler');
const authentication = require('feathers-authentication')
const jwt = require('feathers-authentication-jwt')
// Import the plugin
const signed = require('feathers-authentication-signed')
// Initialize the application
const app = feathers()
.configure(rest())
.configure(socketio())
.configure(hooks())
// Needed for parsing bodies (login)
.use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: true }))
// Configure auth
.configure(authentication(config))
.configure(jwt())
.configure(signed({
idField: '_id'
}))
.use(errorHandler());
app.service('authentication').hooks({
before: {
create: [
// Register the required authentication strategies
authentication.hooks.authenticate([
'jwt',
'challenge-request',
'challenge'
])
],
remove: [
authentication.hooks.authenticate('jwt')
]
}
});
app.listen(3030);
console.log('Feathers app started on 127.0.0.1:3030');
License
Copyright (c) 2017
Licensed under the MIT license.