Comparing version 0.0.2 to 0.1.0
27
index.js
@@ -13,6 +13,7 @@ const express = require('express'); | ||
serviceValidator = () => true, | ||
useCookie = false, | ||
cookieOptions = {}, | ||
app = express(), | ||
} = {} | ||
) => { | ||
const app = express(); | ||
app.get(landingPath, [ | ||
@@ -27,2 +28,10 @@ (req, res, next) => { | ||
} | ||
if (useCookie) { | ||
const token = req.cookies.get('paale_token', cookieOptions); | ||
if (token) { | ||
return res.redirect(appendQuery(service, `token=${token}`)); | ||
} | ||
} | ||
next(); | ||
@@ -45,3 +54,8 @@ }, | ||
tokenStorage.store, | ||
(req, res) => res.redirect(appendQuery(req.paale_service, `token=${req.paale_token}`)), | ||
(req, res) => { | ||
if (useCookie) { | ||
res.cookies.set('paale_token', req.paale_token, cookieOptions); | ||
} | ||
res.redirect(appendQuery(req.paale_service, `token=${req.paale_token}`)); | ||
}, | ||
]); | ||
@@ -51,2 +65,9 @@ | ||
(req, res, next) => { | ||
if (useCookie) { | ||
req.paale_token = req.cookies.get('paale_token', cookieOptions); | ||
if (req.paale_token) { | ||
return next(); | ||
} | ||
} | ||
let parts = req.get('Authorization'); | ||
@@ -53,0 +74,0 @@ if (!parts) { |
{ | ||
"name": "paale-dai", | ||
"version": "0.0.2", | ||
"version": "0.1.0", | ||
"description": "", | ||
@@ -31,3 +31,3 @@ "scripts": { | ||
"devDependencies": { | ||
"lodash": "^4.16.4", | ||
"cookies": "^0.6.2", | ||
"eslint": "^3.8.1", | ||
@@ -37,2 +37,3 @@ "eslint-config-airbnb-base": "^9.0.0", | ||
"istanbul": "^0.4.5", | ||
"lodash": "^4.16.4", | ||
"mocha": "^3.1.2", | ||
@@ -39,0 +40,0 @@ "proxyquire": "^1.7.10", |
107
README.md
paale-dai | ||
======================= | ||
[![Build Status](https://travis-ci.org/IntroCept/paale-dai.svg?branch=master)](https://travis-ci.org/IntroCept/paale-dai) | ||
[![Coverage Status](https://coveralls.io/repos/github/IntroCept/paale-dai/badge.svg?branch=master)](https://coveralls.io/github/IntroCept/paale-dai?branch=master) | ||
[![NPM Version][npm-image]][npm-url] | ||
[![NPM Downloads][downloads-image]][downloads-url] | ||
[![Build Status][travis-image]][travis-url] | ||
[![Test Coverage][coveralls-image]][coveralls-url] | ||
@@ -24,2 +26,101 @@ paale-dai is an express based middleware for creating SSO based authentication microservice. | ||
// or express().use('/paale', server); | ||
``` | ||
``` | ||
## Install | ||
This is a [Node.js](https://nodejs.org/en/) module available through the | ||
[npm registry](https://www.npmjs.com/). Installation is done using the | ||
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): | ||
``` | ||
$ npm install paale-dai | ||
``` | ||
## Basic concept | ||
![Basic overview](docs/basic-flow.svg) | ||
## Handler | ||
Handler is the object which actually handles the authentication. Currently, this modules only ships with `google-oauth2` handler which does authentication based on google oauth2. Similarly you can rewrite your own handler like based on facebook oauth2 flow. | ||
### Example handler based on username/password | ||
```js | ||
const handler = { | ||
landing(callbackPath) { | ||
return (req, res, next) => { | ||
// render login page here | ||
}; | ||
}, | ||
authentication(callbackPath) { | ||
return (req, res, next) => { | ||
if (user = validateUser(req.body.username, req.body.password)) { | ||
req.paale_user = user; | ||
next(); | ||
} | ||
// incorrect authentication attempt | ||
}; | ||
}, | ||
parseService(req) { | ||
return req.query.service; | ||
} | ||
}; | ||
``` | ||
## Using cookies | ||
You can enable cookie support using package [cookies](cookie-package) if you don't want the handler to do authentication every time login request is made by the user. | ||
```js | ||
const express = require('express'); | ||
const Cookies = require('cookies'); | ||
const app = express(); | ||
app.use(Cookies.express()); | ||
paale( | ||
handler(), | ||
jwtStorage(), | ||
{ | ||
useCookie: true, | ||
app | ||
} | ||
); | ||
``` | ||
## API | ||
``` | ||
paale( | ||
handler, | ||
tokenStorage, | ||
{ | ||
identityPath = '/user', | ||
landingPath = '/', | ||
callbackPath = '/authentication', | ||
callbackRouteMethod = 'get', | ||
serviceValidator = () => true, | ||
useCookie = false, | ||
cookieOptions = {}, | ||
app = express(), | ||
} = {} | ||
) | ||
``` | ||
## Validating token | ||
In the above figure, after the application has received the token, it can make query to `paale-dai` to validate the token using cookie `paale_token=token` or header `Authorization: Bearer token` | ||
## Token storage | ||
Token storage are a way to store the tokens. They map a token to a user. You can store the tokens in a database by creating a custom token storage. | ||
By default this package ships with only JWT based token storage. If you use it, the applications can validate the token themselves without querying the `paale-dai` all the time if they have the public key. | ||
[npm-image]: https://img.shields.io/npm/v/paale-dai.svg | ||
[npm-url]: https://npmjs.org/package/paale-dai | ||
[coveralls-image]: https://coveralls.io/repos/github/IntroCept/paale-dai/badge.svg?branch=master | ||
[coveralls-url]: https://coveralls.io/github/IntroCept/paale-dai?branch=master | ||
[downloads-image]: https://img.shields.io/npm/dm/paale-dai.svg | ||
[downloads-url]: https://npmjs.org/package/paale-dai | ||
[travis-image]: https://travis-ci.org/IntroCept/paale-dai.svg?branch=master | ||
[travis-url]: https://travis-ci.org/IntroCept/paale-dai | ||
[cookie-package]: https://npmjs.org/package/cookies | ||
@@ -7,2 +7,4 @@ const should = require('should'); | ||
const jwtModule = require('jsonwebtoken'); | ||
const Cookies = require('cookies'); | ||
const express = require('express'); | ||
const proxyquire = require('proxyquire').noCallThru(); | ||
@@ -55,4 +57,3 @@ const paale = require('../../index'); | ||
describe('Post Google Redirection', () => { | ||
let app, | ||
agent, | ||
let agent, | ||
stateEncoder, | ||
@@ -62,3 +63,4 @@ OAuth2, | ||
const state = 'tgije', | ||
const app = express(), | ||
state = 'tgije', | ||
google = {}, | ||
@@ -107,3 +109,6 @@ service = 'http://senani.introcept.co', | ||
}); | ||
app = paale( | ||
app.use(Cookies.express()); | ||
paale( | ||
handler('GOOGLE_CLIENT_ID', 'GOOGLE_CLIENT_SECRET'), | ||
@@ -114,4 +119,7 @@ jwtStorage(), | ||
serviceValidator: service => !_.startsWith(service, 'http://danger'), | ||
useCookie: true, | ||
app | ||
} | ||
); | ||
agent = request.agent(app); | ||
@@ -138,14 +146,2 @@ }); | ||
// it('should check if email belongs to introcept.co', function () { | ||
// people.get = function (opts, callback) { | ||
// return callback(null, { | ||
// domain: 'gmail.com' | ||
// }); | ||
// }; | ||
// | ||
// var req = agent.get(appendQuery(callbackPath, 'code=' + code + '&state=' + state)) | ||
// .expect(403, 'You must have an email address from introcept.co'); | ||
// return endRequest(req); | ||
// }); | ||
it('should redirect to original requesting service', () => { | ||
@@ -174,11 +170,23 @@ const response = { | ||
.expect(302); | ||
return endRequest(req); | ||
return endRequest(req) | ||
.then((res) => { | ||
res.header.location.should.be.exactly(appendQuery(service, `token=${token}`)); | ||
}); | ||
}); | ||
it('should retrieve from cookies the next time and directly redirect to the redirecting service', () => { | ||
const req = agent.get('/?service=http://senani.introcept.co') | ||
.expect(302); | ||
return endRequest(req) | ||
.then((res) => { | ||
res.header.location.should.be.exactly(appendQuery(service, `token=${token}`)); | ||
}); | ||
}); | ||
}); | ||
describe('Profile API tests', () => { | ||
let app, | ||
agent, | ||
let agent, | ||
jwt = { JsonWebTokenError: jwtModule.JsonWebTokenError, TokenExpiredError: jwtModule.TokenExpiredError }; | ||
const token = 'o35234-o2345'; | ||
const token = 'o35234-o2345', | ||
app = express(); | ||
before(() => { | ||
@@ -189,3 +197,6 @@ const handler = require(path.resolve('./handler/google-oauth2')); | ||
}); | ||
app = paale( | ||
app.use(Cookies.express()); | ||
paale( | ||
handler('GOOGLE_CLIENT_ID', 'GOOGLE_CLIENT_SECRET'), | ||
@@ -195,2 +206,4 @@ jwtStorage(), | ||
identityPath: '/me', | ||
useCookie: true, | ||
app | ||
} | ||
@@ -235,3 +248,3 @@ ); | ||
it('should return expired token response for expired token', () => { | ||
it('should use cookie to retrieve token and return expired token response for expired token', () => { | ||
jwt.verify = function (sourceToken, key, opts, callback) { | ||
@@ -243,9 +256,7 @@ sourceToken.should.be.exactly(token); | ||
const req = agent.get('/me') | ||
.set('Authorization', `Bearer ${token}`) | ||
.set('Cookie', `paale_token=${token}`) | ||
.expect(401); | ||
return endRequest(req) | ||
.then((response) => { | ||
response.body.code.should.be.exactly('expiredToken'); | ||
}); | ||
.then((response) => response.body.code.should.be.exactly('expiredToken')); | ||
}); | ||
@@ -252,0 +263,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
102560
15
467
126
9