├── .gitignore ├── LICENSE ├── README.md ├── app.js ├── model.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Pedro Trujillo (pedroetb) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-oauth2-server example 2 | 3 | This is a basic example of a OAuth2 server, using [node-oauth2-server](https://github.com/oauthjs/node-oauth2-server) (version 3.0.1) with the minimum (only the required to work) model configuration. 4 | 5 | If you want an example with a better data management system, you should go to [node-oauth2-server-mongo-example](https://github.com/pedroetb/node-oauth2-server-mongo-example) instead. 6 | 7 | ## Setup 8 | 9 | Install **nodejs** and **npm** and then, simply run `npm install` and `npm start`. The server should now be running at `http://localhost:3000`. 10 | 11 | ## Usage 12 | 13 | You can use different grant types to get an access token. By now, `password`, `client_credentials` and `refresh_token` are available. 14 | 15 | ### Checking example data 16 | 17 | #### With *password* grant 18 | 19 | There is one client added to server and ready to work: 20 | 21 | * **clientId**: `application` 22 | * **clientSecret**: `secret` 23 | 24 | And there is also one existing user: 25 | 26 | * **username**: `pedroetb` 27 | * **password**: `password` 28 | 29 | #### With *client_credentials* grant 30 | 31 | There is one confidential client added to server and ready to work: 32 | 33 | * **clientId**: `confidentialApplication` 34 | * **clientSecret**: `topSecret` 35 | 36 | You don't need any user to use this grant type, but for security is only available to confidential clients. 37 | 38 | #### With *refresh_token* grant 39 | 40 | There is one client added to server and ready to work: 41 | 42 | * **clientId**: `application` 43 | * **clientSecret**: `secret` 44 | 45 | You don't need any user to use this grant type, it was already provided when original token was obtained (by *password* grant type, for example). 46 | 47 | ### Obtaining a token 48 | 49 | To obtain a token you should POST to `http://localhost:3000/oauth/token`. 50 | 51 | #### With *password* grant 52 | 53 | You need to include the client credentials in request headers and the user credentials and grant type in request body: 54 | 55 | * **Headers** 56 | * **Authorization**: `"Basic " + clientId:clientSecret base64'd` 57 | * (for example, to use `application:secret`, you should send `Basic YXBwbGljYXRpb246c2VjcmV0`) 58 | 59 | * **Content-Type**: `application/x-www-form-urlencoded` 60 | * **Body** 61 | * `grant_type=password&username=pedroetb&password=password` 62 | * (contains 3 parameters: `grant_type`, `username` and `password`) 63 | 64 | For example, using `curl`: 65 | ``` 66 | curl http://localhost:3000/oauth/token \ 67 | -d "grant_type=password" \ 68 | -d "username=pedroetb" \ 69 | -d "password=password" \ 70 | -H "Authorization: Basic YXBwbGljYXRpb246c2VjcmV0" \ 71 | -H "Content-Type: application/x-www-form-urlencoded" 72 | ``` 73 | 74 | If all goes as planned, you should receive a response like this: 75 | 76 | ``` 77 | { 78 | "accessToken": "951d6f603c2ce322c5def00ce58952ed2d096a72", 79 | "accessTokenExpiresAt": "2018-11-18T16:18:25.852Z", 80 | "refreshToken": "67c8300ad53efa493c2278acf12d92bdb71832f9", 81 | "refreshTokenExpiresAt": "2018-12-02T15:18:25.852Z", 82 | "client": { 83 | "id": "application" 84 | }, 85 | "user": { 86 | "id": "pedroetb" 87 | } 88 | } 89 | ``` 90 | 91 | #### With *client_credentials* grant 92 | 93 | You need to include the client credentials in request headers and the grant type in request body: 94 | 95 | * **Headers** 96 | * **Authorization**: `"Basic " + clientId:clientSecret base64'd` 97 | * (for example, to use `confidentialApplication:topSecret`, you should send `Basic Y29uZmlkZW50aWFsQXBwbGljYXRpb246dG9wU2VjcmV0`) 98 | 99 | * **Content-Type**: `application/x-www-form-urlencoded` 100 | * **Body** 101 | * `grant_type=client_credentials` 102 | 103 | For example, using `curl`: 104 | ``` 105 | curl http://localhost:3000/oauth/token \ 106 | -d "grant_type=client_credentials" \ 107 | -H "Authorization: Basic Y29uZmlkZW50aWFsQXBwbGljYXRpb246dG9wU2VjcmV0" \ 108 | -H "Content-Type: application/x-www-form-urlencoded" 109 | ``` 110 | 111 | If all goes as planned, you should receive a response like this: 112 | 113 | ``` 114 | { 115 | "accessToken": "951d6f603c2ce322c5def00ce58952ed2d096a72", 116 | "accessTokenExpiresAt": "2018-11-18T16:18:25.852Z", 117 | "client": { 118 | "id": "confidentialApplication" 119 | }, 120 | "user": { 121 | "id": "confidentialApplication" 122 | } 123 | } 124 | ``` 125 | 126 | #### With *refresh_token* grant 127 | 128 | When obtaining an access token using *password* grant, you get also a refresh token. 129 | With this token you can get a new access token, using only that value (username and password are not needed), while it has not been expired. 130 | 131 | > Remember that, if you refresh a token while it was still valid, the old access and refresh tokens get revoked, and only the new access and refresh tokens are valid to be used. 132 | 133 | You need to include the client credentials in request headers and the refresh token and grant type in request body: 134 | 135 | * **Headers** 136 | * **Authorization**: `"Basic " + clientId:clientSecret base64'd` 137 | * (for example, to use `application:secret`, you should send `Basic YXBwbGljYXRpb246c2VjcmV0`) 138 | 139 | * **Content-Type**: `application/x-www-form-urlencoded` 140 | * **Body** 141 | * `grant_type=refresh_token&refresh_token=67c8300ad53efa493c2278acf12d92bdb71832f9` 142 | * (contains 2 parameters: `grant_type` and `refresh_token`) 143 | 144 | For example, using `curl`: 145 | ``` 146 | curl http://localhost:3000/oauth/token \ 147 | -d "grant_type=refresh_token" \ 148 | -d "refresh_token=67c8300ad53efa493c2278acf12d92bdb71832f9" \ 149 | -H "Authorization: Basic YXBwbGljYXRpb246c2VjcmV0" \ 150 | -H "Content-Type: application/x-www-form-urlencoded" 151 | ``` 152 | 153 | If all goes as planned, you should receive a response like this: 154 | 155 | ``` 156 | { 157 | "accessToken": "17be4ee45b177651db3fd9d286042de75d48eb3b", 158 | "accessTokenExpiresAt": "2018-11-18T16:18:35.248Z", 159 | "refreshToken": "37eaff895c8fc9fc839c0098cf3fb01858097908", 160 | "refreshTokenExpiresAt": "2018-12-02T15:18:35.248Z", 161 | "client": { 162 | "id": "application" 163 | }, 164 | "user": { 165 | "id": "pedroetb" 166 | } 167 | } 168 | ``` 169 | 170 | ### Using the token 171 | 172 | Now, you can use your brand-new token to access restricted areas. For example, you can GET to `http://localhost:3000/` including your token at headers: 173 | 174 | * **Headers** 175 | * **Authorization**: `"Bearer " + accessToken` 176 | * (for example, `Bearer 951d6f603c2ce322c5def00ce58952ed2d096a72`) 177 | 178 | For example, using `curl`: 179 | ``` 180 | curl http://localhost:3000 \ 181 | -H "Authorization: Bearer 951d6f603c2ce322c5def00ce58952ed2d096a72" 182 | ``` 183 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'), 2 | bodyParser = require('body-parser'), 3 | OAuth2Server = require('oauth2-server'), 4 | Request = OAuth2Server.Request, 5 | Response = OAuth2Server.Response; 6 | 7 | var app = express(); 8 | 9 | app.use(bodyParser.urlencoded({ extended: true })); 10 | 11 | app.use(bodyParser.json()); 12 | 13 | app.oauth = new OAuth2Server({ 14 | model: require('./model.js'), 15 | accessTokenLifetime: 60 * 60, 16 | allowBearerTokensInQueryString: true 17 | }); 18 | 19 | app.all('/oauth/token', obtainToken); 20 | 21 | app.get('/', authenticateRequest, function(req, res) { 22 | 23 | res.send('Congratulations, you are in a secret area!'); 24 | }); 25 | 26 | app.listen(3000); 27 | 28 | function obtainToken(req, res) { 29 | 30 | var request = new Request(req); 31 | var response = new Response(res); 32 | 33 | return app.oauth.token(request, response) 34 | .then(function(token) { 35 | 36 | res.json(token); 37 | }).catch(function(err) { 38 | 39 | res.status(err.code || 500).json(err); 40 | }); 41 | } 42 | 43 | function authenticateRequest(req, res, next) { 44 | 45 | var request = new Request(req); 46 | var response = new Response(res); 47 | 48 | return app.oauth.authenticate(request, response) 49 | .then(function(token) { 50 | 51 | next(); 52 | }).catch(function(err) { 53 | 54 | res.status(err.code || 500).json(err); 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /model.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Configuration. 3 | */ 4 | 5 | var config = { 6 | clients: [{ 7 | id: 'application', // TODO: Needed by refresh_token grant, because there is a bug at line 103 in https://github.com/oauthjs/node-oauth2-server/blob/v3.0.1/lib/grant-types/refresh-token-grant-type.js (used client.id instead of client.clientId) 8 | clientId: 'application', 9 | clientSecret: 'secret', 10 | grants: [ 11 | 'password', 12 | 'refresh_token' 13 | ], 14 | redirectUris: [] 15 | }], 16 | confidentialClients: [{ 17 | clientId: 'confidentialApplication', 18 | clientSecret: 'topSecret', 19 | grants: [ 20 | 'password', 21 | 'client_credentials' 22 | ], 23 | redirectUris: [] 24 | }], 25 | tokens: [], 26 | users: [{ 27 | username: 'pedroetb', 28 | password: 'password' 29 | }] 30 | }; 31 | 32 | /** 33 | * Dump the memory storage content (for debug). 34 | */ 35 | 36 | var dump = function() { 37 | 38 | console.log('clients', config.clients); 39 | console.log('confidentialClients', config.confidentialClients); 40 | console.log('tokens', config.tokens); 41 | console.log('users', config.users); 42 | }; 43 | 44 | /* 45 | * Methods used by all grant types. 46 | */ 47 | 48 | var getAccessToken = function(token) { 49 | 50 | var tokens = config.tokens.filter(function(savedToken) { 51 | 52 | return savedToken.accessToken === token; 53 | }); 54 | 55 | return tokens[0]; 56 | }; 57 | 58 | var getClient = function(clientId, clientSecret) { 59 | 60 | var clients = config.clients.filter(function(client) { 61 | 62 | return client.clientId === clientId && client.clientSecret === clientSecret; 63 | }); 64 | 65 | var confidentialClients = config.confidentialClients.filter(function(client) { 66 | 67 | return client.clientId === clientId && client.clientSecret === clientSecret; 68 | }); 69 | 70 | return clients[0] || confidentialClients[0]; 71 | }; 72 | 73 | var saveToken = function(token, client, user) { 74 | 75 | token.client = { 76 | id: client.clientId 77 | }; 78 | 79 | token.user = { 80 | username: user.username 81 | }; 82 | 83 | config.tokens.push(token); 84 | 85 | return token; 86 | }; 87 | 88 | /* 89 | * Method used only by password grant type. 90 | */ 91 | 92 | var getUser = function(username, password) { 93 | 94 | var users = config.users.filter(function(user) { 95 | 96 | return user.username === username && user.password === password; 97 | }); 98 | 99 | return users[0]; 100 | }; 101 | 102 | /* 103 | * Method used only by client_credentials grant type. 104 | */ 105 | 106 | var getUserFromClient = function(client) { 107 | 108 | var clients = config.confidentialClients.filter(function(savedClient) { 109 | 110 | return savedClient.clientId === client.clientId && savedClient.clientSecret === client.clientSecret; 111 | }); 112 | 113 | return clients.length; 114 | }; 115 | 116 | /* 117 | * Methods used only by refresh_token grant type. 118 | */ 119 | 120 | var getRefreshToken = function(refreshToken) { 121 | 122 | var tokens = config.tokens.filter(function(savedToken) { 123 | 124 | return savedToken.refreshToken === refreshToken; 125 | }); 126 | 127 | if (!tokens.length) { 128 | return; 129 | } 130 | 131 | return tokens[0]; 132 | }; 133 | 134 | var revokeToken = function(token) { 135 | 136 | config.tokens = config.tokens.filter(function(savedToken) { 137 | 138 | return savedToken.refreshToken !== token.refreshToken; 139 | }); 140 | 141 | var revokedTokensFound = config.tokens.filter(function(savedToken) { 142 | 143 | return savedToken.refreshToken === token.refreshToken; 144 | }); 145 | 146 | return !revokedTokensFound.length; 147 | }; 148 | 149 | /** 150 | * Export model definition object. 151 | */ 152 | 153 | module.exports = { 154 | getAccessToken: getAccessToken, 155 | getClient: getClient, 156 | saveToken: saveToken, 157 | getUser: getUser, 158 | getUserFromClient: getUserFromClient, 159 | getRefreshToken: getRefreshToken, 160 | revokeToken: revokeToken 161 | }; 162 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-oauth2-server-example", 3 | "version": "1.3.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.7", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 10 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 11 | "requires": { 12 | "mime-types": "~2.1.24", 13 | "negotiator": "0.6.2" 14 | }, 15 | "dependencies": { 16 | "mime-db": { 17 | "version": "1.40.0", 18 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 19 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 20 | }, 21 | "mime-types": { 22 | "version": "2.1.24", 23 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 24 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 25 | "requires": { 26 | "mime-db": "1.40.0" 27 | } 28 | } 29 | } 30 | }, 31 | "array-flatten": { 32 | "version": "1.1.1", 33 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 34 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 35 | }, 36 | "basic-auth": { 37 | "version": "2.0.1", 38 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", 39 | "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", 40 | "requires": { 41 | "safe-buffer": "5.1.2" 42 | } 43 | }, 44 | "bluebird": { 45 | "version": "3.5.3", 46 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", 47 | "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==" 48 | }, 49 | "body-parser": { 50 | "version": "1.19.0", 51 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 52 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 53 | "requires": { 54 | "bytes": "3.1.0", 55 | "content-type": "~1.0.4", 56 | "debug": "2.6.9", 57 | "depd": "~1.1.2", 58 | "http-errors": "1.7.2", 59 | "iconv-lite": "0.4.24", 60 | "on-finished": "~2.3.0", 61 | "qs": "6.7.0", 62 | "raw-body": "2.4.0", 63 | "type-is": "~1.6.17" 64 | }, 65 | "dependencies": { 66 | "mime-db": { 67 | "version": "1.40.0", 68 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 69 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 70 | }, 71 | "mime-types": { 72 | "version": "2.1.24", 73 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 74 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 75 | "requires": { 76 | "mime-db": "1.40.0" 77 | } 78 | }, 79 | "type-is": { 80 | "version": "1.6.18", 81 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 82 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 83 | "requires": { 84 | "media-typer": "0.3.0", 85 | "mime-types": "~2.1.24" 86 | } 87 | } 88 | } 89 | }, 90 | "bytes": { 91 | "version": "3.1.0", 92 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 93 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 94 | }, 95 | "co-bluebird": { 96 | "version": "1.1.0", 97 | "resolved": "https://registry.npmjs.org/co-bluebird/-/co-bluebird-1.1.0.tgz", 98 | "integrity": "sha1-yLnzqTIKftMJh9zKGlw8/1llXHw=", 99 | "requires": { 100 | "bluebird": "^2.10.0", 101 | "co-use": "^1.1.0" 102 | }, 103 | "dependencies": { 104 | "bluebird": { 105 | "version": "2.11.0", 106 | "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", 107 | "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" 108 | } 109 | } 110 | }, 111 | "co-use": { 112 | "version": "1.1.0", 113 | "resolved": "https://registry.npmjs.org/co-use/-/co-use-1.1.0.tgz", 114 | "integrity": "sha1-xrs83xDLc17Kqdru2kbXJclKTmI=" 115 | }, 116 | "content-disposition": { 117 | "version": "0.5.3", 118 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 119 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 120 | "requires": { 121 | "safe-buffer": "5.1.2" 122 | } 123 | }, 124 | "content-type": { 125 | "version": "1.0.4", 126 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 127 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 128 | }, 129 | "cookie": { 130 | "version": "0.4.0", 131 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", 132 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 133 | }, 134 | "cookie-signature": { 135 | "version": "1.0.6", 136 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 137 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 138 | }, 139 | "debug": { 140 | "version": "2.6.9", 141 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 142 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 143 | "requires": { 144 | "ms": "2.0.0" 145 | } 146 | }, 147 | "depd": { 148 | "version": "1.1.2", 149 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 150 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 151 | }, 152 | "destroy": { 153 | "version": "1.0.4", 154 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 155 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 156 | }, 157 | "ee-first": { 158 | "version": "1.1.1", 159 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 160 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 161 | }, 162 | "encodeurl": { 163 | "version": "1.0.2", 164 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 165 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 166 | }, 167 | "escape-html": { 168 | "version": "1.0.3", 169 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 170 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 171 | }, 172 | "etag": { 173 | "version": "1.8.1", 174 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 175 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 176 | }, 177 | "express": { 178 | "version": "4.17.1", 179 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", 180 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 181 | "requires": { 182 | "accepts": "~1.3.7", 183 | "array-flatten": "1.1.1", 184 | "body-parser": "1.19.0", 185 | "content-disposition": "0.5.3", 186 | "content-type": "~1.0.4", 187 | "cookie": "0.4.0", 188 | "cookie-signature": "1.0.6", 189 | "debug": "2.6.9", 190 | "depd": "~1.1.2", 191 | "encodeurl": "~1.0.2", 192 | "escape-html": "~1.0.3", 193 | "etag": "~1.8.1", 194 | "finalhandler": "~1.1.2", 195 | "fresh": "0.5.2", 196 | "merge-descriptors": "1.0.1", 197 | "methods": "~1.1.2", 198 | "on-finished": "~2.3.0", 199 | "parseurl": "~1.3.3", 200 | "path-to-regexp": "0.1.7", 201 | "proxy-addr": "~2.0.5", 202 | "qs": "6.7.0", 203 | "range-parser": "~1.2.1", 204 | "safe-buffer": "5.1.2", 205 | "send": "0.17.1", 206 | "serve-static": "1.14.1", 207 | "setprototypeof": "1.1.1", 208 | "statuses": "~1.5.0", 209 | "type-is": "~1.6.18", 210 | "utils-merge": "1.0.1", 211 | "vary": "~1.1.2" 212 | }, 213 | "dependencies": { 214 | "mime-db": { 215 | "version": "1.40.0", 216 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 217 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 218 | }, 219 | "mime-types": { 220 | "version": "2.1.24", 221 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 222 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 223 | "requires": { 224 | "mime-db": "1.40.0" 225 | } 226 | }, 227 | "type-is": { 228 | "version": "1.6.18", 229 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 230 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 231 | "requires": { 232 | "media-typer": "0.3.0", 233 | "mime-types": "~2.1.24" 234 | } 235 | } 236 | } 237 | }, 238 | "finalhandler": { 239 | "version": "1.1.2", 240 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 241 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 242 | "requires": { 243 | "debug": "2.6.9", 244 | "encodeurl": "~1.0.2", 245 | "escape-html": "~1.0.3", 246 | "on-finished": "~2.3.0", 247 | "parseurl": "~1.3.3", 248 | "statuses": "~1.5.0", 249 | "unpipe": "~1.0.0" 250 | } 251 | }, 252 | "forwarded": { 253 | "version": "0.1.2", 254 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 255 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 256 | }, 257 | "fresh": { 258 | "version": "0.5.2", 259 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 260 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 261 | }, 262 | "http-errors": { 263 | "version": "1.7.2", 264 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 265 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 266 | "requires": { 267 | "depd": "~1.1.2", 268 | "inherits": "2.0.3", 269 | "setprototypeof": "1.1.1", 270 | "statuses": ">= 1.5.0 < 2", 271 | "toidentifier": "1.0.0" 272 | } 273 | }, 274 | "iconv-lite": { 275 | "version": "0.4.24", 276 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 277 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 278 | "requires": { 279 | "safer-buffer": ">= 2.1.2 < 3" 280 | } 281 | }, 282 | "inherits": { 283 | "version": "2.0.3", 284 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 285 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 286 | }, 287 | "ipaddr.js": { 288 | "version": "1.9.0", 289 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", 290 | "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" 291 | }, 292 | "is-generator": { 293 | "version": "1.0.3", 294 | "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz", 295 | "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=" 296 | }, 297 | "lodash": { 298 | "version": "4.17.14", 299 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", 300 | "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==" 301 | }, 302 | "media-typer": { 303 | "version": "0.3.0", 304 | "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 305 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 306 | }, 307 | "merge-descriptors": { 308 | "version": "1.0.1", 309 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 310 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 311 | }, 312 | "methods": { 313 | "version": "1.1.2", 314 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 315 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 316 | }, 317 | "mime": { 318 | "version": "1.6.0", 319 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 320 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 321 | }, 322 | "mime-db": { 323 | "version": "1.37.0", 324 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", 325 | "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" 326 | }, 327 | "mime-types": { 328 | "version": "2.1.21", 329 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", 330 | "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", 331 | "requires": { 332 | "mime-db": "~1.37.0" 333 | } 334 | }, 335 | "ms": { 336 | "version": "2.0.0", 337 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 338 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 339 | }, 340 | "negotiator": { 341 | "version": "0.6.2", 342 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 343 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 344 | }, 345 | "oauth2-server": { 346 | "version": "3.0.1", 347 | "resolved": "https://registry.npmjs.org/oauth2-server/-/oauth2-server-3.0.1.tgz", 348 | "integrity": "sha512-LFAT4MeTaOgdW+b8YMVMsPhJ8LrbSfVkYZRPgRmELJEJoXcchb/L4b9/lEmgpeNtjH8PlFiqof+YwI+y/oJuOg==", 349 | "requires": { 350 | "basic-auth": "^2.0.0", 351 | "bluebird": "^3.5.1", 352 | "lodash": "^4.17.10", 353 | "promisify-any": "^2.0.1", 354 | "statuses": "^1.5.0", 355 | "type-is": "^1.6.16" 356 | } 357 | }, 358 | "on-finished": { 359 | "version": "2.3.0", 360 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 361 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 362 | "requires": { 363 | "ee-first": "1.1.1" 364 | } 365 | }, 366 | "parseurl": { 367 | "version": "1.3.3", 368 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 369 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 370 | }, 371 | "path-to-regexp": { 372 | "version": "0.1.7", 373 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 374 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 375 | }, 376 | "promisify-any": { 377 | "version": "2.0.1", 378 | "resolved": "https://registry.npmjs.org/promisify-any/-/promisify-any-2.0.1.tgz", 379 | "integrity": "sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU=", 380 | "requires": { 381 | "bluebird": "^2.10.0", 382 | "co-bluebird": "^1.1.0", 383 | "is-generator": "^1.0.2" 384 | }, 385 | "dependencies": { 386 | "bluebird": { 387 | "version": "2.11.0", 388 | "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", 389 | "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" 390 | } 391 | } 392 | }, 393 | "proxy-addr": { 394 | "version": "2.0.5", 395 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", 396 | "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", 397 | "requires": { 398 | "forwarded": "~0.1.2", 399 | "ipaddr.js": "1.9.0" 400 | } 401 | }, 402 | "qs": { 403 | "version": "6.7.0", 404 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 405 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 406 | }, 407 | "range-parser": { 408 | "version": "1.2.1", 409 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 410 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 411 | }, 412 | "raw-body": { 413 | "version": "2.4.0", 414 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 415 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 416 | "requires": { 417 | "bytes": "3.1.0", 418 | "http-errors": "1.7.2", 419 | "iconv-lite": "0.4.24", 420 | "unpipe": "1.0.0" 421 | } 422 | }, 423 | "safe-buffer": { 424 | "version": "5.1.2", 425 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 426 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 427 | }, 428 | "safer-buffer": { 429 | "version": "2.1.2", 430 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 431 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 432 | }, 433 | "send": { 434 | "version": "0.17.1", 435 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", 436 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 437 | "requires": { 438 | "debug": "2.6.9", 439 | "depd": "~1.1.2", 440 | "destroy": "~1.0.4", 441 | "encodeurl": "~1.0.2", 442 | "escape-html": "~1.0.3", 443 | "etag": "~1.8.1", 444 | "fresh": "0.5.2", 445 | "http-errors": "~1.7.2", 446 | "mime": "1.6.0", 447 | "ms": "2.1.1", 448 | "on-finished": "~2.3.0", 449 | "range-parser": "~1.2.1", 450 | "statuses": "~1.5.0" 451 | }, 452 | "dependencies": { 453 | "ms": { 454 | "version": "2.1.1", 455 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 456 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 457 | } 458 | } 459 | }, 460 | "serve-static": { 461 | "version": "1.14.1", 462 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", 463 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 464 | "requires": { 465 | "encodeurl": "~1.0.2", 466 | "escape-html": "~1.0.3", 467 | "parseurl": "~1.3.3", 468 | "send": "0.17.1" 469 | } 470 | }, 471 | "setprototypeof": { 472 | "version": "1.1.1", 473 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 474 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 475 | }, 476 | "statuses": { 477 | "version": "1.5.0", 478 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 479 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 480 | }, 481 | "toidentifier": { 482 | "version": "1.0.0", 483 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 484 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 485 | }, 486 | "type-is": { 487 | "version": "1.6.16", 488 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 489 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 490 | "requires": { 491 | "media-typer": "0.3.0", 492 | "mime-types": "~2.1.18" 493 | } 494 | }, 495 | "unpipe": { 496 | "version": "1.0.0", 497 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 498 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 499 | }, 500 | "utils-merge": { 501 | "version": "1.0.1", 502 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 503 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 504 | }, 505 | "vary": { 506 | "version": "1.1.2", 507 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 508 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 509 | } 510 | } 511 | } 512 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-oauth2-server-example", 3 | "version": "1.3.2", 4 | "description": "Working oauth2 server with minimal configuration", 5 | "keywords": [ 6 | "oauth2-server", 7 | "oauth2", 8 | "oauth", 9 | "grant", 10 | "refresh-token", 11 | "password", 12 | "client-credentials" 13 | ], 14 | "homepage": "https://github.com/pedroetb/node-oauth2-server-example", 15 | "license": "MIT", 16 | "author": "Pedro Trujillo", 17 | "contributors": [ 18 | { 19 | "name": "Pedro Trujillo", 20 | "email": "pedroetb@gmail.com" 21 | } 22 | ], 23 | "main": "app.js", 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/pedroetb/node-oauth2-server-example.git" 27 | }, 28 | "scripts": { 29 | "start": "node app.js" 30 | }, 31 | "dependencies": { 32 | "body-parser": "^1.19.0", 33 | "express": "^4.17.1", 34 | "oauth2-server": "^3.0.1" 35 | }, 36 | "engines": { 37 | "node": ">=4.0.0", 38 | "npm": ">=2.14.2" 39 | } 40 | } 41 | --------------------------------------------------------------------------------