
Security News
Package Maintainers Call for Improvements to GitHub’s New npm Security Plan
Maintainers back GitHub’s npm security overhaul but raise concerns about CI/CD workflows, enterprise support, and token management.
Implement OAuth2.0 and basic authentication cleanly into your NodeJS server application using Bookshelf
and knex
as ORM and queries builder.
This module requires a database infrastructure. To automate the creation of schemas and others boring jobs, ideman
provides a node command line interface tool called ideman-cli
.
So, before continue with the installation of this module, go to ideman-cli
project and then install ideman
. Otherwise you can create manually the database schema following the documentation below.
WARNING:
Remember that before installing ideman
you MUST create the database schemas, otherwise this module will not work (ideman-cli
).
In your project root run from command line:
$ npm install -save ideman
Let's start! Install in your application Bookshelf
and its dependency knex
.
Create a new file in your project root like:
//file: ./ideman.js
var knex = require('knex')({
client: 'pg',
connection: 'postgres://postgres:postgres@localhost:5432/ideman?charset=utf-8&ssl=true',
});
var Bookshelf = require('bookshelf')(knex);
var ideman = require('ideman')(Bookshelf);
ideman.init({
token: {
life: 3600 //token expiration in seconds
},
oauth: {
authentications: ['bearer' /*, 'basic'*/], //enable bearer token
grants: ['password', 'refresh_token' /*, 'client_credentials' */] //enable user credentials and refresh token grants
}
});
module.exports = ideman;
Then include this file everywhere you need ideman
methods, for example in your Express
application you could have:
//file: ./routes/index.js
var express = require('express');
var router = express.Router();
var ideman = require('../ideman');
router.route('/oauth2/token').post(ideman.isClientAuthenticated, ideman.token);
router.route('/protected/resource').post(ideman.isAuthenticated, function() {
res.json({
data: 'The protected resource'
});
});
Call the endpoint /oauth2/token
to retrieve an access token:
$ curl -H 'Accept: application/x-www-form-urlencoded' -X POST -d 'grant_type=password&client_id=clientId&client_secret=clientSecret&username=userId&password=userPassword' http://localhost:3000/oauth2/token
It will return a JSON response:
{
"access_token":"NgvhmoKm9ASMCa3KGLh2yjNPqhIhFLEgPacesMFiIOQPuZ1Mq19Xg"
/* ... */
}
With the new access_token
you can call the protected resource /protected/resource
$ curl -H 'Authorization: Bearer NgvhmoKm9ASMCa3KGLh2yjNPqhIhFLEgPacesMFiIOQPuZ1Mq19Xg' -X POST http://localhost:3000/protected/resource
The ideman
module is initialized by injecting an initialized Bookshelf
instance. It can also accepts a configuration object for database customizations.
Arguments
bookshelf {Object} Bookshelf instance
[config] {Object} Optional models and tables configuration
Returns
{Object} Singleton instance
The configuration object allows you to redefine tables and models names. If you don't specify any configuration, it uses a default object:
{
prefix: '',
entities: {
user: {
table: 'users',
model: 'User'
},
client: {
table: 'clients',
model: 'Client'
},
token: {
table: 'tokens',
model: 'Token'
},
code: {
table: 'codes',
model: 'Code'
}
}
}
Initialization of singleton instance.
Arguments
options {Object} Ideman parameters
If you don't specify any paramaters, it uses a default object:
{
oauth2: {
//Use mandatory client secret in the auth request
useClientSecret: false,
//Enables authentications strategies
authentications: ['basic', 'bearer'],
//Enables authorizations grants
grants: ['client_credentials', 'password', 'refresh_token', 'authorization_code']
},
validation: {
//Enables input validation
enabled: false,
//Regexp for username
username: /^[\w\.]{2,100}$/g,
//Regexp for password
password: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[.)(=,|$@$!%*#?&])[A-Za-z\d.)(=, | $@ $!%*#?&]{8,255}$/g,
//Regexp for client name
clientId: /^[\w\.]{2,100}$/g,
//Regexp for client secret
clientSecret: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[.)(=,|$@$!%*#?&])[A-Za-z\d.)(=, | $@ $!%*#?&]{8,255}$/g,
},
user: {
//Users' password are crypted and compared by the specified mode below
passwordEnc: 'bcrypt' //bcrypt|crypto|none
},
ldap: {
//Enable LDAP user binding
enabled: false,
//Search filters, ex. (|(cn=<username>)(mail=<username>))
authAttributes: ['cn', 'mail'],
//Returned attribute after search (returned value must match with username column for a successful login)
returnAttribute: 'dn',
//Ldapper module configuration
ldapper: null
},
//Crypton module configuration
crypton: null,
token: {
//Token life in seconds
life: 3600,
//Token length in bytes
length: 32, //bytes
//Delete active tokens on login
autoRemove: true,
jwt: {
//Enables jwt token instead the standard token
enabled: false,
//Check if IP caller are the same of jwt IP when it was created
ipcheck: false,
//Check if user-agent caller are the same of jwt user-agent when it was created
uacheck: false,
//Secret key for signing jwt token
secretKey: 'K7pHX4OASe?c&lm'
}
}
}
Gets the ideman
initialization object.
Returns
{Object} Ideman parameters
Gets the ideman
database configuration object.
Returns
{Object} Ideman db config
Gets the Bookshelf
instance.
Returns
{Object} Bookshelf instance
Gets the passport
instance.
Returns
{Object} Passport instance
It is useful when you need to initialize passport
for Express
without installing it in your application.
For example when you use the middlewares methods of ideman
module, your Express
application needs to be configured with:
var app = express();
app.use(passport.initialize());
Gets a Bookshelf
model. Available default models are: User
, Client
, Token
, Code
.
Arguments
name {string} Model name
Returns
{Object} Bookshelf model
Now you can extend a Bookshelf
model in your application:
var bookshelf = ideman.getBookshelf();
var User = ideman.getModel('User');
var UserExt = bookshelf.model('UserExt', User.extend({
test: function() {
console.log('hello world');
return;
}
}));
console.log(UserExt.forge().tableName);
Gets all Bookshelf
models.
Returns
{Array} All bookshelf models
Checks if user credentials are valid.
Arguments
username {string} Username
password {string} Clear password
Returns
{Object} Returns a promise with bookshelf `User` model
Checks if client credentials are valid.
Arguments
name {string} Client name
secret {string} Clear client secret
Returns
{Object} Returns a promise with bookshelf `Client` model
Checks if token is valid.
Arguments
token {string} Bearer token
[ip] {string} Optional IP address to check
[userAgent] {string} Optional user agent to check
Returns
{Object} Returns a promise with referred bookshelf `User` or `Client` model
Exchanges user's credentials for an access token. The client input object must be an existing entity into database.
Arguments
client {Object} Bookshelf `Client` model
username {string} Username
password {string} Clear password
[ip] {string} Optional IP address to save with token
[userAgent] {string} Optional user agent to save with token
Returns
{Object} Returns a promise with tokens
Example of a common scenario:
var promise = ideman.validateClientCredentials('name', 'secret')
.then(function(client) {
return ideman.exchangePassword(client, 'username', 'password');
});
The returned JSON object is like:
{
"access_token":"<token>",
"refresh_token":"<refreshtoken>",
"expires_in":3600,
"token_type":"Bearer"
}
Exchanges client's credentials for an access token. The client input object must be an existing entity into database.
Arguments
client {Object} Bookshelf `Client` model
[ip] {string} Optional IP address to save with token
[userAgent] {string} Optional user agent to save with token
Returns
{Object} Returns a promise with tokens
The returned JSON object is like:
{
"access_token":"<token>",
"refresh_token":"<refreshtoken>",
"expires_in":3600,
"token_type":"Bearer"
}
Exchanges a refesh token for a new access token. The client input object must be an existing entity into database.
Arguments
client {Object} Bookshelf `Client` model
refreshToken {string} Refresh token
Returns
{Object} Returns a promise with tokens
The returned JSON object is like:
{
"access_token":"<token>",
"refresh_token":"<refreshtoken>",
"expires_in":3600,
"token_type":"Bearer"
}
Revokes a token. If force
is specified it removes all active tokens associated to user or client.
Arguments
token {string} Access token
force {bool} Removes all tokens
Returns
{bool} Returns true
Checks credentials for the given user on LDAP.
Arguments
username {string} Username
password {string} Password
Returns
{string} Returns null if user was not found, otherwise the attribute value specified in configuration
Throws
{LDAPConnectionError|LDAPBindError|LDAPUnbindError|LDAPSearchError}
Express
middlewaresThis middleware protects your endpoint and checks if request contains basic credentials or a valid bearer token.
See about authorizations
for request's details.
Example
router.route('/protected/resource').post(ideman.isAuthenticated, function() {
res.json({
data: 'The protected resource'
});
});
Request
# using HTTP Basic Authentication
$ curl -u userId:userPwd -X GET http://localhost:3000/protected/resource
# using Bearer token
$ curl -H 'Authorization: Bearer NgvhmoKm9ASMCa3KGLh2yjNPqhIhFLEgPacesMFiIOQPuZ1Mq19Xg' -X POST http://localhost:3000/protected/resource
This middleware has been used with token
endpoint and checks for valid client credentials before getting an access token.
See about authorizations
for request's details.
Example
router.route('/oauth2/token').post(ideman.isClientAuthenticated, ideman.token);
Request
# user credentials grant
$ curl -H 'Accept: application/x-www-form-urlencoded' -X POST -d 'grant_type=password&client_id=clientId&username=userId&password=userPassword' http://localhost:3000/oauth2/token
# user credentials grant with basic auth
$ curl -u clientId:clientSecret -H 'Accept: application/x-www-form-urlencoded' -X POST -d 'grant_type=password&username=userId&password=userPassword' http://localhost:3000/oauth2/token
# client credentials grant
$ curl -H 'Accept: application/x-www-form-urlencoded' -X POST -d 'grant_type=client_credentials&client_id=clientId&client_secret=clientSecret' http://localhost:3000/oauth2/token
# client credentials grant with basic auth
$ curl -u clientId:clientSecret -H 'Accept: application/x-www-form-urlencoded' -X POST -d 'grant_type=client_credentials' http://localhost:3000/oauth2/token
# refresh token grant
$ curl -H 'Accept: application/x-www-form-urlencoded' -u clientId:clientSecret -X POST -d 'grant_type=refresh_token&refresh_token=wRv7bQiR8W7mEYTTlHsSXw4HL0DqP2qM12gQTN7XbSq74Z7JkNyUTv3ZeN' http://localhost:3000/oauth2/token
Express
endpointsThis endpoint has been used with isClientAuthenticated
middleware and returns an access token.
Example
router.route('/oauth2/token').post(ideman.isClientAuthenticated, ideman.token);
This endpoint has been used with isAuthenticated
middleware and revokes the current token.
Example
router.route('/oauth2/logout').post(ideman.isAuthenticated, ideman.logout);
OAuth 2.0 is the next evolution of the OAuth protocol which was originally created in late 2006. OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and living room devices.
HTTP Basic authentication
implementation is the simplest technique for enforcing access controls to web resources because it doesn't require cookies, session identifier and login pages. This authentication method uses static, standard fields in the HTTP header.
Send in the user credentials directly in the header to call a protected resource:
$ curl -u userId:userPwd -X GET http://localhost:3000/users
The Authorization Code
grant type is used when the client wants to request access to protected resources on behalf of another user (i.e. a 3rd party). This is the grant type most often associated with OAuth.
First, redirect the user to the following URL:
http://localhost:3000/oauth2/authorize?client_id=client&response_type=code&redirect_uri=http://localhost:3000
A successful authorization will pass the client the authorization code in the URL via the supplied redirect_uri:
http://localhost:3000/?code=0tlpnc37ElYTa7Sh
Once this is done, a token can be requested using the authorization code.
$ curl -u clientId:clientSecret -H 'Accept: application/x-www-form-urlencoded' -X POST -d 'grant_type=authorization_code&code=0tlpnc37ElYTa7Sh&redirect_uti=http://localhost:3000' http://localhost:3000/oauth2/token
A successful token request will return a standard access token in JSON format:
{
"access_token":"NgvhmoKm9ASMCa3KGLh2yjNPqhIhFLEgPacesMFiIOQPuZ1Mq19XgEOprNnKuxi8DGcK59aAdUCBhqosKV8GDw4pwxdzoryjaViv0GQi04d0cWFZRxxqheF552h7Ok7SOCL8ndxPgLqf5WzSy22zHF5Hhg8SZPRCAPOos6QgDi4oZnR0EGkyhEgHCchKUDmfmHWxlqCuZDau2gswwx41h9ZhozvLVJJIB0rB4huVGg7sCyqtbo5Lg1M61BwjahWd",
"refresh_token":"wRv7bQiR8W7mEYTTlHsSXw4HL0DqP2qM12gQTN7XbSq74Z7JkNyUTHLgxg0CIBY13G2O46PAWNUtaoDgWRYONYR7u9npnkQeCAXqi2MFuXfJnrWOCFf3nJiWU76cZUV1jgQzR1I2YQngfTvvT96gO8qCrhLjikWDzMnv9yexwubEfX7LcG5eekzKQrW9UwZgP3kaas46nEUXs5G5VY8Fl79JnHk0uDvKZR1ERsdbtHwVWkZSmGC5TEiRfPVv3ZeN",
"expires_in":3600,
"token_type":"Bearer"
}
The User Credentials
grant type (a.k.a. Resource Owner Password Credentials
) is used when the user has a trusted relationship with the client, and so can supply credentials directly.
Send in the user credentials directly to receive an access token:
# using POST Body
$ curl -H 'Accept: application/x-www-form-urlencoded' -X POST -d 'grant_type=password&client_id=clientId&client_secret=clientSecret&username=userId&password=userPassword' http://localhost:3000/oauth2/token
# using HTTP Basic Authentication
$ curl -u clientId:clientSecret -H 'Accept: application/x-www-form-urlencoded' -X POST -d 'grant_type=password&username=userId&password=userPassword' http://localhost:3000/oauth2/token
A successful token request will return a standard access token in JSON format:
{
"access_token":"NgvhmoKm9ASMCa3KGLh2yjNPqhIhFLEgPacesMFiIOQPuZ1Mq19XgEOprNnKuxi8DGcK59aAdUCBhqosKV8GDw4pwxdzoryjaViv0GQi04d0cWFZRxxqheF552h7Ok7SOCL8ndxPgLqf5WzSy22zHF5Hhg8SZPRCAPOos6QgDi4oZnR0EGkyhEgHCchKUDmfmHWxlqCuZDau2gswwx41h9ZhozvLVJJIB0rB4huVGg7sCyqtbo5Lg1M61BwjahWd",
"refresh_token":"wRv7bQiR8W7mEYTTlHsSXw4HL0DqP2qM12gQTN7XbSq74Z7JkNyUTHLgxg0CIBY13G2O46PAWNUtaoDgWRYONYR7u9npnkQeCAXqi2MFuXfJnrWOCFf3nJiWU76cZUV1jgQzR1I2YQngfTvvT96gO8qCrhLjikWDzMnv9yexwubEfX7LcG5eekzKQrW9UwZgP3kaas46nEUXs5G5VY8Fl79JnHk0uDvKZR1ERsdbtHwVWkZSmGC5TEiRfPVv3ZeN",
"expires_in":3600,
"token_type":"Bearer"
}
The Client Credentials
grant type is used when the client is requesting access to protected resources under its control (i.e. there is no third party).
Send in the client credentials directly to receive an access token:
# using POST Body
$ curl -H 'Accept: application/x-www-form-urlencoded' -X POST -d 'grant_type=client_credentials&client_id=clientId&client_secret=clientSecret' http://localhost:3000/oauth2/token
# using HTTP Basic Authentication
$ curl -u clientId:clientSecret -H 'Accept: application/x-www-form-urlencoded' -X POST -d 'grant_type=client_credentials' http://localhost:3000/oauth2/token
A successful token request will return a standard access token in JSON format:
{
"access_token":"NgvhmoKm9ASMCa3KGLh2yjNPqhIhFLEgPacesMFiIOQPuZ1Mq19XgEOprNnKuxi8DGcK59aAdUCBhqosKV8GDw4pwxdzoryjaViv0GQi04d0cWFZRxxqheF552h7Ok7SOCL8ndxPgLqf5WzSy22zHF5Hhg8SZPRCAPOos6QgDi4oZnR0EGkyhEgHCchKUDmfmHWxlqCuZDau2gswwx41h9ZhozvLVJJIB0rB4huVGg7sCyqtbo5Lg1M61BwjahWd",
"refresh_token":"wRv7bQiR8W7mEYTTlHsSXw4HL0DqP2qM12gQTN7XbSq74Z7JkNyUTHLgxg0CIBY13G2O46PAWNUtaoDgWRYONYR7u9npnkQeCAXqi2MFuXfJnrWOCFf3nJiWU76cZUV1jgQzR1I2YQngfTvvT96gO8qCrhLjikWDzMnv9yexwubEfX7LcG5eekzKQrW9UwZgP3kaas46nEUXs5G5VY8Fl79JnHk0uDvKZR1ERsdbtHwVWkZSmGC5TEiRfPVv3ZeN",
"expires_in":3600,
"token_type":"Bearer"
}
The Refresh Token
grant type is used to obtain additional access tokens in order to prolong the client’s authorization of a user’s resources.
First, a refresh token must be retrieved using the Authorizaton Code or User Credentials grant types:
$ curl -H 'Accept: application/x-www-form-urlencoded' -X POST -d 'grant_type=password&client_id=clientId&client_secret=clientSecret&username=userId&password=userPassword' http://localhost:3000/oauth2/token
The access token will then contain a refresh token:
{
"access_token":"NgvhmoKm9ASMCa3KGLh2yjNPqhIhFLEgPacesMFiIOQPuZ1Mq19XgEOprNnKuxi8DGcK59aAdUCBhqosKV8GDw4pwxdzoryjaViv0GQi04d0cWFZRxxqheF552h7Ok7SOCL8ndxPgLqf5WzSy22zHF5Hhg8SZPRCAPOos6QgDi4oZnR0EGkyhEgHCchKUDmfmHWxlqCuZDau2gswwx41h9ZhozvLVJJIB0rB4huVGg7sCyqtbo5Lg1M61BwjahWd",
"refresh_token":"wRv7bQiR8W7mEYTTlHsSXw4HL0DqP2qM12gQTN7XbSq74Z7JkNyUTHLgxg0CIBY13G2O46PAWNUtaoDgWRYONYR7u9npnkQeCAXqi2MFuXfJnrWOCFf3nJiWU76cZUV1jgQzR1I2YQngfTvvT96gO8qCrhLjikWDzMnv9yexwubEfX7LcG5eekzKQrW9UwZgP3kaas46nEUXs5G5VY8Fl79JnHk0uDvKZR1ERsdbtHwVWkZSmGC5TEiRfPVv3ZeN",
"expires_in":3600,
"token_type":"Bearer"
}
This refresh token can then be used to generate a new access token of equal or lesser scope:
$ curl -H 'Accept: application/x-www-form-urlencoded' -u clientId:clientSecret -X POST -d 'grant_type=refresh_token&refresh_token=wRv7bQiR8W7mEYTTlHsSXw4HL0DqP2qM12gQTN7XbSq74Z7JkNyUTHLgxg0CIBY13G2O46PAWNUtaoDgWRYONYR7u9npnkQeCAXqi2MFuXfJnrWOCFf3nJiWU76cZUV1jgQzR1I2YQngfTvvT96gO8qCrhLjikWDzMnv9yexwubEfX7LcG5eekzKQrW9UwZgP3kaas46nEUXs5G5VY8Fl79JnHk0uDvKZR1ERsdbtHwVWkZSmGC5TEiRfPVv3ZeN' http://localhost:3000/oauth2/token
A successful token request will return a standard access token in JSON format:
{
"access_token":"vLBojG5gsVvP7EwIfu9OEAE1daWsicRLN4KmS4goRUdoJPagEx1rvOce1UVbQc2S8EVEP47A9KmWGqofyT94AE7zVowigyE4eobqVmNvb6z6yRHZNT2oaTZ486yThtrJ078SuqRhPRM67KG37c6KJTLDZPECYYZN3fefBFlFG9EbOFeAChszT6kXI96Q9uunZKRuadMEcl8PqueqDfJh203DPzDwwX33lufJYPgZGnZdaVeY11c26NwOkk68g6wx",
"refresh_token":"h5odKWZh9p3ueYDK10RljCblXbsPOKNjX0HhaV0EcCOn4DNm5PX8NtpEoWo2LTL717rNcHXF8LoosrDtrNn9BOLZHJVpuItfzM8pHJFB8gMBBE8NVkDSin1qvaRs8ubWxxLN8PE9qbZSvo4NBzsbhwLS49HMmL4z963S4YXWQrtu5t829NuWGvYU2UBlSNYIUsrBOZe9bW0XZJ5xEBdHZ4tBg06tSDE4VZTyGwtjk8HTkMAqybGwA8FB6UggRNr7",
"expires_in":3600,
"token_type":"Bearer"
}
The MIT License
Copyright (c) 2017 Michele Andreoli http://thinkingmik.com
FAQs
Node module for users authentication management
We found that ideman demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Maintainers back GitHub’s npm security overhaul but raise concerns about CI/CD workflows, enterprise support, and token management.
Product
Socket Firewall is a free tool that blocks malicious packages at install time, giving developers proactive protection against rising supply chain attacks.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.