Merge branch 'master' into patch-1
This commit is contained in:
commit
17d5669a3e
60
.all-contributorsrc
Normal file
60
.all-contributorsrc
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"imageSize": 100,
|
||||||
|
"commit": false,
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"login": "beardaway",
|
||||||
|
"name": "Conrad Sopala",
|
||||||
|
"avatar_url": "https://avatars3.githubusercontent.com/u/11062800?v=4",
|
||||||
|
"profile": "https://twitter.com/beardaway",
|
||||||
|
"contributions": [
|
||||||
|
"review",
|
||||||
|
"maintenance"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Annyv2",
|
||||||
|
"name": "Annyv2",
|
||||||
|
"avatar_url": "https://avatars3.githubusercontent.com/u/5016479?v=4",
|
||||||
|
"profile": "https://github.com/Annyv2",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Amialc",
|
||||||
|
"name": "Vladyslav Martynets",
|
||||||
|
"avatar_url": "https://avatars0.githubusercontent.com/u/1114365?v=4",
|
||||||
|
"profile": "https://github.com/Amialc",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "pose",
|
||||||
|
"name": "Alberto Pose",
|
||||||
|
"avatar_url": "https://avatars3.githubusercontent.com/u/419703?v=4",
|
||||||
|
"profile": "https://github.com/pose",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Root-Core",
|
||||||
|
"name": "Root-Core",
|
||||||
|
"avatar_url": "https://avatars2.githubusercontent.com/u/5329652?v=4",
|
||||||
|
"profile": "https://github.com/Root-Core",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contributorsPerLine": 7,
|
||||||
|
"projectName": "auth0-socketio-jwt",
|
||||||
|
"projectOwner": "auth0-community",
|
||||||
|
"repoType": "github",
|
||||||
|
"repoHost": "https://github.com"
|
||||||
|
}
|
36
ISSUE_TEMPLATE.md
Normal file
36
ISSUE_TEMPLATE.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Issue Report
|
||||||
|
|
||||||
|
If you are reporting a bug, please fill the sections below (if they are applicable), otherwise feel free to delete those that don't apply. Thank you! 🙏🏼
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
What are you reporting?
|
||||||
|
|
||||||
|
### Expected behaviour
|
||||||
|
|
||||||
|
Tell us what you think should happen.
|
||||||
|
|
||||||
|
### Actual behaviour
|
||||||
|
|
||||||
|
Tell us what actually happens.
|
||||||
|
|
||||||
|
### Steps to reproduce the problem
|
||||||
|
|
||||||
|
Tell us what we should do to reproduce the issue.
|
||||||
|
|
||||||
|
### Language / Framework Versions
|
||||||
|
|
||||||
|
1. **Language used:**
|
||||||
|
2. **Framework used:**
|
||||||
|
|
||||||
|
### Testing environment
|
||||||
|
|
||||||
|
1. **Operating system:**
|
||||||
|
2. **Browser version:**
|
||||||
|
|
||||||
|
### Screenshots
|
||||||
|
|
||||||
|
Feel free to insert here any screenshots that you consider helpful in solving your issue.
|
||||||
|
|
||||||
|
|
||||||
|
**Filling this, you're helping yourself and repo maintainers in solving your issues quicker! Teamwork makes the dreamwork 🤜🏼🤛🏻**
|
32
PULL_REQUEST_TEMPLATE.md
Normal file
32
PULL_REQUEST_TEMPLATE.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Pull Request Report
|
||||||
|
|
||||||
|
Please include a summary of the change you made with relevant motivation and context why such change has been made. Filling sections below will allow us to get your changes reviewed and merged easier. If you feel like certain section is not applicable, feel free to delete it. Thanks for co-operation! 🙏🏼
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
Tell us what you changed, why you did it and what additional value it will bring.
|
||||||
|
|
||||||
|
### Type of change
|
||||||
|
|
||||||
|
- [ ] Bug fix (fix to an issue)
|
||||||
|
- [ ] New feature (changes to functionality)
|
||||||
|
- [ ] Big change (fix or feature that would cause existing functionality to work as expected)
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
Please describe the tests that you ran to verify your changes. Provide any instructions that will allow us to reproduce it. Please also list any relevant details for your test configuration.
|
||||||
|
|
||||||
|
**Test Configuration**
|
||||||
|
|
||||||
|
* Framework version:
|
||||||
|
* Language version:
|
||||||
|
* Browser version:
|
||||||
|
|
||||||
|
### Additional info
|
||||||
|
|
||||||
|
- [ ] I have performed a self-review of my own code
|
||||||
|
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||||
|
- [ ] I have made corresponding changes to the documentation
|
||||||
|
- [ ] My changes generate no new warnings and errors
|
||||||
|
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||||
|
- [ ] New and existing unit tests pass locally with my changes
|
135
README.md
135
README.md
@ -1,14 +1,43 @@
|
|||||||
[![Build Status](https://travis-ci.org/auth0/socketio-jwt.svg)](https://travis-ci.org/auth0/socketio-jwt)
|
# socketio-jwt
|
||||||
|
|
||||||
|
[![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors)
|
||||||
|
<img src="https://img.shields.io/badge/community-driven-brightgreen.svg"/> <br>
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
Thanks goes to these wonderful people who contribute(d) or maintain(ed) this repo ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
||||||
|
|
||||||
|
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
||||||
|
<!-- prettier-ignore -->
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://twitter.com/beardaway"><img src="https://avatars3.githubusercontent.com/u/11062800?v=4" width="100px;" alt="Conrad Sopala"/><br /><sub><b>Conrad Sopala</b></sub></a><br /><a href="#review-beardaway" title="Reviewed Pull Requests">👀</a> <a href="#maintenance-beardaway" title="Maintenance">🚧</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Annyv2"><img src="https://avatars3.githubusercontent.com/u/5016479?v=4" width="100px;" alt="Annyv2"/><br /><sub><b>Annyv2</b></sub></a><br /><a href="https://github.com/auth0-community/auth0-socketio-jwt/commits?author=Annyv2" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Amialc"><img src="https://avatars0.githubusercontent.com/u/1114365?v=4" width="100px;" alt="Vladyslav Martynets"/><br /><sub><b>Vladyslav Martynets</b></sub></a><br /><a href="https://github.com/auth0-community/auth0-socketio-jwt/commits?author=Amialc" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/pose"><img src="https://avatars3.githubusercontent.com/u/419703?v=4" width="100px;" alt="Alberto Pose"/><br /><sub><b>Alberto Pose</b></sub></a><br /><a href="https://github.com/auth0-community/auth0-socketio-jwt/commits?author=pose" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/Root-Core"><img src="https://avatars2.githubusercontent.com/u/5329652?v=4" width="100px;" alt="Root-Core"/><br /><sub><b>Root-Core</b></sub></a><br /><a href="https://github.com/auth0-community/auth0-socketio-jwt/commits?author=Root-Core" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||||
|
|
||||||
|
## Intro
|
||||||
|
|
||||||
Authenticate socket.io incoming connections with JWTs. This is useful if you are build a single page application and you are not using cookies as explained in this blog post: [Cookies vs Tokens. Getting auth right with Angular.JS](http://blog.auth0.com/2014/01/07/angularjs-authentication-with-cookies-vs-token/).
|
Authenticate socket.io incoming connections with JWTs. This is useful if you are build a single page application and you are not using cookies as explained in this blog post: [Cookies vs Tokens. Getting auth right with Angular.JS](http://blog.auth0.com/2014/01/07/angularjs-authentication-with-cookies-vs-token/).
|
||||||
|
|
||||||
## Installation
|
This repo is supported and maintained by Community Developers, not Auth0. For more information about different support levels check https://auth0.com/docs/support/matrix .
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
Chrome extensions are packaged as `.crx` files for distribution but may be loaded "unpacked" for development. For more information on how to load an unpacked extension, see the [Chrome extension docs](https://developer.chrome.com/extensions/getstarted#unpacked).
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
```
|
```
|
||||||
npm install socketio-jwt
|
npm install socketio-jwt
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example usage
|
## Usage
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// set authorization for socket.io
|
// set authorization for socket.io
|
||||||
@ -24,7 +53,7 @@ io.sockets
|
|||||||
|
|
||||||
**Note:** If you are using a base64-encoded secret (e.g. your Auth0 secret key), you need to convert it to a Buffer: `Buffer('your secret key', 'base64')`
|
**Note:** If you are using a base64-encoded secret (e.g. your Auth0 secret key), you need to convert it to a Buffer: `Buffer('your secret key', 'base64')`
|
||||||
|
|
||||||
__Client side__:
|
**Client side**
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var socket = io.connect('http://localhost:9000');
|
var socket = io.connect('http://localhost:9000');
|
||||||
@ -41,9 +70,9 @@ socket.on('connect', function () {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## One roundtrip
|
### One roundtrip
|
||||||
|
|
||||||
The previous approach uses a second roundtrip to send the jwt, there is a way you can authenticate on the handshake by sending the JWT as a query string, the caveat is that intermediary HTTP servers can log the url.
|
The previous approach uses a second roundtrip to send the jwt. There is a way you can authenticate on the handshake by sending the JWT as a query string, the caveat is that intermediary HTTP servers can log the url.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var io = require("socket.io")(server);
|
var io = require("socket.io")(server);
|
||||||
@ -54,14 +83,12 @@ io.set('authorization', socketioJwt.authorize({
|
|||||||
secret: 'your secret or public key',
|
secret: 'your secret or public key',
|
||||||
handshake: true
|
handshake: true
|
||||||
}));
|
}));
|
||||||
//////////////////////////////
|
|
||||||
|
|
||||||
//// With socket.io >= 1.0 ////
|
//// With socket.io >= 1.0 ////
|
||||||
io.use(socketioJwt.authorize({
|
io.use(socketioJwt.authorize({
|
||||||
secret: 'your secret or public key',
|
secret: 'your secret or public key',
|
||||||
handshake: true
|
handshake: true
|
||||||
}));
|
}));
|
||||||
///////////////////////////////
|
|
||||||
|
|
||||||
io.on('connection', function (socket) {
|
io.on('connection', function (socket) {
|
||||||
// in socket.io < 1.0
|
// in socket.io < 1.0
|
||||||
@ -74,7 +101,7 @@ io.on('connection', function (socket) {
|
|||||||
|
|
||||||
For more validation options see [auth0/jsonwebtoken](https://github.com/auth0/node-jsonwebtoken).
|
For more validation options see [auth0/jsonwebtoken](https://github.com/auth0/node-jsonwebtoken).
|
||||||
|
|
||||||
__Client side__:
|
**Client side**
|
||||||
|
|
||||||
Append the jwt token using query string:
|
Append the jwt token using query string:
|
||||||
|
|
||||||
@ -84,9 +111,9 @@ var socket = io.connect('http://localhost:9000', {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Handling token expiration
|
### Handling token expiration
|
||||||
|
|
||||||
__Server side__:
|
**Server side**
|
||||||
|
|
||||||
When you sign the token with an expiration time:
|
When you sign the token with an expiration time:
|
||||||
|
|
||||||
@ -94,9 +121,9 @@ When you sign the token with an expiration time:
|
|||||||
var token = jwt.sign(user_profile, jwt_secret, {expiresInMinutes: 60});
|
var token = jwt.sign(user_profile, jwt_secret, {expiresInMinutes: 60});
|
||||||
```
|
```
|
||||||
|
|
||||||
Your client-side code should handle it as below.
|
Your client-side code should handle it as below:
|
||||||
|
|
||||||
__Client side__:
|
**Client side**
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
socket.on("unauthorized", function(error) {
|
socket.on("unauthorized", function(error) {
|
||||||
@ -107,15 +134,15 @@ socket.on("unauthorized", function(error) {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Handling invalid token
|
### Handling invalid token
|
||||||
|
|
||||||
Token sent by client is invalid.
|
Token sent by client is invalid.
|
||||||
|
|
||||||
__Server side__:
|
**Server side**:
|
||||||
|
|
||||||
No further configuration needed.
|
No further configuration needed.
|
||||||
|
|
||||||
__Client side__:
|
**Client side**
|
||||||
|
|
||||||
Add a callback client-side to execute socket disconnect server-side.
|
Add a callback client-side to execute socket disconnect server-side.
|
||||||
|
|
||||||
@ -129,7 +156,7 @@ socket.on("unauthorized", function(error, callback) {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
__Server side__:
|
**Server side**
|
||||||
|
|
||||||
To disconnect socket server-side without client-side callback:
|
To disconnect socket server-side without client-side callback:
|
||||||
|
|
||||||
@ -141,11 +168,11 @@ io.sockets.on('connection', socketioJwt.authorize({
|
|||||||
}))
|
}))
|
||||||
```
|
```
|
||||||
|
|
||||||
__Client side__:
|
**Client side**
|
||||||
|
|
||||||
Nothing needs to be changed client-side if callback is false.
|
Nothing needs to be changed client-side if callback is false.
|
||||||
|
|
||||||
__Server side__:
|
**Server side**
|
||||||
|
|
||||||
To disconnect socket server-side while giving client-side 15 seconds to execute callback:
|
To disconnect socket server-side while giving client-side 15 seconds to execute callback:
|
||||||
|
|
||||||
@ -157,9 +184,9 @@ io.sockets.on('connection', socketioJwt.authorize({
|
|||||||
}))
|
}))
|
||||||
```
|
```
|
||||||
|
|
||||||
Your client-side code should handle it as below.
|
Your client-side code should handle it as below:
|
||||||
|
|
||||||
__Client side__:
|
**Client side**
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
socket.on("unauthorized", function(error, callback) {
|
socket.on("unauthorized", function(error, callback) {
|
||||||
@ -171,13 +198,14 @@ socket.on("unauthorized", function(error, callback) {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Getting the secret dynamically
|
### Getting the secret dynamically
|
||||||
You can pass a function instead of an string when configuring secret.
|
|
||||||
|
You can pass a function instead of a string when configuring secret.
|
||||||
This function receives the request, the decoded token and a callback. This
|
This function receives the request, the decoded token and a callback. This
|
||||||
way, you are allowed to use a different secret based on the request and / or
|
way, you are allowed to use a different secret based on the request and / or
|
||||||
the provided token.
|
the provided token.
|
||||||
|
|
||||||
__Server side__:
|
**Server side**
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var SECRETS = {
|
var SECRETS = {
|
||||||
@ -187,33 +215,68 @@ var SECRETS = {
|
|||||||
|
|
||||||
io.use(socketioJwt.authorize({
|
io.use(socketioJwt.authorize({
|
||||||
secret: function(request, decodedToken, callback) {
|
secret: function(request, decodedToken, callback) {
|
||||||
// SECRETS[decodedToken.userId] will be used a a secret or
|
// SECRETS[decodedToken.userId] will be used as a secret or
|
||||||
// public key for connection user.
|
// public key for connection user.
|
||||||
|
|
||||||
callback(null, SECRETS[decodedToken.userId]);
|
callback(null, SECRETS[decodedToken.userId]);
|
||||||
},
|
},
|
||||||
handshake: false
|
handshake: false
|
||||||
}));
|
}));
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
You are always welcome to open an issue or provide a pull-request!
|
Feel like contributing to this repo? We're glad to hear that! Before you start contributing please visit our [Contributing Guideline](https://github.com/auth0-community/getting-started/blob/master/CONTRIBUTION.md).
|
||||||
|
|
||||||
Also check out the unit tests:
|
Here you can also find the [PR template](https://github.com/auth0-community/socketio-jwt/blob/master/PULL_REQUEST_TEMPLATE.md) to fill once creating a PR. It will automatically appear once you open a pull request.
|
||||||
```bash
|
|
||||||
npm test
|
|
||||||
```
|
|
||||||
|
|
||||||
## Issue Reporting
|
## Issues Reporting
|
||||||
|
|
||||||
If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.
|
Spotted a bug or any other kind of issue? We're just humans and we're always waiting for constructive feedback! Check our section on how to [report issues](https://github.com/auth0-community/getting-started/blob/master/CONTRIBUTION.md#issues)!
|
||||||
|
|
||||||
## Author
|
Here you can also find the [Issue template](https://github.com/auth0-community/socketio-jwt/blob/master/ISSUE_TEMPLATE.md) to fill once opening a new issue. It will automatically appear once you create an issue.
|
||||||
|
|
||||||
[Auth0](auth0.com)
|
## Repo Community
|
||||||
|
|
||||||
|
Feel like PRs and issues are not enough? Want to dive into further discussion about the tool? We created topics for each Auth0 Community repo so that you can join discussion on stack available on our repos. Here it is for this one: [socketio-jwt](https://community.auth0.com/t/auth0-community-oss-socketio-jwt/20024)
|
||||||
|
|
||||||
|
<a href="https://community.auth0.com/">
|
||||||
|
<img src="/assets/join_auth0_community_badge.png"/>
|
||||||
|
</a>
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info.
|
This project is licensed under the MIT license. See the [LICENSE](https://github.com/auth0-community/socketio-jwt/blob/master/LICENSE) file for more info.
|
||||||
|
|
||||||
|
## What is Auth0?
|
||||||
|
|
||||||
|
Auth0 helps you to:
|
||||||
|
|
||||||
|
* Add authentication with [multiple authentication sources](https://docs.auth0.com/identityproviders), either social like
|
||||||
|
* Google
|
||||||
|
* Facebook
|
||||||
|
* Microsoft
|
||||||
|
* Linkedin
|
||||||
|
* GitHub
|
||||||
|
* Twitter
|
||||||
|
* Box
|
||||||
|
* Salesforce
|
||||||
|
* etc.
|
||||||
|
|
||||||
|
**or** enterprise identity systems like:
|
||||||
|
* Windows Azure AD
|
||||||
|
* Google Apps
|
||||||
|
* Active Directory
|
||||||
|
* ADFS
|
||||||
|
* Any SAML Identity Provider
|
||||||
|
|
||||||
|
* Add authentication through more traditional [username/password databases](https://docs.auth0.com/mysql-connection-tutorial)
|
||||||
|
* Add support for [linking different user accounts](https://docs.auth0.com/link-accounts) with the same user
|
||||||
|
* Support for generating signed [JSON Web Tokens](https://docs.auth0.com/jwt) to call your APIs and create user identity flow securely
|
||||||
|
* Analytics of how, when and where users are logging in
|
||||||
|
* Pull data from other sources and add it to user profile, through [JavaScript rules](https://docs.auth0.com/rules)
|
||||||
|
|
||||||
|
## Create a free Auth0 account
|
||||||
|
|
||||||
|
* Go to [Auth0 website](https://auth0.com/signup)
|
||||||
|
* Hit the **SIGN UP** button in the upper-right corner
|
||||||
|
BIN
assets/join_auth0_community_badge.png
Normal file
BIN
assets/join_auth0_community_badge.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
3
example/README.md
Normal file
3
example/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Deprecation Notice
|
||||||
|
|
||||||
|
This sample has been deprecated. Please see the [auth0-samples](https://github.com/auth0-samples) org for the latest Auth0 samples.
|
@ -1,30 +0,0 @@
|
|||||||
# Auth0 + Socket.io
|
|
||||||
|
|
||||||
This is the seed project you need to use if you're going to create a Socket.io single page app that will use Auth0.
|
|
||||||
|
|
||||||
### Configure your Auth0 credentials
|
|
||||||
|
|
||||||
First, you need to set the ClientSecret, ClientId and Domain for your Auth0 app as environment variables with the following names respectively: `AUTH0_CLIENT_SECRET`, `AUTH0_CLIENT_ID` and `AUTH0_DOMAIN`. You can find this information in your Auth0 Dashboard.
|
|
||||||
|
|
||||||
So, create a file named `.env` in the directory and set the values like the following:
|
|
||||||
|
|
||||||
````bash
|
|
||||||
# .env file
|
|
||||||
AUTH0_CLIENT_SECRET=myCoolSecret
|
|
||||||
AUTH0_CLIENT_ID=myCoolClientId
|
|
||||||
AUTH0_DOMAIN=myCoolDomain
|
|
||||||
````
|
|
||||||
|
|
||||||
### Set up the Allowed Origin (CORS) in Auth0
|
|
||||||
|
|
||||||
Then, you need to put `http://localhost:3001` as an Allowed Origin (CORS) in the Application Settings on your Auth0.com dashboard.
|
|
||||||
|
|
||||||
### Running the example
|
|
||||||
|
|
||||||
In order to run the example, you need to have `node` installed.
|
|
||||||
|
|
||||||
1. run `npm install`
|
|
||||||
1. run `node index.js` in the directory of this project.
|
|
||||||
|
|
||||||
|
|
||||||
Go to [http://localhost:3001](http://localhost:3001) and you'll see the app running :).
|
|
@ -1,41 +0,0 @@
|
|||||||
var express = require('express');
|
|
||||||
var app = express();
|
|
||||||
var http = require('http').Server(app);
|
|
||||||
var io = require('socket.io')(http);
|
|
||||||
var socketioJwt = require('socketio-jwt');
|
|
||||||
var dotenv = require('dotenv');
|
|
||||||
|
|
||||||
dotenv.load();
|
|
||||||
|
|
||||||
var env = {
|
|
||||||
AUTH0_CLIENT_ID: process.env.AUTH0_CLIENT_ID,
|
|
||||||
AUTH0_DOMAIN: process.env.AUTH0_DOMAIN
|
|
||||||
};
|
|
||||||
var port = process.env.PORT || 3001;
|
|
||||||
|
|
||||||
app.set('views', __dirname + '/views');
|
|
||||||
app.set('view engine', 'pug');
|
|
||||||
|
|
||||||
io
|
|
||||||
.on('connection', socketioJwt.authorize({
|
|
||||||
secret: Buffer(JSON.stringify(process.env.AUTH0_CLIENT_SECRET), 'base64'),
|
|
||||||
timeout: 15000 // 15 seconds to send the authentication message
|
|
||||||
}))
|
|
||||||
.on('authenticated', function(socket){
|
|
||||||
console.log('connected & authenticated: ' + JSON.stringify(socket.decoded_token));
|
|
||||||
socket.on('chat message', function(msg){
|
|
||||||
debugger;
|
|
||||||
io.emit('chat message', msg);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use(express.static(__dirname + '/public'));
|
|
||||||
|
|
||||||
app.get('/', function (req, res) {
|
|
||||||
res.render('index', { env: env });
|
|
||||||
});
|
|
||||||
|
|
||||||
http.listen(port, function(){
|
|
||||||
console.log('listening on *:' + port);
|
|
||||||
});
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "socket-auth0-chat-example",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "Auth0 + Socket.io seed",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git://github.com/auth0/socketio-jwt.git"
|
|
||||||
},
|
|
||||||
"author": "Auth0",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"dotenv": "^2.0.0",
|
|
||||||
"express": "^4.13.4",
|
|
||||||
"pug": "^2.0.0-beta2",
|
|
||||||
"socket.io": "^1.4.6",
|
|
||||||
"socketio-jwt": "^4.3.4"
|
|
||||||
},
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/auth0/socketio-jwt/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/auth0/socketio-jwt#readme",
|
|
||||||
"devDependencies": {},
|
|
||||||
"scripts": {
|
|
||||||
"start": "node index.js",
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
||||||
body { font: 13px Helvetica, Arial; }
|
|
||||||
#chatForm { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
|
|
||||||
#chatForm input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
|
|
||||||
#chatForm button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
|
|
||||||
#messages { list-style-type: none; margin: 0; padding: 0; }
|
|
||||||
#messages li { padding: 5px 10px; }
|
|
||||||
#messages li:nth-child(odd) { background: #eee; }
|
|
||||||
#login { width: 100%; padding: 10px }
|
|
||||||
#login button { width: 10%; padding: 8px; border: none; background: rgb(130, 255, 130);}
|
|
@ -1,78 +0,0 @@
|
|||||||
extends layout
|
|
||||||
|
|
||||||
block content
|
|
||||||
script(src="https://cdn.auth0.com/js/lock/10.0/lock.min.js")
|
|
||||||
script(src="/socket.io/socket.io.js")
|
|
||||||
script(src="http://code.jquery.com/jquery-1.12.4.js")
|
|
||||||
|
|
||||||
|
|
||||||
div#login
|
|
||||||
button.btn Login
|
|
||||||
div#chat
|
|
||||||
ul#messages
|
|
||||||
form(id="chatForm" action="")
|
|
||||||
input(id="m" autocomplete="off")
|
|
||||||
button.btn Send
|
|
||||||
|
|
||||||
script.
|
|
||||||
var userProfile;
|
|
||||||
var userToken;
|
|
||||||
var lock = new Auth0Lock('#{env.AUTH0_CLIENT_ID}', '#{env.AUTH0_DOMAIN}');
|
|
||||||
var id_token = localStorage.getItem('id_token');
|
|
||||||
$('#chat').hide();
|
|
||||||
$('#login button').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
lock.show();
|
|
||||||
});
|
|
||||||
|
|
||||||
lock.on('authenticated', function(authResult) {
|
|
||||||
lock.getProfile(authResult.idToken, function(error, profile) {
|
|
||||||
if (error) {
|
|
||||||
// Handle error
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log('connected and authenticated');
|
|
||||||
localStorage.setItem('id_token', authResult.idToken);
|
|
||||||
localStorage.setItem('profile', JSON.stringify(profile));
|
|
||||||
userProfile = profile;
|
|
||||||
id_token = authResult.idToken;
|
|
||||||
openChat();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (id_token) {
|
|
||||||
lock.getProfile(id_token, function (err, profile) {
|
|
||||||
if (err) {
|
|
||||||
return alert('There was an error getting the profile: ' + err.message);
|
|
||||||
}
|
|
||||||
userProfile = profile;
|
|
||||||
openChat();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function openChat() {
|
|
||||||
var socket = io();
|
|
||||||
socket
|
|
||||||
.on('connect', function (msg) {
|
|
||||||
console.log("connected");
|
|
||||||
socket.emit('authenticate', {token: id_token}); // send the jwt
|
|
||||||
})
|
|
||||||
.on('authenticated', function () {
|
|
||||||
//Do
|
|
||||||
$('#login').hide();
|
|
||||||
$('#chat').show();
|
|
||||||
$('form').submit(function (event) {
|
|
||||||
socket.emit('chat message', $('#m').val());
|
|
||||||
$('#m').val('');
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.on('unauthorized', function(msg){
|
|
||||||
console.log("unauthorized: " + JSON.stringify(msg.data));
|
|
||||||
throw new Error(msg.data.type);
|
|
||||||
})
|
|
||||||
.on('chat message', function (msg) {
|
|
||||||
console.log("msg");
|
|
||||||
$('#messages').append($('<li>').text(msg));
|
|
||||||
});
|
|
||||||
};
|
|
@ -1,7 +0,0 @@
|
|||||||
doctype html
|
|
||||||
html
|
|
||||||
head
|
|
||||||
|
|
||||||
link(rel='stylesheet', href='/stylesheets/style.css')
|
|
||||||
body
|
|
||||||
block content
|
|
41
lib/index.js
41
lib/index.js
@ -57,10 +57,15 @@ function noQsMethod(options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if(!data || typeof data.token !== "string") {
|
var token = options.cookie ? socket.request.cookies[options.cookie] : (data ? data.token : undefined);
|
||||||
|
|
||||||
|
if(!token || typeof token !== "string") {
|
||||||
return onError({message: 'invalid token datatype'}, 'invalid_token');
|
return onError({message: 'invalid token datatype'}, 'invalid_token');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store encoded JWT
|
||||||
|
socket[options.encodedPropertyName] = data.token;
|
||||||
|
|
||||||
var onJwtVerificationReady = function(err, decoded) {
|
var onJwtVerificationReady = function(err, decoded) {
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -96,31 +101,31 @@ function noQsMethod(options) {
|
|||||||
return onError(err, 'invalid_secret');
|
return onError(err, 'invalid_secret');
|
||||||
}
|
}
|
||||||
|
|
||||||
jwt.verify(data.token, secret, options, onJwtVerificationReady);
|
jwt.verify(token, secret, options, onJwtVerificationReady);
|
||||||
};
|
};
|
||||||
|
|
||||||
getSecret(socket.request, options.secret, data.token, onSecretReady);
|
getSecret(socket.request, options.secret, token, onSecretReady);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function authorize(options, onConnection) {
|
function authorize(options, onConnection) {
|
||||||
options = xtend({ decodedPropertyName: 'decoded_token' }, options);
|
options = xtend({ decodedPropertyName: 'decoded_token', encodedPropertyName: 'encoded_token' }, options);
|
||||||
|
|
||||||
if (!options.handshake) {
|
if (!options.handshake) {
|
||||||
return noQsMethod(options);
|
return noQsMethod(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
var defaults = {
|
var defaults = {
|
||||||
success: function(data, accept){
|
success: function(socket, accept){
|
||||||
if (data.request) {
|
if (socket.request) {
|
||||||
accept();
|
accept();
|
||||||
} else {
|
} else {
|
||||||
accept(null, true);
|
accept(null, true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fail: function(error, data, accept){
|
fail: function(error, socket, accept){
|
||||||
if (data.request) {
|
if (socket.request) {
|
||||||
accept(error);
|
accept(error);
|
||||||
} else {
|
} else {
|
||||||
accept(null, false);
|
accept(null, false);
|
||||||
@ -130,10 +135,10 @@ function authorize(options, onConnection) {
|
|||||||
|
|
||||||
var auth = xtend(defaults, options);
|
var auth = xtend(defaults, options);
|
||||||
|
|
||||||
return function(data, accept){
|
return function(socket, accept){
|
||||||
var token, error;
|
var token, error;
|
||||||
var req = data.request || data;
|
|
||||||
var handshake = data.handshake;
|
var handshake = data.handshake;
|
||||||
|
var req = socket.request || socket;
|
||||||
var authorization_header = (req.headers || {}).authorization;
|
var authorization_header = (req.headers || {}).authorization;
|
||||||
|
|
||||||
if (authorization_header) {
|
if (authorization_header) {
|
||||||
@ -149,7 +154,7 @@ function authorize(options, onConnection) {
|
|||||||
error = new UnauthorizedError('credentials_bad_format', {
|
error = new UnauthorizedError('credentials_bad_format', {
|
||||||
message: 'Format is Authorization: Bearer [token]'
|
message: 'Format is Authorization: Bearer [token]'
|
||||||
});
|
});
|
||||||
return auth.fail(error, data, accept);
|
return auth.fail(error, socket, accept);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,25 +173,28 @@ function authorize(options, onConnection) {
|
|||||||
error = new UnauthorizedError('credentials_required', {
|
error = new UnauthorizedError('credentials_required', {
|
||||||
message: 'No Authorization header was found'
|
message: 'No Authorization header was found'
|
||||||
});
|
});
|
||||||
return auth.fail(error, data, accept);
|
return auth.fail(error, socket, accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store encoded JWT
|
||||||
|
socket[options.encodedPropertyName] = token;
|
||||||
|
|
||||||
var onJwtVerificationReady = function(err, decoded) {
|
var onJwtVerificationReady = function(err, decoded) {
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
error = new UnauthorizedError(err.code || 'invalid_token', err);
|
error = new UnauthorizedError(err.code || 'invalid_token', err);
|
||||||
return auth.fail(error, data, accept);
|
return auth.fail(error, socket, accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
data[options.decodedPropertyName] = decoded;
|
socket[options.decodedPropertyName] = decoded;
|
||||||
|
|
||||||
return auth.success(data, accept);
|
return auth.success(socket, accept);
|
||||||
};
|
};
|
||||||
|
|
||||||
var onSecretReady = function(err, secret) {
|
var onSecretReady = function(err, secret) {
|
||||||
if (err) {
|
if (err) {
|
||||||
error = new UnauthorizedError(err.code || 'invalid_secret', err);
|
error = new UnauthorizedError(err.code || 'invalid_secret', err);
|
||||||
return auth.fail(error, data, accept);
|
return auth.fail(error, socket, accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
jwt.verify(token, secret, options, onJwtVerificationReady);
|
jwt.verify(token, secret, options, onJwtVerificationReady);
|
||||||
@ -225,3 +233,4 @@ function getSecret(request, secret, token, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
exports.authorize = authorize;
|
exports.authorize = authorize;
|
||||||
|
exports.UnauthorizedError = UnauthorizedError;
|
||||||
|
23
package.json
23
package.json
@ -3,6 +3,7 @@
|
|||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"description": "authenticate socket.io connections using JWTs",
|
"description": "authenticate socket.io connections using JWTs",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
|
"types": "./types/index.d.ts",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"socket",
|
"socket",
|
||||||
"socket.io",
|
"socket.io",
|
||||||
@ -22,19 +23,19 @@
|
|||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsonwebtoken": "^5.0.0",
|
|
||||||
"xtend": "~2.1.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"body-parser": "~1.13.3",
|
"@types/socket.io": "~1.4.29",
|
||||||
"express": "~4.10.6",
|
"body-parser": "~1.17.1",
|
||||||
"mocha": "~1.17.0",
|
"express": "~4.15.2",
|
||||||
"passport-local": "~0.1.6",
|
"mocha": "~3.2.0",
|
||||||
"request": "~2.19.0",
|
"request": "~2.81.0",
|
||||||
"serve-static": "^1.7.1",
|
"serve-static": "^1.12.1",
|
||||||
|
"jsonwebtoken": "^8.3.0",
|
||||||
|
"xtend": "~2.1.2",
|
||||||
"server-destroy": "~1.0.1",
|
"server-destroy": "~1.0.1",
|
||||||
"should": "~1.2.2",
|
"should": "~11.2.1",
|
||||||
"socket.io": "^1.0.4",
|
"socket.io": "^1.7.3",
|
||||||
"socket.io-client": "^1.0.4"
|
"socket.io-client": "^1.7.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -38,7 +38,7 @@ exports.start = function (options, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// We are sending the profile inside the token
|
// We are sending the profile inside the token
|
||||||
var token = jwt.sign(profile, options.secret, { expiresInMinutes: 60*5 });
|
var token = jwt.sign(profile, options.secret, { expiresIn: 60*60*5 });
|
||||||
|
|
||||||
res.json({token: token});
|
res.json({token: token});
|
||||||
});
|
});
|
||||||
|
@ -38,7 +38,7 @@ exports.start = function (callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// We are sending the profile inside the token
|
// We are sending the profile inside the token
|
||||||
var token = jwt.sign(profile, options.secret, { expiresInMinutes: 60*5 });
|
var token = jwt.sign(profile, options.secret, { expiresIn: 60*60*5 });
|
||||||
|
|
||||||
res.json({token: token});
|
res.json({token: token});
|
||||||
});
|
});
|
||||||
|
72
types/index.d.ts
vendored
Normal file
72
types/index.d.ts
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* This module allows to authenticate socket.io connections with JWTs.
|
||||||
|
* This is especially if you do not want to use cookies in a single page application.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <reference types="socket.io" />
|
||||||
|
|
||||||
|
declare module 'socketio-jwt' {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines possible errors for the secret-callback.
|
||||||
|
*/
|
||||||
|
interface ISocketIOError {
|
||||||
|
readonly code: string;
|
||||||
|
readonly message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback gets called, if secret is given dynamically.
|
||||||
|
*/
|
||||||
|
interface ISocketCallback {
|
||||||
|
(err: ISocketIOError, success: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISocketIOMiddleware {
|
||||||
|
(socket: SocketIO.Socket, fn: (err?: any) => void): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IOptions {
|
||||||
|
additional_auth?: (decoded: object, onSuccess: () => void, onError: (err: (string | ISocketIOError), code: string) => void) => void;
|
||||||
|
|
||||||
|
callback?: (false | number);
|
||||||
|
secret: (string | ((request: any, decodedToken: object, callback: ISocketCallback) => void));
|
||||||
|
|
||||||
|
encodedPropertyName?: string;
|
||||||
|
decodedPropertyName?: string;
|
||||||
|
auth_header_required?: boolean;
|
||||||
|
handshake?: boolean;
|
||||||
|
required?: boolean;
|
||||||
|
timeout?: number;
|
||||||
|
cookie?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function authorize(options: IOptions/*, onConnection: Function*/): ISocketIOMiddleware;
|
||||||
|
|
||||||
|
interface UnauthorizedError extends Error {
|
||||||
|
readonly message: string;
|
||||||
|
readonly inner: object;
|
||||||
|
readonly data: { message: string, code: string, type: 'UnauthorizedError' }
|
||||||
|
}
|
||||||
|
|
||||||
|
var UnauthorizedError: {
|
||||||
|
prototype: UnauthorizedError;
|
||||||
|
new (code: string, error: { message: string }): UnauthorizedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an augmented version of the SocketIO.Server.
|
||||||
|
* It knows the 'authenticated' event and should be extended in future.
|
||||||
|
* @see SocketIO.Server
|
||||||
|
*/
|
||||||
|
export interface JWTServer extends SocketIO.Server {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The event gets fired when a new connection is authenticated via JWT.
|
||||||
|
* @param event The event being fired: 'authenticated'
|
||||||
|
* @param listener A listener that should take one parameter of type Socket
|
||||||
|
* @return The default '/' Namespace
|
||||||
|
*/
|
||||||
|
on(event: ('authenticated' | string), listener: (socket: SocketIO.Socket) => void): SocketIO.Namespace;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user