Compare commits

..

No commits in common. "develop" and "v1.0.1" have entirely different histories.

44 changed files with 506 additions and 15266 deletions

View File

@ -1 +0,0 @@
{ "extends": ["@commitlint/config-conventional"] }

View File

@ -1,16 +0,0 @@
{
"extends": ["conventions", "prettier"],
"plugins": ["prettier", "import", "unicorn"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
},
"env": {
"node": true
},
"rules": {
"prettier/prettier": "error",
"import/extensions": ["error", "always"],
"unicorn/prefer-node-protocol": "error"
}
}

1
.gitattributes vendored
View File

@ -1 +0,0 @@
* text=auto eol=lf

View File

@ -60,7 +60,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at reported to the community leaders responsible for enforcement at
<contact@theoludwig.fr>. contact@divlo.fr.
All complaints will be reviewed and investigated promptly and fairly. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the All community leaders are obligated to respect the privacy and security of the

54
.github/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,54 @@
# 💡 Contributing
Thanks a lot for your interest in contributing to **Thream/socketio-jwt**! 🎉
## Code of Conduct
**Thream** has adopted the [Contributor Covenant](https://www.contributor-covenant.org/) as its Code of Conduct, and we expect project participants to adhere to it. Please read [the full text](./CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated.
## Open Development
All work on **Thream** happens directly on [GitHub](https://github.com/Thream). Both core team members and external contributors send pull requests which go through the same review process.
## Types of contributions
- Reporting a bug.
- Suggest a new feature idea.
- Correct spelling errors, improvements or additions to documentation files (README, CONTRIBUTING...).
- Improve structure/format/performance/refactor/tests of the code.
## Pull Requests
- **Please first discuss** the change you wish to make via [issue](https://github.com/Thream/socketio-jwt/issues) before making a change. It might avoid a waste of your time.
- Ensure your code respect [Typescript Standard Style](https://www.npmjs.com/package/ts-standard).
- Make sure your **code passes the tests**.
If you're adding new features to **Thream/socketio-jwt**, please include tests.
## Commits
The commit message guidelines respect [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional) and [Semantic Versioning](https://semver.org/) for releases.
### Types
Types define which kind of changes you made to the project.
| Types | Description |
| -------- | ------------------------------------------------------------------------------------------------------------ |
| feat | A new feature. |
| fix | A bug fix. |
| docs | Documentation only changes. |
| style | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc). |
| refactor | A code change that neither fixes a bug nor adds a feature. |
| perf | A code change that improves performance. |
| test | Adding missing tests or correcting existing tests. |
| build | Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm). |
| ci | Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs). |
| chore | Other changes that don't modify src or test files. |
| revert | Reverts a previous commit. |
### Scopes
Scopes define what part of the code changed.

View File

@ -1,8 +1,7 @@
--- ---
name: "🐛 Bug Report" name: '🐛 Bug Report'
about: "Report an unexpected problem or unintended behavior." about: 'Report an unexpected problem or unintended behavior.'
title: "[Bug]" labels: 'bug'
labels: "bug"
--- ---
<!-- <!--

View File

@ -1,18 +1,20 @@
--- ---
name: "📜 Documentation" name: '📜 Documentation'
about: "Correct spelling errors, improvements or additions to documentation files (README, CONTRIBUTING...)." about: 'Correct spelling errors, improvements or additions to documentation files (README, CONTRIBUTING...).'
title: "[Documentation]" labels: 'documentation'
labels: "documentation"
--- ---
<!-- Please make sure your issue has not already been fixed. --> <!--
Please make sure your issue has not already been fixed.
## Documentation Please place an x (no spaces - [x]) in all [ ] that apply.
-->
<!-- Please uncomment the type of documentation problem this issue address --> ### Documentation :
<!-- Documentation is Missing --> - [ ] Is Missing
<!-- Documentation is Confusing --> - [ ] Is Confusing
<!-- Documentation has Typo errors --> - [ ] Has Typo errors
- [ ] Not Sure?
## Proposal ### Proposal

View File

@ -1,20 +1,19 @@
--- ---
name: "✨ Feature Request" name: '✨ Feature Request'
about: "Suggest a new feature idea." about: 'Suggest a new feature idea.'
title: "[Feature]" labels: 'feature request'
labels: "feature request"
--- ---
<!-- Please make sure your issue has not already been fixed. --> <!-- Please make sure your issue has not already been fixed. -->
## Description ### Description
<!-- A clear and concise description of the problem or missing capability... --> <!-- A clear and concise description of the problem or missing capability... -->
## Describe the solution you'd like ### Describe the solution you'd like
<!-- If you have a solution in mind, please describe it. --> <!-- If you have a solution in mind, please describe it. -->
## Describe alternatives you've considered ### Describe alternatives you've considered
<!-- Have you considered any alternative solutions or workarounds? --> <!-- Have you considered any alternative solutions or workarounds? -->

View File

@ -1,20 +1,21 @@
--- ---
name: "🔧 Improvement" name: '🔧 Improvement'
about: "Improve structure/format/performance/refactor/tests of the code." about: 'Improve structure/format/performance/refactor/tests of the code.'
title: "[Improvement]" labels: 'improvement'
labels: "improvement"
--- ---
<!-- Please make sure your issue has not already been fixed. --> <!--
Please make sure your issue has not already been fixed.
## Type of Improvement Please place an x (no spaces - [x]) in all [ ] that apply.
-->
<!-- Please uncomment the type of improvements this issue address --> ### Type of Improvement :
<!-- Files and Folders Structure --> - [ ] Files and Folders Structure
<!-- Performance --> - [ ] Performance
<!-- Refactoring code --> - [ ] Refactoring code
<!-- Tests --> - [ ] Tests
<!-- Not Sure? --> - [ ] Not Sure?
## Proposal ### Proposal

View File

@ -1,8 +1,7 @@
--- ---
name: "🙋 Question" name: '🙋 Question'
about: "Further information is requested." about: 'Further information is requested.'
title: "[Question]" labels: 'question'
labels: "question"
--- ---
### Question ### Question

View File

@ -1,7 +1,27 @@
<!-- Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time. --> <!--
# What changes this PR introduce? Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time.
## List any relevant issue numbers Before submitting your contribution, please take a moment to review this document:
https://github.com/Thream/socketio-jwt/blob/master/.github/CONTRIBUTING.md
## Is there anything you'd like reviewers to focus on? Please place an x (no spaces - [x]) in all [ ] that apply.
-->
### What type of change does this PR introduce?
- [ ] Bugfix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Not Sure?
### Does this PR introduce breaking changes?
- [ ] Yes
- [ ] No
### List any relevant issue numbers:
### Description:

13
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,13 @@
# For more information see: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: 'github-actions'
directory: '/'
schedule:
interval: 'daily'
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'daily'

View File

@ -1,27 +0,0 @@
name: "Build"
on:
push:
branches: [develop]
pull_request:
branches: [master, develop]
jobs:
build:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v4.0.0"
- name: "Setup Node.js"
uses: "actions/setup-node@v3.8.1"
with:
node-version: "20.x"
cache: "npm"
- name: "Install dependencies"
run: "npm clean-install"
- name: "Build"
run: "npm run build"
- run: "npm run build:typescript"

20
.github/workflows/commitlint.yml vendored Normal file
View File

@ -0,0 +1,20 @@
# For more information see: https://github.com/marketplace/actions/commit-linter
name: 'Lint Commit Messages'
on:
push:
branches: [master, develop]
pull_request_review:
branches: [master, develop]
types: [submitted]
jobs:
commitlint:
if: ${{ (github.event_name == 'push') || (github.event_name == 'pull_request_review' && github.event.review.state == 'approved' && (github.event.review.author_association == 'COLLABORATOR' || github.event.review.author_association == 'MEMBER' || github.event.review.author_association == 'OWNER') && !github.event.pull_request.draft && github.event.pull_request.state == 'open') }}
runs-on: ubuntu-latest
steps:
- uses: 'actions/checkout@v2'
with:
fetch-depth: 0
- uses: 'wagoid/commitlint-github-action@v2'

View File

@ -1,28 +0,0 @@
name: "Lint"
on:
push:
branches: [develop]
pull_request:
branches: [master, develop]
jobs:
lint:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v4.0.0"
- name: "Setup Node.js"
uses: "actions/setup-node@v3.8.1"
with:
node-version: "20.x"
cache: "npm"
- name: "Install dependencies"
run: "npm clean-install"
- run: 'npm run lint:commit -- --to "${{ github.sha }}"'
- run: "npm run lint:editorconfig"
- run: "npm run lint:markdown"
- run: "npm run lint:eslint"
- run: "npm run lint:prettier"

47
.github/workflows/nodejs.yml vendored Normal file
View File

@ -0,0 +1,47 @@
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: 'Node.js CI'
on:
push:
branches: [master, develop]
pull_request_review:
branches: [master, develop]
types: [submitted]
jobs:
ci_app:
if: ${{ (github.event_name == 'push') || (github.event_name == 'pull_request_review' && github.event.review.state == 'approved' && (github.event.review.author_association == 'COLLABORATOR' || github.event.review.author_association == 'MEMBER' || github.event.review.author_association == 'OWNER') && !github.event.pull_request.draft && github.event.pull_request.state == 'open') }}
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: 'actions/checkout@v2'
- name: Use Node.js ${{ matrix.node-version }}
uses: 'actions/setup-node@v2.1.4'
with:
node-version: ${{ matrix.node-version }}
- name: 'Cache dependencies'
uses: 'actions/cache@v2'
with:
path: |
**/node_modules
key: ${{ runner.os }}-${{ hashFiles('**/package.json') }}
- name: 'Install dependencies'
run: 'npm install'
- name: 'Lint'
run: 'npm run lint'
- name: 'Build'
run: 'npm run build'
- name: 'Run the tests and generate coverage report'
run: 'npm test'
- name: 'Upload coverage to Codecov'
uses: 'codecov/codecov-action@v1'

30
.github/workflows/npm-publish.yml vendored Normal file
View File

@ -0,0 +1,30 @@
# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
name: 'Node.js Package'
on:
release:
types: [created]
jobs:
publish-npm:
runs-on: 'ubuntu-latest'
steps:
- uses: 'actions/checkout@v2'
- name: 'Cache dependencies'
uses: 'actions/cache@v2'
with:
path: '**/node_modules'
key: ${{ runner.os }}-${{ hashFiles('**/package.json') }}
- uses: 'actions/setup-node@v2.1.2'
with:
node-version: 14
registry-url: 'https://registry.npmjs.org/'
- run: 'npm install'
- run: 'npm run build'
- run: 'npm publish --access public'
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}

View File

@ -1,39 +0,0 @@
name: "Release"
on:
push:
branches: [master]
jobs:
release:
runs-on: "ubuntu-latest"
permissions:
contents: "write"
issues: "write"
pull-requests: "write"
id-token: "write"
steps:
- uses: "actions/checkout@v4.0.0"
- name: "Setup Node.js"
uses: "actions/setup-node@v3.8.1"
with:
node-version: "20.x"
cache: "npm"
- name: "Install dependencies"
run: "npm clean-install"
- name: "Build Package"
run: "npm run build"
- run: "npm run build:typescript"
- name: "Verify the integrity of provenance attestations and registry signatures for installed dependencies"
run: "npm audit signatures"
- name: "Release"
run: "npm run release"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@ -1,28 +0,0 @@
name: "Test"
on:
push:
branches: [develop]
pull_request:
branches: [master, develop]
jobs:
test:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v4.0.0"
- name: "Setup Node.js"
uses: "actions/setup-node@v3.8.1"
with:
node-version: "20.x"
cache: "npm"
- name: "Install dependencies"
run: "npm clean-install"
- name: "Build"
run: "npm run build"
- name: "Test"
run: "npm run test"

34
.gitignore vendored
View File

@ -2,34 +2,34 @@
# dependencies # dependencies
node_modules node_modules
.npm .pnp
.pnp.js
.yarn
# production # production
build build
.swc
# testing # testing
coverage coverage
.nyc_output
# envs
.env
.env.production
# debug # debug
npm-debug.log* npm-debug.log*
yarn-debug.log*
yarn-error.log*
# IDEs and editors # lockfiles
/.idea package-lock.json
.project yarn.lock
.classpath pnpm-lock.yaml
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode # editors
.vscode/* .vscode
!.vscode/settings.json .theia
!.vscode/tasks.json .idea
!.vscode/launch.json
!.vscode/extensions.json
# misc # misc
.DS_Store .DS_Store

View File

@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint:commit -- --edit

View File

@ -1,6 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint:staged
npm run build
npm run build:typescript

View File

@ -1,6 +0,0 @@
{
"*": ["editorconfig-checker"],
"*.{js,jsx,ts,tsx}": ["prettier --write", "eslint --fix"],
"*.{json,jsonc,yml,yaml}": ["prettier --write"],
"*.{md,mdx}": ["prettier --write", "markdownlint-cli2 --fix"]
}

View File

@ -1,11 +0,0 @@
{
"config": {
"extends": "markdownlint/style/prettier",
"relative-links": true,
"default": true,
"MD033": false
},
"globs": ["**/*.{md,mdx}"],
"ignores": ["**/node_modules"],
"customRules": ["markdownlint-rule-relative-links"]
}

2
.npmrc
View File

@ -1,2 +1,2 @@
package-lock=false
save-exact=true save-exact=true
provenance=true

View File

@ -1,3 +0,0 @@
{
"semi": false
}

View File

@ -1,19 +0,0 @@
{
"branches": ["master"],
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"preset": "conventionalcommits"
}
],
[
"@semantic-release/release-notes-generator",
{
"preset": "conventionalcommits"
}
],
"@semantic-release/npm",
"@semantic-release/github"
]
}

13
.swcrc
View File

@ -1,13 +0,0 @@
{
"sourceMaps": true,
"jsc": {
"parser": {
"syntax": "typescript",
"dynamicImport": true
},
"target": "esnext"
},
"module": {
"type": "es6"
}
}

View File

@ -1,8 +0,0 @@
{
"recommendations": [
"editorconfig.editorconfig",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"davidanson.vscode-markdownlint"
]
}

11
.vscode/settings.json vendored
View File

@ -1,11 +0,0 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.preferences.importModuleSpecifierEnding": "js",
"editor.defaultFormatter": "esbenp.prettier-vscode",
"prettier.configPath": ".prettierrc.json",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"eslint.options": { "ignorePath": ".gitignore" }
}

2
.yarnrc Normal file
View File

@ -0,0 +1,2 @@
install.no-lockfile true
save-exact true

9
CHANGELOG.md Normal file
View File

@ -0,0 +1,9 @@
# Changelog
## [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`
## [1.0.0](https://github.com/Thream/socketio-jwt/compare/v4.6.2...v1.0.0) (2020-12-29)
Initial release.

View File

@ -1,32 +0,0 @@
# 💡 Contributing
Thanks a lot for your interest in contributing to **Thream/socketio-jwt**! 🎉
## Code of Conduct
**Thream** has adopted the [Contributor Covenant](https://www.contributor-covenant.org/) as its Code of Conduct, and we expect project participants to adhere to it. Please read [the full text](./CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated.
## Open Development
All work on **Thream** happens directly on [GitHub](https://github.com/Thream). Both core team members and external contributors send pull requests which go through the same review process.
## Types of contributions
- Reporting a bug.
- Suggest a new feature idea.
- Correct spelling errors, improvements or additions to documentation files (README, CONTRIBUTING...).
- Improve structure/format/performance/refactor/tests of the code.
## Pull Requests
- **Please first discuss** the change you wish to make via [issue](https://github.com/Thream/socketio-jwt/issues) before making a change. It might avoid a waste of your time.
- Ensure your code respect linting.
- Make sure your **code passes the tests**.
If you're adding new features to **Thream/socketio-jwt**, please include tests.
## Commits
The commit message guidelines adheres to [Conventional Commits](https://www.conventionalcommits.org/) and [Semantic Versioning](https://semver.org/) for releases.

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) Auth0, Inc. <support@auth0.com> (<https://auth0.com/>) and Thream contributors Copyright (c) Auth0, Inc. <support@auth0.com> (http://auth0.com) and Thream contributors
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

129
README.md
View File

@ -1,42 +1,30 @@
<h1 align="center">Thream/socketio-jwt</h1> <h1 align="center"><a href="https://www.npmjs.com/package/@thream/socketio-jwt">Thream/socketio-jwt</a></h1>
<p align="center"> <p align="center">
<strong>Authenticate socket.io incoming connections with JWTs.</strong> <strong>Authenticate socket.io incoming connections with JWTs.</strong>
</p> </p>
<p align="center"> <p align="center">
<strong>⚠️ This project is not maintained anymore, you can still use the code as you wish and fork it to maintain it yourself.</strong> <a href="https://github.com/Thream/socketio-jwt/actions?query=workflow%3A%22Node.js+CI%22"><img src="https://github.com/Thream/socketio-jwt/workflows/Node.js%20CI/badge.svg" alt="Node.js CI" /></a>
</p> <a href="https://codecov.io/gh/Thream/socketio-jwt"><img src="https://codecov.io/gh/Thream/socketio-jwt/branch/develop/graph/badge.svg" alt="codecov" /></a>
<a href="https://dependabot.com/"><img src="https://badgen.net/github/dependabot/Thream/socketio-jwt?icon=dependabot" alt="Dependabot badge" /></a>
<p align="center">
<a href="./CONTRIBUTING.md"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" /></a>
<a href="./LICENSE"><img src="https://img.shields.io/badge/licence-MIT-blue.svg" alt="Licence MIT"/></a>
<a href="./CODE_OF_CONDUCT.md"><img src="https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg" alt="Contributor Covenant" /></a>
<br/>
<a href="https://github.com/Thream/socketio-jwt/actions/workflows/build.yml"><img src="https://github.com/Thream/socketio-jwt/actions/workflows/build.yml/badge.svg?branch=develop" /></a>
<a href="https://github.com/Thream/socketio-jwt/actions/workflows/lint.yml"><img src="https://github.com/Thream/socketio-jwt/actions/workflows/lint.yml/badge.svg?branch=develop" /></a>
<a href="https://github.com/Thream/socketio-jwt/actions/workflows/test.yml"><img src="https://github.com/Thream/socketio-jwt/actions/workflows/test.yml/badge.svg?branch=develop" /></a>
<br />
<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="https://github.com/semantic-release/semantic-release"><img src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg" alt="semantic-release" /></a>
<a href="https://www.npmjs.com/package/@thream/socketio-jwt"><img src="https://img.shields.io/npm/v/@thream/socketio-jwt.svg" alt="npm version"></a> <a href="https://www.npmjs.com/package/@thream/socketio-jwt"><img src="https://img.shields.io/npm/v/@thream/socketio-jwt.svg" alt="npm version"></a>
<a href="https://www.npmjs.com/package/ts-standard"><img alt="TypeScript Standard Style" src="https://camo.githubusercontent.com/f87caadb70f384c0361ec72ccf07714ef69a5c0a/68747470733a2f2f62616467656e2e6e65742f62616467652f636f64652532307374796c652f74732d7374616e646172642f626c75653f69636f6e3d74797065736372697074"/></a>
<a href="./LICENSE"><img src="https://img.shields.io/badge/licence-MIT-blue.svg" alt="Licence MIT"/></a>
<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>
</p> </p>
## 📜 About ## 📜 About
Authenticate socket.io incoming connections with JWTs. Authenticate socket.io incoming connections with JWTs.
This repository was originally forked from [auth0-socketio-jwt](https://github.com/auth0-community/auth0-socketio-jwt) and it is not intended to take any credit but to improve the code from now on. Compatible with `socket.io >= 3.0`.
## Prerequisites 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.
- [Node.js](https://nodejs.org/) >= 16.0.0
- [Socket.IO](https://socket.io/) >= 3.0.0
## 💾 Install ## 💾 Install
**Note:** It is a package that is recommended to use/install on both the client and server sides.
```sh ```sh
npm install --save @thream/socketio-jwt npm install --save @thream/socketio-jwt
``` ```
@ -46,111 +34,46 @@ npm install --save @thream/socketio-jwt
### Server side ### Server side
```ts ```ts
import { Server } from "socket.io" import { Server } from 'socket.io'
import { authorize } from "@thream/socketio-jwt" import { authorize } from '@thream/socketio-jwt'
const io = new Server(9000) const io = new Server(9000)
io.use( io.use(
authorize({ authorize({
secret: "your secret or public key", secret: 'your secret or public key'
}), })
) )
io.on("connection", async (socket) => { io.on('connection', async () => {
// jwt payload of the connected client
console.log(socket.decodedToken)
const clients = await io.sockets.allSockets() const clients = await io.sockets.allSockets()
if (clients != null) {
for (const clientId of clients) { for (const clientId of clients) {
const client = io.sockets.sockets.get(clientId) const client = io.sockets.sockets.get(clientId)
client?.emit("messages", { message: "Success!" }) client.emit('messages', { message: 'Success!' })
// we can access the jwt payload of each connected client // we can access the jwt payload of each connected client
console.log(client?.decodedToken) console.log(client.decodedToken)
}
} }
}) })
``` ```
### 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.getPublicKey()
},
}),
)
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...
})
```
### Server side with `onAuthentication` (example)
```ts
import { Server } from "socket.io"
import { authorize } from "@thream/socketio-jwt"
const io = new Server(9000)
io.use(
authorize({
secret: "your secret or public key",
onAuthentication: async (decodedToken) => {
// return the object that you want to add to the user property
// or throw an error if the token is unauthorized
},
}),
)
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...
// user object returned in onAuthentication
console.log(socket.user)
})
```
### `authorize` options
- `secret` is a string containing the secret for HMAC algorithms, or a function that should fetch the secret or public key as shown in the example with `jwks-rsa`.
- `algorithms` (default: `HS256`)
- `onAuthentication` is a function that will be called with the `decodedToken` as a parameter after the token is authenticated. Return a value to add to the `user` property in the socket object.
### Client side ### Client side
```ts ```ts
import { io } from "socket.io-client" import { io } from 'socket.io-client'
import { isUnauthorizedError } from "@thream/socketio-jwt/build/UnauthorizedError.js"
// Require Bearer Token // Require Bearer Tokens to be passed in as an Authorization Header
const socket = io("http://localhost:9000", { const socket = io('http://localhost:9000', {
auth: { token: `Bearer ${yourJWT}` }, extraHeaders: { Authorization: `Bearer ${yourJWT}` }
}) })
// Handling token expiration // Handling token expiration
socket.on("connect_error", (error) => { socket.on('connect_error', (error) => {
if (isUnauthorizedError(error)) { if (error.data.type === 'UnauthorizedError') {
console.log("User token has expired") console.log('User token has expired')
} }
}) })
// Listening to events // Listening to events
socket.on("messages", (data) => { socket.on('messages', (data) => {
console.log(data) console.log(data)
}) })
``` ```
@ -159,7 +82,7 @@ socket.on("messages", (data) => {
Anyone can help to improve the project, submit a Feature Request, a bug report or even correct a simple spelling mistake. Anyone can help to improve the project, submit a Feature Request, a bug report or even correct a simple spelling mistake.
The steps to contribute can be found in the [CONTRIBUTING.md](./CONTRIBUTING.md) file. The steps to contribute can be found in the [CONTRIBUTING.md](./.github/CONTRIBUTING.md) file.
## 📄 License ## 📄 License

1
commitlint.config.js Normal file
View File

@ -0,0 +1 @@
module.exports = { extends: ['@commitlint/config-conventional'] }

14300
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,93 +1,111 @@
{ {
"name": "@thream/socketio-jwt", "name": "@thream/socketio-jwt",
"version": "0.0.0-development", "version": "1.0.1",
"type": "module",
"public": true,
"description": "Authenticate socket.io incoming connections with JWTs.", "description": "Authenticate socket.io incoming connections with JWTs.",
"license": "MIT", "license": "MIT",
"main": "build/index.js", "main": "build/index.js",
"types": "build/index.d.ts", "types": "build/index.d.ts",
"files": [ "files": [
"build", "build"
"!**/*.test.js",
"!**/*.test.d.ts",
"!**/*.map"
], ],
"engines": { "engines": {
"node": ">=16.0.0", "node": ">=12"
"npm": ">=9.0.0"
},
"publishConfig": {
"access": "public",
"provenance": true
}, },
"keywords": [ "keywords": [
"socket", "socket",
"socket.io", "socket.io",
"jwt" "jwt"
], ],
"author": "Théo LUDWIG <contact@theoludwig.fr>", "author": "Divlo <contact@divlo.fr>",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/Thream/socketio-jwt" "url": "git+https://github.com/Thream/socketio-jwt"
}, },
"bugs": { "bugs": {
"url": "https://github.com/Thream/socketio-jwt/issues" "url": "https://github.com/Thream/socketio-jwt/issues"
}, },
"homepage": "https://github.com/Thream/socketio-jwt#readme", "homepage": "https://github.com/Thream/socketio-jwt#readme",
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
"pre-commit": "npm run lint"
}
},
"release-it": {
"git": {
"commitMessage": "chore(release): v${version}"
},
"github": {
"release": false
},
"npm": {
"publish": false
},
"hooks": {
"before:init": [
"npm run lint",
"npm run test"
]
},
"plugins": {
"@release-it/conventional-changelog": {
"preset": "angular",
"infile": "CHANGELOG.md"
}
}
},
"jest": {
"preset": "ts-jest",
"testEnvironment": "node",
"rootDir": "./src",
"collectCoverage": true,
"coverageDirectory": "../coverage/"
},
"ts-standard": {
"files": [
"./src/**/*.ts"
],
"envs": [
"node",
"jest"
]
},
"scripts": { "scripts": {
"build": "rimraf ./build && swc ./src --out-dir ./build", "build": "rimraf ./build && tsc",
"build:dev": "swc ./src --out-dir ./build --watch", "lint": "exit 0",
"build:typescript": "tsc", "format": "ts-standard --fix | snazzy",
"lint:commit": "commitlint", "release": "release-it",
"lint:editorconfig": "editorconfig-checker", "test": "jest",
"lint:markdown": "markdownlint-cli2", "test:watchAll": "jest --watchAll",
"lint:eslint": "eslint . --max-warnings 0 --report-unused-disable-directives --ignore-path .gitignore", "test:clearCache": "jest --clearCache"
"lint:prettier": "prettier . --check",
"lint:staged": "lint-staged",
"test": "cross-env NODE_ENV=test node --enable-source-maps --test build/",
"release": "semantic-release",
"postinstall": "husky install",
"prepublishOnly": "pinst --disable",
"postpublish": "pinst --enable"
}, },
"peerDependencies": { "peerDependencies": {
"socket.io": ">=3.0.0" "socket.io": "*"
}, },
"dependencies": { "dependencies": {
"jsonwebtoken": "9.0.2" "jsonwebtoken": "8.5.1"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "18.0.0", "@commitlint/cli": "11.0.0",
"@commitlint/config-conventional": "18.0.0", "@commitlint/config-conventional": "11.0.0",
"@swc/cli": "0.1.62", "@release-it/conventional-changelog": "2.0.0",
"@swc/core": "1.3.94", "@types/express": "4.17.9",
"@tsconfig/strictest": "2.0.2", "@types/jest": "26.0.19",
"@types/jsonwebtoken": "9.0.4", "@types/jsonwebtoken": "8.5.0",
"@types/node": "20.8.7", "@types/node": "14.14.16",
"@typescript-eslint/eslint-plugin": "6.9.0", "@types/server-destroy": "1.0.1",
"@typescript-eslint/parser": "6.9.0", "axios": "0.21.1",
"axios": "1.5.1", "express": "4.17.1",
"cross-env": "7.0.3", "husky": "4.3.6",
"editorconfig-checker": "5.1.1", "jest": "26.6.3",
"eslint": "8.52.0", "release-it": "14.2.2",
"eslint-config-conventions": "12.0.0", "rimraf": "3.0.2",
"eslint-config-prettier": "9.0.0", "server-destroy": "1.0.1",
"eslint-plugin-import": "2.29.0", "snazzy": "9.0.0",
"eslint-plugin-prettier": "5.0.1", "socket.io": "3.0.4",
"eslint-plugin-promise": "6.1.1", "socket.io-client": "3.0.4",
"eslint-plugin-unicorn": "48.0.1", "ts-jest": "26.4.4",
"fastify": "4.24.3", "ts-standard": "10.0.0",
"husky": "8.0.3", "typescript": "4.1.3"
"lint-staged": "15.0.2",
"markdownlint-cli2": "0.10.0",
"markdownlint-rule-relative-links": "2.1.0",
"pinst": "3.0.0",
"prettier": "3.0.3",
"rimraf": "5.0.5",
"semantic-release": "22.0.5",
"socket.io": "4.7.2",
"socket.io-client": "4.7.2",
"typescript": "5.2.2"
} }
} }

View File

@ -1,30 +1,16 @@
export class UnauthorizedError extends Error { export class UnauthorizedError extends Error {
public inner: { message: string } public inner: { message: string }
public data: { message: string; code: string; type: "UnauthorizedError" } public data: { message: string, code: string, type: 'UnauthorizedError' }
constructor (code: string, error: { message: string }) { constructor (code: string, error: { message: string }) {
super(error.message) super(error.message)
this.name = "UnauthorizedError" this.message = error.message
this.inner = error this.inner = error
this.data = { this.data = {
message: this.message, message: this.message,
code, code,
type: "UnauthorizedError", type: 'UnauthorizedError'
} }
Object.setPrototypeOf(this, UnauthorizedError.prototype) Object.setPrototypeOf(this, UnauthorizedError.prototype)
} }
} }
export const isUnauthorizedError = (
error: unknown,
): error is UnauthorizedError => {
return (
typeof error === "object" &&
error != null &&
"data" in error &&
typeof error.data === "object" &&
error.data != null &&
"type" in error.data &&
error.data.type === "UnauthorizedError"
)
}

View File

@ -1,340 +1,69 @@
import test from "node:test" import axios from 'axios'
import assert from "node:assert/strict" import { io } from 'socket.io-client'
import axios from "axios" import { fixtureStart, fixtureStop } from './fixture'
import type { Socket } from "socket.io-client"
import { io } from "socket.io-client"
import { isUnauthorizedError } from "../UnauthorizedError.js" describe('authorize', () => {
import type { Profile } from "./fixture/index.js" let token: string = ''
import {
API_URL,
fixtureStart,
fixtureStop,
getSocket,
basicProfile,
} from "./fixture/index.js"
export const api = axios.create({ beforeEach((done) => {
baseURL: API_URL, jest.setTimeout(15_000)
headers: { fixtureStart(async () => {
"Content-Type": "application/json", const response = await axios.post('http://localhost:9000/login')
},
})
const secretCallback = async (): Promise<string> => {
return "somesecret"
}
await test("authorize", async (t) => {
await t.test("with secret as string in options", async (t) => {
let token = ""
let socket: Socket | null = null
t.beforeEach(async () => {
await fixtureStart()
const response = await api.post("/login", {})
token = response.data.token token = response.data.token
}) done()
t.afterEach(async () => {
socket?.disconnect()
await fixtureStop()
})
await t.test("should emit error with no token provided", () => {
socket = io(API_URL)
socket.on("connect_error", async (error) => {
assert.strictEqual(isUnauthorizedError(error), true)
if (isUnauthorizedError(error)) {
assert.strictEqual(error.data.message, "no token provided")
assert.strictEqual(error.data.code, "credentials_required")
assert.ok(true)
} else {
assert.fail("should be unauthorized error")
}
})
socket.on("connect", async () => {
assert.fail("should not connect")
}) })
}) })
await t.test("should emit error with bad token format", () => { afterEach((done) => {
socket = io(API_URL, { fixtureStop(done)
auth: { token: "testing" },
}) })
socket.on("connect_error", async (error) => {
assert.strictEqual(isUnauthorizedError(error), true) it('should emit error with no token provided', (done) => {
if (isUnauthorizedError(error)) { const socket = io('http://localhost:9000')
assert.strictEqual( socket.on('connect_error', (err: any) => {
error.data.message, expect(err.data.message).toEqual('no token provided')
"Format is Authorization: Bearer [token]", expect(err.data.code).toEqual('credentials_required')
socket.close()
done()
})
})
it('should emit error with bad token format', (done) => {
const socket = io('http://localhost:9000', {
extraHeaders: { Authorization: 'testing' }
})
socket.on('connect_error', (err: any) => {
expect(err.data.message).toEqual(
'Format is Authorization: Bearer [token]'
) )
assert.strictEqual(error.data.code, "credentials_bad_format") expect(err.data.code).toEqual('credentials_bad_format')
assert.ok(true) socket.close()
} else { done()
assert.fail("should be unauthorized error")
}
})
socket.on("connect", async () => {
assert.fail("should not connect")
}) })
}) })
await t.test("should emit error with unauthorized handshake", () => { it('should emit error with unauthorized handshake', (done) => {
socket = io(API_URL, { const socket = io('http://localhost:9000', {
auth: { token: "Bearer testing" }, extraHeaders: { Authorization: 'Bearer testing' }
}) })
socket.on("connect_error", async (error) => { socket.on('connect_error', (err: any) => {
assert.strictEqual(isUnauthorizedError(error), true) expect(err.data.message).toEqual(
if (isUnauthorizedError(error)) { 'Unauthorized: Token is missing or invalid Bearer'
assert.strictEqual(
error.data.message,
"Unauthorized: Token is missing or invalid Bearer",
) )
assert.strictEqual(error.data.code, "invalid_token") expect(err.data.code).toEqual('invalid_token')
assert.ok(true) socket.close()
} else { done()
assert.fail("should be unauthorized error")
}
})
socket.on("connect", async () => {
assert.fail("should not connect")
}) })
}) })
await t.test("should connect the user", () => { it('should connect the user', (done) => {
socket = io(API_URL, { const socket = io('http://localhost:9000', {
auth: { token: `Bearer ${token}` }, extraHeaders: { Authorization: `Bearer ${token}` }
})
socket.on("connect", async () => {
assert.ok(true)
})
socket.on("connect_error", async (error) => {
assert.fail(error.message)
})
})
})
await t.test("with secret as callback in options", async (t) => {
let token = ""
let socket: Socket | null = null
t.beforeEach(async () => {
await fixtureStart({ secret: secretCallback })
const response = await api.post("/login", {})
token = response.data.token
})
t.afterEach(async () => {
socket?.disconnect()
await fixtureStop()
})
await t.test("should emit error with no token provided", () => {
socket = io(API_URL)
socket.on("connect_error", async (error) => {
assert.strictEqual(isUnauthorizedError(error), true)
if (isUnauthorizedError(error)) {
assert.strictEqual(error.data.message, "no token provided")
assert.strictEqual(error.data.code, "credentials_required")
assert.ok(true)
} else {
assert.fail("should be unauthorized error")
}
})
socket.on("connect", async () => {
assert.fail("should not connect")
})
})
await t.test("should emit error with bad token format", () => {
socket = io(API_URL, {
auth: { token: "testing" },
})
socket.on("connect_error", async (error) => {
assert.strictEqual(isUnauthorizedError(error), true)
if (isUnauthorizedError(error)) {
assert.strictEqual(
error.data.message,
"Format is Authorization: Bearer [token]",
)
assert.strictEqual(error.data.code, "credentials_bad_format")
assert.ok(true)
} else {
assert.fail("should be unauthorized error")
}
})
socket.on("connect", async () => {
assert.fail("should not connect")
})
})
await t.test("should emit error with unauthorized handshake", () => {
socket = io(API_URL, {
auth: { token: "Bearer testing" },
})
socket.on("connect_error", async (error) => {
assert.strictEqual(isUnauthorizedError(error), true)
if (isUnauthorizedError(error)) {
assert.strictEqual(
error.data.message,
"Unauthorized: Token is missing or invalid Bearer",
)
assert.strictEqual(error.data.code, "invalid_token")
assert.ok(true)
} else {
assert.fail("should be unauthorized error")
}
})
socket.on("connect", async () => {
assert.fail("should not connect")
})
})
await t.test("should connect the user", () => {
socket = io(API_URL, {
auth: { token: `Bearer ${token}` },
})
socket.on("connect", async () => {
assert.ok(true)
})
socket.on("connect_error", async (error) => {
assert.fail(error.message)
})
})
})
await t.test("with onAuthentication callback in options", async (t) => {
let token = ""
let wrongToken = ""
let socket: Socket | null = null
t.beforeEach(async () => {
await fixtureStart({
secret: secretCallback,
onAuthentication: (decodedToken: Profile) => {
if (!decodedToken.checkField) {
throw new Error("Check Field validation failed")
}
return {
email: decodedToken.email,
}
},
})
const response = await api.post("/login", {})
token = response.data.token
const responseWrong = await api.post("/login-wrong", {})
wrongToken = responseWrong.data.token
})
t.afterEach(async () => {
socket?.disconnect()
await fixtureStop()
})
await t.test("should emit error with no token provided", () => {
socket = io(API_URL)
socket.on("connect_error", async (error) => {
assert.strictEqual(isUnauthorizedError(error), true)
if (isUnauthorizedError(error)) {
assert.strictEqual(error.data.message, "no token provided")
assert.strictEqual(error.data.code, "credentials_required")
assert.ok(true)
} else {
assert.fail("should be unauthorized error")
}
})
socket.on("connect", async () => {
assert.fail("should not connect")
})
})
await t.test("should emit error with bad token format", () => {
socket = io(API_URL, {
auth: { token: "testing" },
})
socket.on("connect_error", async (error) => {
assert.strictEqual(isUnauthorizedError(error), true)
if (isUnauthorizedError(error)) {
assert.strictEqual(
error.data.message,
"Format is Authorization: Bearer [token]",
)
assert.strictEqual(error.data.code, "credentials_bad_format")
assert.ok(true)
} else {
assert.fail("should be unauthorized error")
}
})
socket.on("connect", async () => {
assert.fail("should not connect")
})
})
await t.test("should emit error with unauthorized handshake", () => {
socket = io(API_URL, {
auth: { token: "Bearer testing" },
})
socket.on("connect_error", async (error) => {
assert.strictEqual(isUnauthorizedError(error), true)
if (isUnauthorizedError(error)) {
assert.strictEqual(
error.data.message,
"Unauthorized: Token is missing or invalid Bearer",
)
assert.strictEqual(error.data.code, "invalid_token")
assert.ok(true)
} else {
assert.fail("should be unauthorized error")
}
})
socket.on("connect", async () => {
assert.fail("should not connect")
})
})
await t.test("should connect the user", () => {
socket = io(API_URL, {
auth: { token: `Bearer ${token}` },
})
socket.on("connect", async () => {
assert.ok(true)
})
socket.on("connect_error", async (error) => {
assert.fail(error.message)
})
})
await t.test("should contains user properties", () => {
const socketServer = getSocket()
socketServer?.on("connection", (client: any) => {
assert.strictEqual(client.user.email, basicProfile.email)
assert.ok(true)
})
socket = io(API_URL, {
auth: { token: `Bearer ${token}` },
})
socket.on("connect_error", async (error) => {
assert.fail(error.message)
})
})
await t.test("should emit error when user validation fails", () => {
socket = io(API_URL, {
auth: { token: `Bearer ${wrongToken}` },
})
socket.on("connect_error", async (error) => {
try {
assert.strictEqual(error.message, "Check Field validation failed")
assert.ok(true)
} catch {
assert.fail(error.message)
}
})
socket.on("connect", async () => {
assert.fail("should not connect")
}) })
socket.on('connect', () => {
socket.close()
done()
}) })
}) })
}) })

View File

@ -1,83 +1,48 @@
import jwt from "jsonwebtoken" import express from 'express'
import { Server as SocketIoServer } from "socket.io" import jwt from 'jsonwebtoken'
import type { FastifyInstance } from "fastify" import { Server as HttpServer } from 'http'
import fastify from "fastify" import { Server as HttpsServer } from 'https'
import { Server as SocketIoServer } from 'socket.io'
import enableDestroy from 'server-destroy'
import type { AuthorizeOptions } from "../../index.js" import { authorize } from '../../index'
import { authorize } from "../../index.js"
interface FastifyIo { interface Socket {
instance: SocketIoServer io: null | SocketIoServer
init: (httpServer: HttpServer | HttpsServer) => void
} }
declare module "fastify" { const socket: Socket = {
export interface FastifyInstance { io: null,
io: FastifyIo init (httpServer) {
socket.io = new SocketIoServer(httpServer)
} }
} }
export interface BasicProfile { let server: HttpServer | null = null
email: string
id: number export const fixtureStart = (done: any): void => {
const options = { secret: 'aaafoo super sercret' }
const app = express()
app.use(express.json())
app.post('/login', (_req, res) => {
const profile = {
email: 'john@doe.com',
id: 123
} }
const token = jwt.sign(profile, options.secret, { expiresIn: 60 * 60 * 5 })
export interface Profile extends BasicProfile { return res.json({ token })
checkField: boolean
}
export const PORT = 9000
export const API_URL = `http://localhost:${PORT}`
export const basicProfile: BasicProfile = {
email: "john@doe.com",
id: 123,
}
let application: FastifyInstance | null = null
export const fixtureStart = async (
options: AuthorizeOptions = { secret: "super secret" },
): Promise<void> => {
const profile: Profile = { ...basicProfile, checkField: true }
let keySecret = ""
if (typeof options.secret === "string") {
keySecret = options.secret
} else {
keySecret = await options.secret({
header: { alg: "HS256" },
payload: profile,
})
}
application = fastify()
application.post("/login", async (_request, reply) => {
const token = jwt.sign(profile, keySecret, {
expiresIn: 60 * 60 * 5,
})
reply.statusCode = 201
return { token }
})
application.post("/login-wrong", async (_request, reply) => {
profile.checkField = false
const token = jwt.sign(profile, keySecret, {
expiresIn: 60 * 60 * 5,
})
reply.statusCode = 201
return { token }
})
const instance = new SocketIoServer(application.server)
instance.use(authorize(options))
application.decorate("io", { instance })
application.addHook("onClose", (fastify) => {
fastify.io.instance.close()
})
await application.listen({
port: PORT,
}) })
server = app.listen(9000, done)
socket.init(server)
socket.io?.use(authorize(options))
enableDestroy(server)
} }
export const fixtureStop = async (): Promise<void> => { export const fixtureStop = (callback: Function): void => {
await application?.close() socket.io?.close()
} try {
server?.destroy()
export const getSocket = (): SocketIoServer | undefined => { } catch (err) {}
return application?.io.instance callback()
} }

View File

@ -1,91 +1,58 @@
import type { Algorithm } from "jsonwebtoken" import jwt from 'jsonwebtoken'
import jwt from "jsonwebtoken" import { Socket } from 'socket.io'
import type { Socket } from "socket.io"
import { UnauthorizedError } from "./UnauthorizedError.js" import { UnauthorizedError } from './UnauthorizedError'
declare module "socket.io" { interface ExtendedError extends Error {
interface Socket extends ExtendedSocket {} data?: any
}
interface ExtendedSocket {
encodedToken?: string
decodedToken?: any
user?: any
} }
type SocketIOMiddleware = ( type SocketIOMiddleware = (
socket: Socket, socket: Socket,
next: (error?: UnauthorizedError) => void, next: (err?: ExtendedError) => void
) => void ) => void
interface CompleteDecodedToken { interface AuthorizeOptions {
header: { secret: string
alg: Algorithm
[key: string]: any
}
payload: any
}
type SecretCallback = (
decodedToken: CompleteDecodedToken,
) => Promise<string> | string
export interface AuthorizeOptions {
secret: string | SecretCallback
algorithms?: Algorithm[]
onAuthentication?: (decodedToken: any) => Promise<any> | any
} }
export const authorize = (options: AuthorizeOptions): SocketIOMiddleware => { export const authorize = (options: AuthorizeOptions): SocketIOMiddleware => {
const { secret, algorithms = ["HS256"], onAuthentication } = options const { secret } = options
return async (socket, next) => { return (socket, next) => {
let encodedToken: string | null = null let token: string | null = null
const { token } = socket.handshake.auth const authorizationHeader = socket.request.headers.authorization
if (token != null) { if (authorizationHeader != null) {
const tokenSplitted = token.split(" ") const tokenSplitted = authorizationHeader.split(' ')
if (tokenSplitted.length !== 2 || tokenSplitted[0] !== "Bearer") { if (tokenSplitted.length !== 2 || tokenSplitted[0] !== 'Bearer') {
return next( return next(
new UnauthorizedError("credentials_bad_format", { new UnauthorizedError('credentials_bad_format', {
message: "Format is Authorization: Bearer [token]", message: 'Format is Authorization: Bearer [token]'
}), })
) )
} }
encodedToken = tokenSplitted[1] token = tokenSplitted[1]
} }
if (encodedToken == null) { if (token == null) {
return next( return next(
new UnauthorizedError("credentials_required", { new UnauthorizedError('credentials_required', {
message: "no token provided", message: 'no token provided'
}), })
) )
} }
socket.encodedToken = encodedToken // Store encoded JWT
let keySecret: string | null = null socket = Object.assign(socket, { encodedToken: token })
let decodedToken: any = null let payload: any
if (typeof secret === "string") {
keySecret = secret
} else {
const completeDecodedToken = jwt.decode(encodedToken, { complete: true })
keySecret = await secret(completeDecodedToken as CompleteDecodedToken)
}
try { try {
decodedToken = jwt.verify(encodedToken, keySecret, { algorithms }) payload = jwt.verify(token, secret)
} catch { } catch {
return next( return next(
new UnauthorizedError("invalid_token", { new UnauthorizedError('invalid_token', {
message: "Unauthorized: Token is missing or invalid Bearer", message: 'Unauthorized: Token is missing or invalid Bearer'
}), })
) )
} }
socket.decodedToken = decodedToken // Store decoded JWT
if (onAuthentication != null) { socket = Object.assign(socket, { decodedToken: payload })
try {
socket.user = await onAuthentication(decodedToken)
} catch (error: any) {
return next(error)
}
}
return next() return next()
} }
} }

View File

@ -1,2 +1 @@
export * from "./authorize.js" export * from './authorize'
export * from "./UnauthorizedError.js"

View File

@ -1,13 +1,23 @@
{ {
"extends": "@tsconfig/strictest/tsconfig.json",
"compilerOptions": { "compilerOptions": {
"target": "ESNext", "target": "ES2019",
"lib": ["ESNext"], "module": "commonjs",
"module": "NodeNext", "lib": ["ES2019"],
"moduleResolution": "NodeNext", "moduleResolution": "node",
"allowJs": false,
"checkJs": false,
"declaration": true,
"sourceMap": false,
"outDir": "./build", "outDir": "./build",
"rootDir": "./src", "rootDir": "./src",
"emitDeclarationOnly": true, "removeComments": false,
"declaration": true "noEmitOnError": true,
"importHelpers": false,
"strict": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"forceConsistentCasingInFileNames": true,
"incremental": false
} }
} }