Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

simple-oauth2

Package Overview
Dependencies
Maintainers
2
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

simple-oauth2 - npm Package Compare versions

Comparing version 1.5.1 to 1.5.2

.eslintignore

24

CHANGELOG.md
# Changelog
## Next
## v1.5.2
* Publish new version, to fix the 1.5.1 version which mistakenly included some breaking changes
* Replace internal request library to wreck
* Replace bluebird with native promise implementation
* Replace callback interface with async/await
## v1.5.1
* Add support to specify scopes as array in `getToken` method

@@ -15,3 +11,2 @@ * Add support to empty strings and visual ASCII characters on `clientId`/`clientSecret` options

## v1.5.0
* Update debug dependency

@@ -21,3 +16,2 @@ * Add support to encode the authorization headers

## v1.4.0
* Update dependencies

@@ -27,27 +21,20 @@ * Add Node 8 to test matrix

## v1.3.0
* Add support for custom idParamName in authCode.authorizeURL() method
## v1.2.0
* Upgrade dependencies, to avoid using outdated/vulnerable versions
## v1.1.0
* Add support to body encoding format in library requests
## v1.0.3
* Add missing documentation for module options
## v1.0.2
* Parse token payload response `expires_in` property as integer
## v1.0.1
* Fixed documentation for **client** option.
## v1.0.0
* Refactored test to use fixtures.

@@ -64,3 +51,2 @@ * Update code to comply with more linter rules.

## v0.8.0 (1 August 2016)
* Upgraded code to strict mode.

@@ -72,3 +58,2 @@ * Upgraded all the code base to es6.

## v0.7.0 (22 April 2016)
* Replaced internal logger by the debug module logger.

@@ -78,3 +63,2 @@ * Fixed some project metadata.

## v0.6.0 (04 April 2016)
* Added optional sending support to the body auth params.

@@ -86,11 +70,8 @@ * Updated license information.

## v0.5.1 (25 January 2016)
* Fixed error class prototype inheritance. Now inherits correctly from Error.
## v0.5.0 (22 January 2016)
* Now all error states returned from the server, are rejected as HTTPError instances. (This allow to know what httpStatusCode was returned)
## v0.4.0 (18 January 2016)
* Updated project dependencies.

@@ -104,3 +85,2 @@ * Added support for passing arguments to the refresh token action.

## v0.3.0 (29 November 2015)
* Better documentation!

@@ -107,0 +87,0 @@ * Added support for promise based API

@@ -34,4 +34,5 @@ 'use strict';

options: Joi.object().keys({
bodyFormat: Joi.any().only('form', 'json').default('form'),
authorizationMethod: Joi.any().only('header', 'body').default('header'),
bodyFormat: Joi.any().valid('form', 'json').default('form'),
useBasicAuthorizationHeader: Joi.boolean().default(true),
useBodyAuth: Joi.boolean().default(true),
}).default(),

@@ -43,16 +44,21 @@ });

/**
* Creates a new simple-oauth2 client with the provided configuration
* @param {Object} opts Module options as defined in schema
* @returns {Object} The simple-oauth2 client
* Creates a new simple-oauth2 client
* with the passed configuration
*
* @param {Object} options Module options as defined in schema
*/
create(opts = {}) {
const options = Joi.attempt(opts, optionsSchema, 'Invalid options provided to simple-oauth2');
create(options) {
const moduleOptions = Joi.attempt(
options || {},
optionsSchema,
'Invalid options provided to simple-oauth2'
);
return {
accessToken: accessTokenModule(options),
ownerPassword: passwordModule(options),
authorizationCode: authCodeModule(options),
clientCredentials: clientCredentialsModule(options),
authorizationCode: authCodeModule(moduleOptions),
ownerPassword: passwordModule(moduleOptions),
clientCredentials: clientCredentialsModule(moduleOptions),
accessToken: accessTokenModule(moduleOptions),
};
},
};
'use strict';
const url = require('url');
const addSeconds = require('date-fns/add_seconds');

@@ -14,65 +15,75 @@ const isAfter = require('date-fns/is_after');

const core = coreModule(config);
const tokenUrl = url.resolve(config.auth.tokenHost, config.auth.tokenPath);
const revokeUrl = url.resolve(config.auth.tokenHost, config.auth.revokePath);
class AccessToken {
constructor(token) {
this.token = token;
function AccessToken(token) {
this.token = token;
if ('expires_at' in this.token) {
if (!isDate(this.token.expires_at)) {
this.token.expires_at = parse(this.token.expires_at);
}
} else {
this.token.expires_at = addSeconds(
new Date(),
Number.parseInt(token.expires_in, 10)
);
if ('expires_at' in this.token) {
if (!isDate(this.token.expires_at)) {
this.token.expires_at = parse(this.token.expires_at);
}
} else {
this.token.expires_at = addSeconds(
new Date(),
Number.parseInt(token.expires_in, 10)
);
}
}
/**
* Check if the access token is expired or not
*/
expired() {
return isAfter(new Date(), this.token.expires_at);
}
/**
* Creates an OAuth2.AccessToken instance
* @param {Object} token An object containing the token object returned from the OAuth2 server.
*/
function createAccessToken(tokenToUse) {
return new AccessToken(tokenToUse);
}
/**
* Refresh the access token
* @param {Object} params An optional argument for additional API request params.
*/
async refresh(params) {
const options = Object.assign({}, params, {
grant_type: 'refresh_token',
refresh_token: this.token.refresh_token,
});
/**
* Check if the access token is expired or not
*/
AccessToken.prototype.expired = function expired() {
return isAfter(new Date(), this.token.expires_at);
};
const response = await core.request(config.auth.tokenPath, options);
return createAccessToken(response);
/**
* Refresh the access token
* @param {Object} An optional argument for additional API request params.
* @param {Function} callback
*/
AccessToken.prototype.refresh = function refresh(params, callback) {
if (typeof params === 'function') {
callback = params;
params = undefined;
}
/**
* Revoke access or refresh token
* @param {String} tokenType A string containing the type of token to revoke.
* Should be either "access_token" or "refresh_token"
*/
async revoke(tokenType) {
const token = tokenType === 'access_token' ? this.token.access_token : this.token.refresh_token;
const options = {
token,
token_type_hint: tokenType,
};
const options = Object.assign({}, params || {}, {
grant_type: 'refresh_token',
refresh_token: this.token.refresh_token,
});
return core.request(config.auth.revokePath, options);
}
}
return core
.api('POST', tokenUrl, options)
.then(response => createAccessToken(response))
.nodeify(callback);
};
/**
* Creates an OAuth2.AccessToken instance
* @param {Object} token An object containing the token object returned from the OAuth2 server.
*/
function createAccessToken(token) {
return new AccessToken(token);
}
* Revoke access or refresh token
* @param {String} tokenType A string containing the type of token to revoke.
* Should be either "access_token" or "refresh_token"
* @param {Function} callback
*/
AccessToken.prototype.revoke = function revoke(tokenType, callback) {
const token = tokenType === 'access_token' ? this.token.access_token : this.token.refresh_token;
const options = {
token,
token_type_hint: tokenType,
};
return core
.api('POST', revokeUrl, options)
.nodeify(callback);
};
return {

@@ -79,0 +90,0 @@ create: createAccessToken,

@@ -12,2 +12,3 @@ 'use strict';

const core = coreModule(config);
const tokenUrl = url.resolve(config.auth.tokenHost, config.auth.tokenPath);
const authorizeUrl = url.resolve(config.auth.authorizeHost, config.auth.authorizePath);

@@ -19,4 +20,3 @@

* where the user is redirected after authentication
* @param {String|Array<String>} params.scope A String or array of strings
* that represents the application privileges
* @param {String} params.scope A String that represents the application privileges
* @param {String} params.state A String that represents an option opaque value used by the client

@@ -26,13 +26,11 @@ * to main the state between the request and the callback

*/
function authorizeURL(params = {}) {
const baseParams = {
response_type: 'code',
[config.client.idParamName]: config.client.id,
};
if (Array.isArray(params.scope)) {
function authorizeURL(params) {
if (params && params.scope && params.scope instanceof Array) {
params.scope = params.scope.join(',');
}
const options = Object.assign({}, baseParams, params);
const options = Object.assign({}, {
response_type: 'code',
[config.client.idParamName]: config.client.id,
}, params);

@@ -46,5 +44,6 @@ return `${authorizeUrl}?${qs.stringify(options)}`;

* @param {String} params.redirecURI A string that represents the callback uri
* @param {Function} callback
* @return {Promise}
*/
async function getToken(params) {
function getToken(params, callback) {
const options = Object.assign({}, params, {

@@ -54,3 +53,5 @@ grant_type: 'authorization_code',

return core.request(config.auth.tokenPath, options);
return core
.api('POST', tokenUrl, options)
.nodeify(callback);
}

@@ -57,0 +58,0 @@

'use strict';
const url = require('url');
const coreModule = require('./../core');

@@ -10,15 +11,18 @@

const core = coreModule(config);
const tokenUrl = url.resolve(config.auth.tokenHost, config.auth.tokenPath);
/**
* Returns the Access Token Object
* @param {Object} params
* @param {String} params.scope A string that represents the application privileges
* @param {Function} callback
* @return {Promise}
*/
async function getToken(params) {
const options = Object.assign({}, params, {
function getToken(params, callback) {
const options = Object.assign({}, params || {}, {
grant_type: 'client_credentials',
});
return core.request(config.auth.tokenPath, options);
return core
.api('POST', tokenUrl, options)
.nodeify(callback);
}

@@ -25,0 +29,0 @@

'use strict';
const url = require('url');
const coreModule = require('./../core');

@@ -10,17 +11,20 @@

const core = coreModule(config);
const tokenUrl = url.resolve(config.auth.tokenHost, config.auth.tokenPath);
/**
* Returns the Access Token Object
* @param {Object} params
* @param {String} params.username A string that represents the registered username
* @param {String} params.password A string that represents the registered password
* @param {String} params.password A string that represents the registered password.
* @param {String} params.scope A string that represents the application privileges
* @param {Function} callback
* @return {Promise}
*/
async function getToken(params) {
const options = Object.assign({}, params, {
function getToken(params, callback) {
const options = Object.assign({}, params || {}, {
grant_type: 'password',
});
return core.request(config.auth.tokenPath, options);
return core
.api('POST', tokenUrl, options)
.nodeify(callback);
}

@@ -27,0 +31,0 @@

'use strict';
const Wreck = require('wreck');
const querystring = require('querystring');
const debug = require('debug')('simple-oauth2:index');
const encoding = require('./encoding');
const Promise = require('bluebird');
const debug = require('debug')('simple-oauth2:main');
const utils = require('./utils');
const HTTPError = require('./error');
const request = Promise.promisify(require('request'), {
multiArgs: true,
});
/**
* Parse the oauth server response
* Decides wether or not the response is accepted
* @param {response} response raw response object
* @param {Object} body
* @param {Function} callback
* @return {Promise}
*/
function parseReponse(response, body) {
debug('Checking response body', body);
try {
body = JSON.parse(body);
} catch (e) {
/* The OAuth2 server does not return a valid JSON */
}
if (response.statusCode >= 400) {
return Promise.reject(new HTTPError(response.statusCode, body));
}
return Promise.resolve(body);
}
module.exports = (config) => {
const httpOptions = Object.assign({}, config.http, {
baseUrl: config.auth.tokenHost,
});
// makes an http request
function call(method, uri, params) {
const options = Object.assign({}, { method, uri }, config.http);
const wreck = Wreck.defaults(httpOptions);
// api authenticated call sent using headers
if (params.access_token && !params[config.client.idParamName]) {
options.headers.Authorization = `Bearer ${params.access_token}`;
async function request(url, params) {
let payload = params;
const options = {
json: true,
headers: {},
};
delete params.access_token;
if (config.options.authorizationMethod === 'header') {
const basicHeader = encoding.getAuthorizationHeaderToken(
config.client.id,
config.client.secret
);
// oauth2 server call used to retrieve a valid token
} else if (config.options.useBasicAuthorizationHeader &&
config.client.id &&
!params[config.client.idParamName]) {
const basicHeader = utils.getAuthorizationHeaderToken(config.client.id, config.client.secret);
options.headers.Authorization = `Basic ${basicHeader}`;
}
debug('Using header authentication. Authorization header set to %s', basicHeader);
if (Object.keys(params).length === 0) params = null;
options.headers.Authorization = `Basic ${basicHeader}`;
if (method !== 'GET') {
if (config.options.bodyFormat === 'form') {
options.form = params;
} else {
// if the bodyFormat is not form, is assummed to be json
options.json = true;
options.body = params;
}
} else {
debug('Using body authentication');
options.qs = params;
}
payload = Object.assign({}, payload, {
[config.client.idParamName]: config.client.id,
[config.client.secretParamName]: config.client.secret,
});
// Enable the system to send authorization params in the body.
if (config.options.useBodyAuth) {
if (options.form) {
// An example using `form` authorization params in the body is the
// GitHub API.
options.form[config.client.idParamName] = config.client.id;
options.form[config.client.secretParamName] = config.client.secret;
} else {
// An example using `json` authorization params in the body is the
// Amazon Developer Publishing API.
options.body[config.client.idParamName] = config.client.id;
options.body[config.client.secretParamName] = config.client.secret;
}
}
if (config.options.bodyFormat === 'form') {
debug('Using form request format');
debug('Making the HTTP request', options);
// An example using `form` authorization params in the body is the
// GitHub API.
options.payload = querystring.stringify(payload);
options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
} else {
debug('Using json request format');
return request(options);
}
// An example using `json` authorization params in the body is the
// Amazon Developer Publishing API.
options.payload = payload;
options.headers['Content-Type'] = 'application/json';
// High level method to call API
function api(method, url, params, callback) {
if (typeof params === 'function') {
callback = params;
params = {};
}
debug('Creating request to: (POST) %s', url);
debug('Using options: %j', options);
debug('OAuth2 Node Request');
const result = await wreck.post(url, options);
return result.payload;
return call(method, url, params)
.spread(parseReponse)
.nodeify(callback);
}
return {
request,
call,
api,
};
};
{
"name": "simple-oauth2",
"version": "1.5.1",
"version": "1.5.2",
"description": "Node.js client for OAuth2",

@@ -16,3 +16,3 @@ "author": "Andrea Reginato <andrea.reginato@gmail.com>",

"engine": {
"node": ">=8.0"
"node": ">=4.0"
},

@@ -29,6 +29,7 @@ "scripts": {

"dependencies": {
"bluebird": "^3.5.0",
"date-fns": "^1.3.0",
"debug": "^3.1.0",
"joi": "^13.0.2",
"wreck": "^14.0.2"
"joi": "^12.0.0",
"request": "^2.81.0"
},

@@ -35,0 +36,0 @@ "devDependencies": {

@@ -1,3 +0,1 @@

# Simple OAuth2
[![NPM Package Version](https://img.shields.io/npm/v/simple-oauth2.svg?style=flat-square)](https://www.npmjs.com/package/simple-oauth2)

@@ -7,4 +5,6 @@ [![Build Status](https://img.shields.io/travis/lelylan/simple-oauth2.svg?style=flat-square)](https://travis-ci.org/lelylan/simple-oauth2)

Node.js client library for [OAuth2](http://oauth.net/2/).
# Simple OAuth2
Node.js client library for [OAuth2](http://oauth.net/2/) (this library supports both callbacks or promises for async flow).
OAuth2 lets users grant the access to the desired resources to third party applications,

@@ -26,2 +26,3 @@ giving them the possibility to enable and disable those accesses whenever they want.

## Table of Contents

@@ -54,40 +55,38 @@

## Requirements
Node client library is tested against the latest minor Node versions: 4, 5 and 6.
The node client library is tested against the latest Node 8 LTS and newer versions.
To use in older node version, please use [simple-oauth2@0.x](https://github.com/lelylan/simple-oauth2/tree/v0.8.0).
To use in node 4, 5 or 6, please use [simple-oauth2@1.x](https://github.com/lelylan/simple-oauth2/tree/1.5.0). Older node versions are unsupported.
## Getting started
### Installation
Install the client library using [npm](http://npmjs.org/):
```bash
npm install --save simple-oauth2
```
```bash
$ npm install --save simple-oauth2
```
### Options
Simple OAuth2 accepts an object with the following valid params.
* `client` - required object with the following properties:
* `id` - Service registered client id. Required.
* `secret` - Service registered client secret. Required.
* `secretParamName` - Parameter name used to send the client secret. Default to **client_secret**.
* `idParamName` - Parameter name used to send the client id. Default to **client_id**.
- `id` - Service registered client id. Required.
- `secret` - Service registered client secret. Required.
- `secretParamName` - Parameter name used to send the client secret. Default to **client_secret**.
- `idParamName` - Parameter name used to send the client id. Default to **client_id**.
* `auth` - required object with the following properties.
* `tokenHost` - String used to set the host to request the tokens to. Required.
* `tokenPath` - String path to request an access token. Default to **/oauth/token**.
* `revokePath` - String path to revoke an access token. Default to **/oauth/revoke**.
* `authorizeHost` - String used to set the host to request an "authorization code". Default to the value set on `auth.tokenHost`.
* `authorizePath` - String path to request an authorization code. Default to **/oauth/authorize**.
- `tokenHost` - String used to set the host to request the tokens to. Required.
- `tokenPath` - String path to request an access token. Default to **/oauth/token**.
- `revokePath` - String path to revoke an access token. Default to **/oauth/revoke**.
- `authorizeHost` - String used to set the host to request an "authorization code". Default to the value set on `auth.tokenHost`.
- `authorizePath` - String path to request an authorization code. Default to **/oauth/authorize**.
* `http` optional object used to set global options to the internal http library ([wreck](https://github.com/hapijs/wreck)).
* All options except **baseUrl** are allowed. Default to `headers.Accept = application/json`.
* `http` optional object used to set global options to the internal http library (request-js).
- Any key is allowed here. Default to `headers.Accept = application/json`.
* `options` optional object to setup the module.
* `bodyFormat` - Format of data sent in the request body. Valid options are `form` or `json`. Defaults to **form**.
* `authorizationMethod` - Indicates the method used to send the client.id/client.secret authorization params at the token request. Valid options are `header` or `body`. If set to **body**, the **bodyFormat** option will be used to format the credentials. Defaults to **header**.
- `bodyFormat` - Format of data sent in the request body. Valid values are `form` or `json`. Defaults to **form**.
- `useBodyAuth` - Whether or not the client.id/client.secret params are sent in the request body. Defaults to **true**.
- `useBasicAuthorizationHeader` - Whether or not the Basic Authorization header should be sent at the token request.

@@ -111,7 +110,5 @@ ```javascript

### Example of Usage
See the [example folder](./example).
## OAuth2 Supported flows
### Authorization Code flow

@@ -143,10 +140,21 @@

// Callbacks
// Save the access token
try {
const result = await oauth2.authorizationCode.getToken(tokenConfig)
oauth2.authorizationCode.getToken(tokenConfig, (error, result) => {
if (error) {
return console.log('Access Token Error', error.message);
}
const accessToken = oauth2.accessToken.create(result);
} catch (error) {
});
// Promises
// Save the access token
oauth2.authorizationCode.getToken(tokenConfig)
.then((result) => {
const accessToken = oauth2.accessToken.create(result);
})
.catch((error) => {
console.log('Access Token Error', error.message);
}
});
```

@@ -167,12 +175,24 @@

username: 'username',
password: 'password'
password: 'password' 
};
// Callbacks
// Save the access token
try {
const result = await oauth2.ownerPassword.getToken(tokenConfig);
oauth2.ownerPassword.getToken(tokenConfig, (error, result) => {
if (error) {
return console.log('Access Token Error', error.message);
}
const accessToken = oauth2.accessToken.create(result);
} catch (error) {
console.log('Access Token Error', error.message);
}
});
// Promises
// Save the access token
oauth2.ownerPassword
.getToken(tokenConfig)
.then((result) => {
const accessToken = oauth2.accessToken.create(result);
return accessToken;
});
```

@@ -188,13 +208,26 @@

// Callbacks
// Get the access token object for the client
try {
const result = await oauth2.clientCredentials.getToken(tokenConfig);
oauth2.clientCredentials.getToken(tokenConfig, (error, result) => {
if (error) {
return console.log('Access Token Error', error.message);
}
const accessToken = oauth2.accessToken.create(result);
} catch (error) {
console.log('Access Token error', error.message);
}
});
// Promises
// Get the access token object for the client
oauth2.clientCredentials
.getToken(tokenConfig)
.then((result) => {
const accessToken = oauth2.accessToken.create(result);
})
.catch((error) => {
console.log('Access Token error', error.message);
});
```
## Helpers
### Access Token object

@@ -219,7 +252,12 @@

if (accessToken.expired()) {
try {
accessToken = await accessToken.refresh();
} catch (error) {
console.log('Error refreshing access token: ', error.message);
}
// Callbacks
accessToken.refresh((error, result) => {
accessToken = result;
})
// Promises
accessToken.refresh()
.then((result) => {
accessToken = result;
});
}

@@ -248,7 +286,12 @@ ```

if (shouldRefresh) {
try {
accessToken = await accessToken.refresh();
} catch (error) {
console.log('Error refreshing access token: ', error.message);
}
// Callbacks
accessToken.refresh((error, result) => {
accessToken = result;
})
// Promises
accessToken.refresh()
.then((result) => {
accessToken = result;
});
}

@@ -262,13 +305,26 @@ ```

// Revoke both access and refresh tokens
try {
// Revoke only the access token
await accessToken.revoke('access_token')
// Callbacks
// Revoke only the access token
accessToken.revoke('access_token', (error) => {
// Session ended. But the refresh_token is still valid.
// Session ended. But the refresh_token is still valid.
// Revoke the refresh token
await accessToken.revoke('refresh_token');
} catch (error) {
console.log('Error revoking token: ', error.message);
}
// Revoke the refresh_token
accessToken.revoke('refresh_token', (error) => {
console.log('token revoked.');
});
});
// Promises
// Revoke only the access token
accessToken.revoke('access_token')
.then(() => {
// Revoke the refresh token
return accessToken.revoke('refresh_token');
})
.then(() => {
console.log('Token revoked');
})
.catch((error) => {
console.log('Error revoking token.', error.message);
});
```

@@ -278,33 +334,34 @@

Errors are returned when a 4xx or 5xx status code is received.
Exceptions are raised when a 4xx or 5xx status code is returned.
BoomError
HTTPError
As a standard [boom](https://github.com/hapijs/boom) error you can access any of the boom error properties. The total amount of information varies according to the generated status code.
Through the error message attribute you can access the JSON representation
based on HTTP `status` and error `message`.
```javascript
// Callbacks
oauth2.authorizationCode.getToken({}, (error, token) => {
if (error) {
return console.log(error.message);
}
});
try {
await oauth2.authorizationCode.getToken();
} catch(error) {
console.log(error);
}
// Promises
oauth2.authorizationCode
.getToken({})
.catch((error) => {
console.log(error.message);
});
// => {
// "statusCode": 401,
// "error": "Unauthorized",
// "message": "invalid password"
// }
// => { "status": "401", "message": "Unauthorized" }
```
## Contributing
See [CONTRIBUTING](https://github.com/lelylan/simple-oauth2/blob/master/CONTRIBUTING.md)
## Authors
[Andrea Reginato](http://twitter.com/lelylan)
### Contributors
Special thanks to the following people for submitting patches.

@@ -315,3 +372,2 @@

## Changelog
See [CHANGELOG](https://github.com/lelylan/simple-oauth2/blob/master/CHANGELOG.md)

@@ -318,0 +374,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc