@thream/socketio-jwt
Advanced tools
Comparing version 1.0.1 to 1.1.0
@@ -9,7 +9,7 @@ "use strict"; | ||
const fixture_1 = require("./fixture"); | ||
describe('authorize', () => { | ||
describe('authorize - with secret as string in options', () => { | ||
let token = ''; | ||
beforeEach((done) => { | ||
beforeEach(async (done) => { | ||
jest.setTimeout(15000); | ||
fixture_1.fixtureStart(async () => { | ||
await fixture_1.fixtureStart(async () => { | ||
const response = await axios_1.default.post('http://localhost:9000/login'); | ||
@@ -64,1 +64,27 @@ token = response.data.token; | ||
}); | ||
const secretCallback = async () => { | ||
return 'somesecret'; | ||
}; | ||
describe('authorize - with secret as callback in options', () => { | ||
let token = ''; | ||
beforeEach(async (done) => { | ||
jest.setTimeout(15000); | ||
await fixture_1.fixtureStart(async () => { | ||
const response = await axios_1.default.post('http://localhost:9000/login'); | ||
token = response.data.token; | ||
done(); | ||
}, { secret: secretCallback }); | ||
}); | ||
afterEach((done) => { | ||
fixture_1.fixtureStop(done); | ||
}); | ||
it('should connect the user', (done) => { | ||
const socket = socket_io_client_1.io('http://localhost:9000', { | ||
extraHeaders: { Authorization: `Bearer ${token}` } | ||
}); | ||
socket.on('connect', () => { | ||
socket.close(); | ||
done(); | ||
}); | ||
}); | ||
}); |
@@ -1,2 +0,3 @@ | ||
export declare const fixtureStart: (done: any) => void; | ||
import { AuthorizeOptions } from '../../index'; | ||
export declare const fixtureStart: (done: any, options?: AuthorizeOptions) => Promise<void>; | ||
export declare const fixtureStop: (callback: Function) => void; |
@@ -19,7 +19,13 @@ "use strict"; | ||
let server = null; | ||
const fixtureStart = (done) => { | ||
const fixtureStart = async (done, options = { secret: 'aaafoo super sercret' }) => { | ||
var _a; | ||
const options = { secret: 'aaafoo super sercret' }; | ||
const app = express_1.default(); | ||
app.use(express_1.default.json()); | ||
let keySecret = 'secret'; | ||
if (typeof options.secret === 'string') { | ||
keySecret = options.secret; | ||
} | ||
else { | ||
keySecret = await options.secret(() => { }); | ||
} | ||
app.post('/login', (_req, res) => { | ||
@@ -30,3 +36,5 @@ const profile = { | ||
}; | ||
const token = jsonwebtoken_1.default.sign(profile, options.secret, { expiresIn: 60 * 60 * 5 }); | ||
const token = jsonwebtoken_1.default.sign(profile, keySecret, { | ||
expiresIn: 60 * 60 * 5 | ||
}); | ||
return res.json({ token }); | ||
@@ -33,0 +41,0 @@ }); |
@@ -0,10 +1,23 @@ | ||
import { Algorithm } from 'jsonwebtoken'; | ||
import { Socket } from 'socket.io'; | ||
declare module 'socket.io' { | ||
interface Socket extends ExtendedSocket { | ||
} | ||
} | ||
interface ExtendedError extends Error { | ||
data?: any; | ||
} | ||
interface ExtendedSocket { | ||
encodedToken?: string; | ||
decodedToken?: any; | ||
} | ||
declare type SocketIOMiddleware = (socket: Socket, next: (err?: ExtendedError) => void) => void; | ||
interface AuthorizeOptions { | ||
secret: string; | ||
declare type SecretCallback = (decodedToken: null | { | ||
[key: string]: any; | ||
} | string) => Promise<string>; | ||
export interface AuthorizeOptions { | ||
secret: string | SecretCallback; | ||
algorithms?: Algorithm[]; | ||
} | ||
export declare const authorize: (options: AuthorizeOptions) => SocketIOMiddleware; | ||
export {}; |
@@ -10,5 +10,5 @@ "use strict"; | ||
const authorize = (options) => { | ||
const { secret } = options; | ||
return (socket, next) => { | ||
let token = null; | ||
const { secret, algorithms = ['HS256'] } = options; | ||
return async (socket, next) => { | ||
let encodedToken = null; | ||
const authorizationHeader = socket.request.headers.authorization; | ||
@@ -22,5 +22,5 @@ if (authorizationHeader != null) { | ||
} | ||
token = tokenSplitted[1]; | ||
encodedToken = tokenSplitted[1]; | ||
} | ||
if (token == null) { | ||
if (encodedToken == null) { | ||
return next(new UnauthorizedError_1.UnauthorizedError('credentials_required', { | ||
@@ -31,6 +31,14 @@ message: 'no token provided' | ||
// Store encoded JWT | ||
socket = Object.assign(socket, { encodedToken: token }); | ||
let payload; | ||
socket.encodedToken = encodedToken; | ||
let keySecret = null; | ||
let decodedToken; | ||
if (typeof secret === 'string') { | ||
keySecret = secret; | ||
} | ||
else { | ||
decodedToken = jsonwebtoken_1.default.decode(encodedToken, { complete: true }); | ||
keySecret = await secret(decodedToken); | ||
} | ||
try { | ||
payload = jsonwebtoken_1.default.verify(token, secret); | ||
decodedToken = jsonwebtoken_1.default.verify(encodedToken, keySecret, { algorithms }); | ||
} | ||
@@ -43,3 +51,3 @@ catch { | ||
// Store decoded JWT | ||
socket = Object.assign(socket, { decodedToken: payload }); | ||
socket.decodedToken = decodedToken; | ||
return next(); | ||
@@ -46,0 +54,0 @@ }; |
# Changelog | ||
## [1.1.0](https://github.com/Thream/socketio-jwt/compare/v1.0.1...v1.1.0) (2021-01-07) | ||
### Features | ||
- add algorithms option ([abbabc5](https://github.com/Thream/socketio-jwt/commit/abbabc588e3ea8b906fa0a0dcc83c91a3b5b5ea8)) | ||
- add support for jwks-rsa ([#1](https://github.com/Thream/socketio-jwt/issues/1)) ([261e8d6](https://github.com/Thream/socketio-jwt/commit/261e8d66e2ec6fefb77429abcef8f846d996ecac)) | ||
- improve types by extending socket.io module ([#6](https://github.com/Thream/socketio-jwt/issues/6)) ([84b523f](https://github.com/Thream/socketio-jwt/commit/84b523f4348c81933887f0dc700f438c84bd779a)) | ||
## [1.0.1](https://github.com/Thream/socketio-jwt/compare/v1.0.0...v1.0.1) (2020-12-29) | ||
- docs(readme): fix usage section by correctly importing `authorize` | ||
### Documentation | ||
- fix usage section by correctly importing `authorize` | ||
## [1.0.0](https://github.com/Thream/socketio-jwt/compare/v4.6.2...v1.0.0) (2020-12-29) | ||
Initial release. |
{ | ||
"name": "@thream/socketio-jwt", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "Authenticate socket.io incoming connections with JWTs.", | ||
@@ -75,3 +75,3 @@ "license": "MIT", | ||
"build": "rimraf ./build && tsc", | ||
"lint": "exit 0", | ||
"lint": "ts-standard | snazzy", | ||
"format": "ts-standard --fix | snazzy", | ||
@@ -84,3 +84,3 @@ "release": "release-it", | ||
"peerDependencies": { | ||
"socket.io": "*" | ||
"socket.io": ">=3.0.0" | ||
}, | ||
@@ -95,9 +95,9 @@ "dependencies": { | ||
"@types/express": "4.17.9", | ||
"@types/jest": "26.0.19", | ||
"@types/jest": "26.0.20", | ||
"@types/jsonwebtoken": "8.5.0", | ||
"@types/node": "14.14.16", | ||
"@types/node": "14.14.20", | ||
"@types/server-destroy": "1.0.1", | ||
"axios": "0.21.1", | ||
"express": "4.17.1", | ||
"husky": "4.3.6", | ||
"husky": "4.3.7", | ||
"jest": "26.6.3", | ||
@@ -108,4 +108,4 @@ "release-it": "14.2.2", | ||
"snazzy": "9.0.0", | ||
"socket.io": "3.0.4", | ||
"socket.io-client": "3.0.4", | ||
"socket.io": "3.0.5", | ||
"socket.io-client": "3.0.5", | ||
"ts-jest": "26.4.4", | ||
@@ -112,0 +112,0 @@ "ts-standard": "10.0.0", |
@@ -1,2 +0,2 @@ | ||
<h1 align="center"><a href="https://www.npmjs.com/package/@thream/socketio-jwt">Thream/socketio-jwt</a></h1> | ||
<h1 align="center">Thream/socketio-jwt</h1> | ||
@@ -15,3 +15,3 @@ <p align="center"> | ||
<a href="https://conventionalcommits.org"><img src="https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg" alt="Conventional Commits" /></a> | ||
<a href="./.github/CODE_OF_CONDUCT.md"><img src="https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg" alt="Contributor Covenant" /></a> | ||
<a href="https://github.com/Thream/Thream/blob/master/.github/CODE_OF_CONDUCT.md"><img src="https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg" alt="Contributor Covenant" /></a> | ||
</p> | ||
@@ -23,3 +23,3 @@ | ||
Compatible with `socket.io >= 3.0`. | ||
Compatible with `socket.io >= 3.0.0`. | ||
@@ -49,9 +49,13 @@ This repository was originally forked from [auth0-socketio-jwt](https://github.com/auth0-community/auth0-socketio-jwt) & it is not intended to take any credit but to improve the code from now on. | ||
io.on('connection', async () => { | ||
io.on('connection', async (socket) => { | ||
// jwt payload of the connected client | ||
console.log(socket.decodedToken) | ||
const clients = await io.sockets.allSockets() | ||
for (const clientId of clients) { | ||
const client = io.sockets.sockets.get(clientId) | ||
client.emit('messages', { message: 'Success!' }) | ||
// we can access the jwt payload of each connected client | ||
console.log(client.decodedToken) | ||
if (clients != null) { | ||
for (const clientId of clients) { | ||
const client = io.sockets.sockets.get(clientId) | ||
client?.emit('messages', { message: 'Success!' }) | ||
// we can access the jwt payload of each connected client | ||
console.log(client?.decodedToken) | ||
} | ||
} | ||
@@ -61,2 +65,30 @@ }) | ||
### Server side with `jwks-rsa` (example) | ||
```ts | ||
import jwksClient from 'jwks-rsa' | ||
import { Server } from 'socket.io' | ||
import { authorize } from '@thream/socketio-jwt' | ||
const client = jwksClient({ | ||
jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json' | ||
}) | ||
const io = new Server(9000) | ||
io.use( | ||
authorize({ | ||
secret: async (decodedToken) => { | ||
const key = await client.getSigningKeyAsync(decodedToken.header.kid) | ||
return key.rsaPublicKey | ||
} | ||
}) | ||
) | ||
io.on('connection', async (socket) => { | ||
// jwt payload of the connected client | ||
console.log(socket.decodedToken) | ||
// You can do the same things of the previous example there... | ||
}) | ||
``` | ||
### Client side | ||
@@ -63,0 +95,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
18233
266
122