@tsmx/express-jwt-validator
Advanced tools
Comparing version 1.0.4 to 1.1.0
const jwt = require('jsonwebtoken'); | ||
const bearerPrefix = 'Bearer'; | ||
const defaultHeader = 'authorization'; | ||
@@ -7,2 +9,3 @@ const defaultFailedStatus = 401; | ||
const defaultRequestAuthProp = 'authData'; | ||
const defaultStrictBearerValidation = false; | ||
@@ -19,2 +22,3 @@ module.exports = (conf) => { | ||
const requestAuthProp = conf.requestAuthProp ? conf.requestAuthProp : defaultRequestAuthProp; | ||
const strictBearerValidation = Object.prototype.hasOwnProperty.call(conf, 'strictBearerValidation') ? conf.strictBearerValidation === true : defaultStrictBearerValidation; | ||
// return middleware function | ||
@@ -30,2 +34,9 @@ return (req, res, next) => { | ||
} | ||
if (strictBearerValidation) { | ||
if (bearer.length !== 2 || bearer[0] !== bearerPrefix) { | ||
if (conf.logger) conf.logger.warn('Strict Bearer validation failed. Denying request.'); | ||
res.sendStatus(rejectHttpStatus); | ||
return; | ||
} | ||
} | ||
const bearerToken = bearer[1]; | ||
@@ -32,0 +43,0 @@ jwt.verify(bearerToken, conf.secret, (err, authData) => { |
{ | ||
"name": "@tsmx/express-jwt-validator", | ||
"version": "1.0.4", | ||
"version": "1.1.0", | ||
"description": "Simple express middleware for validating JWT bearer tokens.", | ||
@@ -5,0 +5,0 @@ "main": "express-jwt-validator.js", |
@@ -53,2 +53,12 @@ # [**@tsmx/express-jwt-validator**](https://github.com/tsmx/express-jwt-validator) | ||
| Property | Description | | ||
|----------|-------------| | ||
| [secret](#secret) | The JWT validation secret | | ||
| [header](#header) | Custom header HTTP name | | ||
| [strictBearerValidation](#strictbearervalidation) | Enable/disable strict validation | | ||
| [rejectHttpStatus](#rejecthttpstatus) | Custom HTTP response status for failed validations | | ||
| [sendExpiredMessage](#sendexpiredmessage) | Enable/disable error message for expired tokens | | ||
| [requestAuthProp](#requestauthprop) | Custom property name to store token data in `req` | | ||
| [logger](#logger) | An optional logger to receive log output | | ||
### secret | ||
@@ -91,2 +101,21 @@ | ||
### strictBearerValidation | ||
Type: `Boolean` | ||
Default: `false` | ||
Mandatory: no | ||
If set to true, the authorization header is strictly validated against the schema `Bearer <JWT>` (including the whitespace), like `Bearer eyJhb...`. If set to false (default), it is sufficient if the header consists of two strings separated by a whitespace whereas the second entry is considered to be the JWT. | ||
Example: | ||
```js | ||
const verifyToken = require('@tsmx/express-jwt-validator')({ | ||
secret: 'MySecretKey-123456', | ||
strictBearerValidation: true | ||
}); | ||
``` | ||
### rejectHttpStatus | ||
@@ -171,2 +200,3 @@ | ||
| Rejected - No valid 'Bearer TOKEN' entry in auth header | WARN | | ||
| Rejected - Strict Bearer validation failed | WARN | | ||
| Rejected - Expired token was sent | WARN | | ||
@@ -176,3 +206,3 @@ | Rejected - Invalid token was sent (potential attack) | ERROR | | ||
Example: | ||
Example for winston: | ||
@@ -188,2 +218,16 @@ ```js | ||
}); | ||
``` | ||
Example for log4js: | ||
```js | ||
const log4js = require('log4js'); | ||
log4js.configure({ /*... log4js options ...*/ }); | ||
log4jsLogger = log4js.getLogger(); | ||
const verifyToken = require('@tsmx/express-jwt-validator')({ | ||
secret: 'MySecretKey-123456', | ||
logger: log4jsLogger | ||
}); | ||
``` |
@@ -57,2 +57,12 @@ const testApp = require('./test-app'); | ||
it('tests a failed access to a secret route with strict validation and an invalid bearer syntax and a winston logger defined', async () => { | ||
const app = testApp({ secret: testSecret, logger: winstonLogger, strictBearerValidation: true }); | ||
const request = supertest(app); | ||
const response = await request | ||
.get('/secret') | ||
.set('Authorization', 'BearerX ' + testToken); | ||
expect(response.status).toBe(401); | ||
expect(memStream.toString()).toMatch(/^WARN?/); | ||
}); | ||
it('tests a failed access to a secret route with an expired token and a winston logger defined', async () => { | ||
@@ -59,0 +69,0 @@ const app = testApp({ secret: testSecret, logger: winstonLogger }); |
@@ -65,2 +65,13 @@ const testApp = require('./test-app'); | ||
it('tests a successful access to a secret route with strict validation', async () => { | ||
const app = testApp({ secret: testSecret, strictBearerValiadtion: true }); | ||
const request = supertest(app); | ||
const response = await request | ||
.get('/secret') | ||
.set('Authorization', 'Bearer ' + testToken); | ||
expect(response.status).toBe(200); | ||
expect(response.body.authData.user).toBe('TestUser123'); | ||
expect(response.body.authData.info).toBe('test test'); | ||
}); | ||
it('tests a successful access to a secret route with a custom request property', async () => { | ||
@@ -98,2 +109,22 @@ const app = testApp({ secret: testSecret, requestAuthProp: 'tokenPayload' }); | ||
it('tests a failed access to a secret route with an strict validation (\'Bearer\' prefix wrong)', async () => { | ||
const app = testApp({ secret: testSecret, strictBearerValidation: true }); | ||
const request = supertest(app); | ||
const response = await request | ||
.get('/secret') | ||
.set('Authorization', 'BearerX ' + testToken); | ||
expect(response.status).toBe(401); | ||
expect(response.body.error).toBeUndefined(); | ||
}); | ||
it('tests a failed access to a secret route with an strict validation (too much header elements)', async () => { | ||
const app = testApp({ secret: testSecret, strictBearerValidation: true }); | ||
const request = supertest(app); | ||
const response = await request | ||
.get('/secret') | ||
.set('Authorization', 'Bearer ' + testToken * ' xxxxxx'); | ||
expect(response.status).toBe(401); | ||
expect(response.body.error).toBeUndefined(); | ||
}); | ||
it('tests a failed access to a secret route with an expired token and no error message', async () => { | ||
@@ -100,0 +131,0 @@ const app = testApp({ secret: testSecret, sendExpiredMessage: false }); |
@@ -63,2 +63,13 @@ const testApp = require('./test-app'); | ||
it('tests a failed access to a secret route with strict validation and an invalid bearer syntax and a log4js logger defined', async () => { | ||
const app = testApp({ secret: testSecret, logger: log4jsLogger, strictBearerValidation: true }); | ||
const request = supertest(app); | ||
const response = await request | ||
.get('/secret') | ||
.set('Authorization', 'BearerX ' + testToken); | ||
expect(response.status).toBe(401); | ||
expect(testOutput.length).toBe(1); | ||
expect(testOutput[0].includes('[WARN]')).toBeTruthy(); | ||
}); | ||
it('tests a failed access to a secret route with an expired token and a log4js logger defined', async () => { | ||
@@ -65,0 +76,0 @@ const app = testApp({ secret: testSecret, logger: log4jsLogger }); |
78766
446
228