Comparing version 0.5.0 to 1.0.0
181
lib/Limes.js
'use strict'; | ||
var expressJwt = require('express-jwt'), | ||
flow = require('middleware-flow'), | ||
jwt = require('jsonwebtoken'); | ||
const expressJwt = require('express-jwt'), | ||
flow = require('middleware-flow'), | ||
jwt = require('jsonwebtoken'); | ||
var Limes = function (options) { | ||
if (!options) { | ||
throw new Error('Options are missing.'); | ||
} | ||
class Limes { | ||
constructor (options) { | ||
if (!options) { | ||
throw new Error('Options are missing.'); | ||
} | ||
if (!options.identityProviderName) { | ||
throw new Error('Identity provider name is missing.'); | ||
} | ||
if (!options.privateKey && !options.certificate) { | ||
throw new Error('Specify private key and / or certificate.'); | ||
} | ||
if (!options.identityProviderName) { | ||
throw new Error('Identity provider name is missing.'); | ||
} | ||
const { | ||
identityProviderName, | ||
privateKey, | ||
certificate, | ||
expiresInMinutes = 24 * 60 | ||
} = options; | ||
if (!options.privateKey && !options.certificate) { | ||
throw new Error('Specify private key and / or certificate.'); | ||
this.identityProviderName = identityProviderName; | ||
this.privateKey = privateKey; | ||
this.certificate = certificate; | ||
this.expiresInMinutes = expiresInMinutes; | ||
} | ||
this.identityProviderName = options.identityProviderName; | ||
this.privateKey = options.privateKey; | ||
this.certificate = options.certificate; | ||
issueTokenFor (subject, payload = {}) { | ||
if (!subject) { | ||
throw new Error('Subject is missing.'); | ||
} | ||
this.expiresInMinutes = options.expiresInMinutes || (24 * 60); | ||
}; | ||
return jwt.sign(payload, this.privateKey, { | ||
algorithm: 'RS256', | ||
expiresIn: this.expiresInMinutes * 60, | ||
subject, | ||
issuer: this.identityProviderName | ||
}); | ||
} | ||
Limes.prototype.issueTokenFor = function (subject, payload) { | ||
if (!subject) { | ||
throw new Error('Subject is missing.'); | ||
issueTokenForAnonymous (payload) { | ||
return this.issueTokenFor('anonymous', payload); | ||
} | ||
payload = payload || {}; | ||
issueDecodedTokenForAnonymous (options) { | ||
const { payloadWhenAnonymous } = options; | ||
return jwt.sign(payload, this.privateKey, { | ||
algorithm: 'RS256', | ||
expiresIn: this.expiresInMinutes * 60, | ||
subject: subject, | ||
issuer: this.identityProviderName | ||
}); | ||
}; | ||
const issuedAt = Math.floor(Date.now() / 1000); | ||
const expiresAt = issuedAt + (this.expiresInMinutes * 60); | ||
Limes.prototype.issueTokenForAnonymous = function (payload) { | ||
return this.issueTokenFor('anonymous', payload); | ||
}; | ||
const token = payloadWhenAnonymous; | ||
Limes.prototype.issueDecodedTokenForAnonymous = function (options) { | ||
var expiresAt, | ||
issuedAt, | ||
token; | ||
token.iat = issuedAt; | ||
token.exp = expiresAt; | ||
token.iss = this.identityProviderName; | ||
token.sub = 'anonymous'; | ||
issuedAt = Math.floor(Date.now() / 1000); | ||
expiresAt = issuedAt + (this.expiresInMinutes * 60); | ||
return token; | ||
} | ||
token = options.payloadWhenAnonymous; | ||
token.iat = issuedAt; | ||
token.exp = expiresAt; | ||
token.iss = this.identityProviderName; | ||
token.sub = 'anonymous'; | ||
return token; | ||
}; | ||
Limes.prototype.verifyToken = function (token, callback) { | ||
jwt.verify(token, this.certificate, { | ||
issuer: this.identityProviderName | ||
}, callback); | ||
}; | ||
Limes.prototype.verifyTokenMiddlewareExpress = function (options) { | ||
var that = this; | ||
options = options || {}; | ||
options.payloadWhenAnonymous = options.payloadWhenAnonymous || {}; | ||
return flow. | ||
try(expressJwt({ | ||
secret: that.certificate, | ||
issuer: that.identityProviderName, | ||
getToken: function fromHeaderOrQuerystring (req) { | ||
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { | ||
return req.headers.authorization.split(' ')[1]; | ||
} else if (req.query && req.query.token) { | ||
return req.query.token; | ||
async verifyToken (token) { | ||
return new Promise((resolve, reject) => { | ||
jwt.verify(token, this.certificate, { | ||
issuer: this.identityProviderName | ||
}, (err, decodedToken) => { | ||
if (err) { | ||
return reject(err); | ||
} | ||
return null; | ||
} | ||
})). | ||
catch(function (err, req, res, next) { | ||
if (err.code === 'invalid_token') { | ||
return res.status(401).end(); | ||
} | ||
req.user = that.issueDecodedTokenForAnonymous(options); | ||
next(); | ||
resolve(decodedToken); | ||
}); | ||
}); | ||
}; | ||
} | ||
Limes.prototype.verifyTokenMiddlewareSocketIo = function (options) { | ||
var that = this; | ||
verifyTokenMiddlewareExpress (options = {}) { | ||
const { payloadWhenAnonymous = {}} = options; | ||
options = options || {}; | ||
options.payloadWhenAnonymous = options.payloadWhenAnonymous || {}; | ||
return flow. | ||
try(expressJwt({ | ||
secret: this.certificate, | ||
issuer: this.identityProviderName, | ||
getToken (req) { | ||
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { | ||
return req.headers.authorization.split(' ')[1]; | ||
} else if (req.query && req.query.token) { | ||
return req.query.token; | ||
} | ||
return function (socket, next) { | ||
socket.on('authenticate', function (token, callback) { | ||
callback = callback || function () {}; | ||
if (!token) { | ||
return callback({ message: 'Token is missing.' }); | ||
} | ||
that.verifyToken(token, function (err, decodedToken) { | ||
if (err) { | ||
return callback({ message: 'Token is invalid.' }); | ||
return null; | ||
} | ||
})). | ||
catch((err, req, res, next) => { | ||
if (err.code === 'invalid_token') { | ||
return res.status(401).end(); | ||
} | ||
socket.user = decodedToken; | ||
callback(null); | ||
req.user = this.issueDecodedTokenForAnonymous({ payloadWhenAnonymous }); | ||
next(); | ||
}); | ||
}); | ||
} | ||
} | ||
socket.user = that.issueDecodedTokenForAnonymous(options); | ||
next(); | ||
}; | ||
}; | ||
module.exports = Limes; |
{ | ||
"name": "limes", | ||
"version": "0.5.0", | ||
"version": "1.0.0", | ||
"description": "limes authenticates users.", | ||
@@ -15,16 +15,14 @@ "contributors": [ | ||
], | ||
"main": "lib/Limes.js", | ||
"main": "dist/Limes.js", | ||
"dependencies": { | ||
"express-jwt": "3.1.0", | ||
"jsonwebtoken": "5.4.1", | ||
"express-jwt": "5.3.0", | ||
"jsonwebtoken": "8.1.1", | ||
"middleware-flow": "0.8.0" | ||
}, | ||
"devDependencies": { | ||
"assertthat": "0.6.0", | ||
"express": "4.13.3", | ||
"grunt": "0.4.5", | ||
"socket.io": "1.3.7", | ||
"socket.io-client": "1.3.7", | ||
"supertest": "1.1.0", | ||
"tourism": "0.21.0" | ||
"assertthat": "1.0.0", | ||
"express": "4.16.2", | ||
"roboter": "0.15.6", | ||
"roboter-server": "0.15.6", | ||
"supertest": "3.0.0" | ||
}, | ||
@@ -31,0 +29,0 @@ "repository": { |
@@ -7,19 +7,21 @@ # limes | ||
$ npm install limes | ||
```shell | ||
$ npm install limes | ||
``` | ||
## Quick start | ||
First you need to add a reference to limes in your application. | ||
First you need to add a reference to limes in your application: | ||
```javascript | ||
var Limes = require('limes'); | ||
const Limes = require('limes'); | ||
``` | ||
Then you can call the `Limes` constructor function to create a new limes instance. You need to specify a parameter object with the `identityProviderName` and either a `privateKey` or a `certificate`, each in `.pem` format. Optionally, you may also provide both. | ||
Then you can call the `Limes` constructor function to create a new limes instance. You need to specify a parameter object with the `identityProviderName` and either a `privateKey` or a `certificate`, each in `.pem` format. Optionally, you may also provide both: | ||
```javascript | ||
var limes = new Limes({ | ||
const limes = new Limes({ | ||
identityProviderName: 'auth.example.com', | ||
privateKey: fs.readFileSync(path.join(__dirname, 'privateKey.pem')), | ||
certificate: fs.readFileSync(path.join(__dirname, 'certificate.pem')) | ||
privateKey: await readFile(path.join(__dirname, 'privateKey.pem')), | ||
certificate: await readFile(path.join(__dirname, 'certificate.pem')) | ||
}); | ||
@@ -32,6 +34,6 @@ ``` | ||
To issue a token call the `issueTokenFor` function and provide the subject you want to issue the token for as well as the desired payload. | ||
To issue a token call the `issueTokenFor` function and provide the subject you want to issue the token for as well as the desired payload: | ||
```javascript | ||
var token = limes.issueTokenFor('Jane Doe', { | ||
const token = limes.issueTokenFor('Jane Doe', { | ||
foo: 'bar' | ||
@@ -43,8 +45,6 @@ }); | ||
To verify a token call the `verifyToken` function and provide the token and a callback. As a result, it returns the decoded token. | ||
To verify a token call the `verifyToken` function and provide the token. As a result, it returns the decoded token: | ||
```javascript | ||
limes.verifyToken(token, function (err, decodedToken) { | ||
// ... | ||
}); | ||
const decodedToken = await limes.verifyToken(token); | ||
``` | ||
@@ -54,3 +54,3 @@ | ||
To verify tokens there are also middlewares for Express and Socket.io. To use them call the `verifyTokenMiddlewareExpress` or `verifyTokenMiddlewareSocketIo` functions and optionally specify the payload for non-authenticated users. | ||
To verify tokens there is also a middleware for Express. To use it call the `verifyTokenMiddlewareExpress` function and optionally specify the payload for non-authenticated users: | ||
@@ -63,40 +63,28 @@ ```javascript | ||
})); | ||
io.use(limes.verifyTokenMiddlewareSocketIo({ | ||
payloadWhenAnonymous: { | ||
foo: 'bar' | ||
} | ||
})); | ||
``` | ||
If a request does not provide a token, an anonymous token is issued. If a request does have an invalid token, an expired one, or one with a wrong issuer, the middleware returns a `401` respectively an error. | ||
If a request does not provide a token, an anonymous token is issued. If a request does have an invalid token, an expired one, or one with a wrong issuer, the middleware returns a `401` respectively an error. Otherwise, it attaches the decoded token to `req.user`. | ||
Otherwise, it attaches the decoded token to `req.user` respectively `socket.user`. | ||
The middleware expects the token to be inside an HTTP header called `authorization` and prefixed with the term `Bearer`: | ||
The Express middleware expects the token to be inside an HTTP header called `authorization` and prefixed with the term `Bearer`. | ||
``` | ||
authorization: Bearer <token> | ||
``` | ||
authorization: Bearer <token> | ||
Alternatively, you may transfer the token using the query string parameter `token`: | ||
Alternatively, you may transfer the token using the query string parameter `token`. | ||
GET /foo/bar?token=<token> | ||
The Socket.io middleware expects you to emit an `authenticate` event and provide the token as well as a callback. | ||
```javascript | ||
socket.emit('authenticate', token, function (err) { | ||
// ... | ||
}); | ||
``` | ||
GET /foo/bar?token=<token> | ||
``` | ||
## Running the build | ||
This module can be built using [Grunt](http://gruntjs.com/). Besides running the tests, this also analyses the code. To run Grunt, go to the folder where you have installed limes and run `grunt`. You need to have [grunt-cli](https://github.com/gruntjs/grunt-cli) installed. | ||
```shell | ||
$ bot | ||
``` | ||
$ grunt | ||
## License | ||
The MIT License (MIT) | ||
Copyright (c) 2014-2015 the native web. | ||
Copyright (c) 2014-2018 the native web. | ||
@@ -103,0 +91,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
5
551
1
1
33016
91
+ Addedasync@1.5.2(transitive)
+ Addedexpress-jwt@5.3.0(transitive)
+ Addedhoek@2.16.3(transitive)
+ Addedisemail@1.2.0(transitive)
+ Addedjoi@6.10.1(transitive)
+ Addedjsonwebtoken@7.4.38.1.1(transitive)
+ Addedlodash.includes@4.3.0(transitive)
+ Addedlodash.isboolean@3.0.3(transitive)
+ Addedlodash.isinteger@4.0.4(transitive)
+ Addedlodash.isnumber@3.0.3(transitive)
+ Addedlodash.isplainobject@4.0.6(transitive)
+ Addedlodash.isstring@4.0.1(transitive)
+ Addedlodash.once@4.1.1(transitive)
+ Addedlodash.set@4.3.2(transitive)
+ Addedmoment@2.30.1(transitive)
+ Addedms@2.1.3(transitive)
+ Addedtopo@1.1.0(transitive)
+ Addedxtend@4.0.2(transitive)
- Removedasync@0.9.2(transitive)
- Removedexpress-jwt@3.1.0(transitive)
- Removedjsonwebtoken@5.4.1(transitive)
- Removedms@0.7.3(transitive)
Updatedexpress-jwt@5.3.0
Updatedjsonwebtoken@8.1.1