Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

simple-oauth2

lelylan1.1mApache-2.05.1.0TypeScript support: definitely-typed

Node.js client for OAuth2

oauth2, authorization, password, client, credentials

readme

Simple OAuth2

NPM Package Version Build Status

Simple OAuth2 is a Node.js client library for the OAuth 2.0 authorization framework. OAuth 2.0 is the industry-standard protocol for authorization, enabling third-party applications to obtain limited access to an HTTP service, either on behalf of a resource owner or by allowing the third-party application to obtain access on its own behalf.

Table of Contents

Requirements

Version Node support
5.x Node 14.x or higher
6.x (Development) Node 16.x or higher

Older node versions are unsupported.

Usage

Install the client library using npm:

npm install --save simple-oauth2

With a minimal configuration, create a client instance of any supported grant type.

const config = {
  client: {
    id: '<client-id>',
    secret: '<client-secret>'
  },
  auth: {
    tokenHost: 'https://api.oauth.com'
  }
};

const { ClientCredentials, ResourceOwnerPassword, AuthorizationCode } = require('simple-oauth2');

For a complete reference of configuration options, see the API Options

Supported Grant Types

Depending on your use-case, any of the following supported grant types may be useful:

Authorization Code Grant

The Authorization Code grant type is used by confidential and public clients to exchange an authorization code for an access token. After the user returns to the client via the redirect URL, the application will get the authorization code from the URL and use it to request an access token.

async function run() {
  const client = new AuthorizationCode(config);

  const authorizationUri = client.authorizeURL({
    redirect_uri: 'http://localhost:3000/callback',
    scope: '<scope>',
    state: '<state>',

    customParam: 'foo', // non-standard oauth params may be passed as well
  });

  // Redirect example using Express (see http://expressjs.com/api.html#res.redirect)
  res.redirect(authorizationUri);

  const tokenParams = {
    code: '<code>',
    redirect_uri: 'http://localhost:3000/callback',
    scope: '<scope>',
  };

  try {
    const accessToken = await client.getToken(tokenParams);
  } catch (error) {
    console.log('Access Token Error', error.message);
  }
}

run();

See the API reference for a complete reference of available options or any of our available examples at the example folder.

Resource Owner Password Credentials Grant

The Resource Owner Password Credentials grant type is a way to exchange a user's credentials for an access token. Because the client application has to collect the user's password and send it to the authorization server, it is not recommended that this grant be used at all anymore.

async function run() {
  const client = new ResourceOwnerPassword(config);

  const tokenParams = {
    username: 'username',
    password: 'password',
    scope: '<scope>',
  };

  try {
    const accessToken = await client.getToken(tokenParams);
  } catch (error) {
    console.log('Access Token Error', error.message);
  }
}

run();

See the API reference for a complete reference of available options.

Client Credentials Grant

The Client Credentials grant type is used by clients to obtain an access token outside of the context of a user. This is typically used by clients to access resources about themselves rather than to access a user's resources.

async function run() {
  const client = new ClientCredentials(config);

  const tokenParams = {
    scope: '<scope>',
  };

  try {
    const accessToken = await client.getToken(tokenParams);
  } catch (error) {
    console.log('Access Token error', error.message);
  }
}

run();

See the API reference for a complete reference of available options.

Access Token

On completion of any supported grant type an access token will be obtained. A list of supported operations can be found below.

Refresh an access token

On long lived applications, it is often necessary to refresh access tokens. In such scenarios the access token is usually persisted in an external database by first serializing it.

async function run() {
  const accessTokenJSONString = JSON.stringify(accessToken);

  await persistAccessTokenJSON(accessTokenJSONString);
}

run();

By the time we need to refresh the persistent access token, we can get back an AccessToken instance by using the client's .createToken method.

async function run() {
  const accessTokenJSONString = await getPersistedAccessTokenJSON();

  let accessToken = client.createToken(JSON.parse(accessTokenJSONString));
}

run();

Once we have determined the access token needs refreshing with the .expired() method, we can finally refresh it with a .refresh() method call.

async function run() {
  if (accessToken.expired()) {
    try {
      const refreshParams = {
        scope: '<scope>',
      };

      accessToken = await accessToken.refresh(refreshParams);
    } catch (error) {
      console.log('Error refreshing access token: ', error.message);
    }
  }
}

run();

The .expired() helper is useful for knowing when a token has definitively expired. However, there is a common race condition when tokens are near expiring. If an OAuth 2.0 token is issued with a expires_in property (as opposed to an expires_at property), there can be discrepancies between the time the OAuth 2.0 server issues the access token and when it is received.

These come down to factors such as network and processing latency and can be worked around by preemptively refreshing the access token:

async function run() {
  const EXPIRATION_WINDOW_IN_SECONDS = 300; // Window of time before the actual expiration to refresh the token

  if (accessToken.expired(EXPIRATION_WINDOW_IN_SECONDS)) {
    try {
      accessToken = await accessToken.refresh();
    } catch (error) {
      console.log('Error refreshing access token: ', error.message);
    }
  }
}

run();

Warning: Tokens obtained with the Client Credentials grant may not be refreshed. Fetch a new token when it's expired.

See the API reference for a complete reference of available options.

Revoke an access or refresh token

When you've done with the token or you want to log out, you can revoke both access and refresh tokens.

async function run() {
  try {
    await accessToken.revoke('access_token');
    await accessToken.revoke('refresh_token');
  } catch (error) {
    console.log('Error revoking token: ', error.message);
  }
}

run();

As a convenience method, you can also revoke both tokens in a single call:

async function run() {
  try {
    // Revokes both tokens, refresh token is only revoked if the access_token is properly revoked
    await accessToken.revokeAll();
  } catch (error) {
    console.log('Error revoking token: ', error.message);
  }
}

run();

See the API reference for a complete reference of available options.

Errors

Whenever a client or server error is produced, a boom error is thrown by the library. As such any boom error property is available, but the exact information may vary according to the type of error.

async function run() {
  const client = new ClientCredentials(config);

  try {
    await client.getToken();
  } catch(error) {
    console.log(error.output);
  }
}

run();

// { statusCode: 401,
//   payload:
//    { statusCode: 401,
//      error: 'Unauthorized',
//      message: 'Response Error: 401 Unauthorized' },
//   headers: {} }

Debugging the module

This module uses the debug module to help on error diagnosis. Use the following environment variable to help in your debug journey:

DEBUG=*simple-oauth2*

Contributing

See CONTRIBUTING

Authors

Andrea Reginato

Contributors

Special thanks to the following people for submitting patches.

Changelog

See CHANGELOG

License

Simple OAuth 2.0 is licensed under the Apache License, Version 2.0

Thanks to Open Source

Simple OAuth 2.0 come to life thanks to the work I've made in Lelylan, an open source microservices architecture for the Internet of Things. If this project helped you in any way, think about giving us a star on Github.

changelog

Changelog

5.1.0

Fixes

  • #434 Preserve existing refresh token when refreshed token doesn't contain a new refresh token

5.0.1

Fixes

  • #440 Update @hapi/hoek to v11.x to avoid URL clonning issues

Documentation

  • #430 Update authorizeURL docs with a custom param example
  • #421 Fix typo on API.md
  • #422 Improve jsdocs
  • #409 Remove build badge

5.0.0

New features

  • #332 Preserve query params on authorizePath on authorizeURL method

Maintainance

  • #341 Rewrite integration tests
  • #382 Update eslint parser dependencies
  • #390 Add Node 16 to test matrix
  • #404 Update ava to v4.x
  • #405 Update @hapi/hoek to v10.0.0
  • #406 Update @hapi/wreck to v18.0.0
  • #407 Update @hapi/boom to v10.0.0
  • #407 Update doctoc to v2.x
  • #408 Add Node 18 to test matrix

Documentation

  • #403 Add LinkedIn example

Breaking changes

  • 340 Accept only options available per grant type
  • #403 Drop support for Node 12. Require at least Node 14
  • #406 Disable redirects by default

4.3.0

New features

  • #387 Add support to configure refreshPath

Maintainance

  • #386 Update eslint v8
  • #379 Use c8 to collect code coverage
  • #356 Update development dependencies
  • #355 Add package support info

Documentation

  • #385 Documentation update
  • #380 Deprecate simple-oauth2 v3
  • #373 Documentation update

4.2.0

Improvements

  • #354 Add support for custom http options to access token refresh and revoke operations

Maintainance

  • #329 Documentation updates for persistent access token refresh
  • #330 Upgrade module to use eslint v7
  • #331 Internal module reorganization
  • #333 Add template for issues
  • #341 Segregate integration tests by responsability area
  • #352 Use Node 14 as default runtime version for development. Document support matrix
  • #353 Use joi instead of the deprecated @hapi/joi module

4.1.0

Improvements

  • #328 Add support to refresh persistent access tokens

Maintainance

  • #326 Remove usage of date-fns production dependency
  • #325 Setup volta instead of nvm to handle node versions
  • #322 Update acorn version in package-lock file

4.0.0

Breaking changes

  • #292 #313 Require at least Node 12
  • #292 Use private class fields for non-public API's
  • #292 Access token .token property is now frozen
  • #318 New public API separating each grant type into it's own submodule
  • #321 Rename resource owner credentials module to be accurate

Maintainance

  • #292 Upgrade @hapi/hoek to v9 (requires Node 12)
  • #292 Upgrade @hapi/joi to v17 (requires Node 12)
  • #292 Upgrade @hapi/wreck to v17 (requires Node 12)
  • #311 Upgrade nock dev library to v12
  • #319 Add Node 14 to test matrix

Documentation

  • #314 Add client credentials token refresh disclaimer
  • #317 Fix output documentation for boom errors
  • #320 Add complete reference documentation

3.4.0

Improvements

  • #301 Refactor module schema to reuse constants across the codebase
  • #302 Extract access token parsing functionality from token class
  • #310 #312 Change how date-fns is imported do make it compatible with webpack

Maintainance

  • #303 #304 Add more references to API documentation on library README
  • #306 Add documentation for URL resolution on host/paths configurations
  • #307 Replace travis CI with github actions

3.3.0

  • #299 Add support to verify for token expiration with a custom expiration window
  • #300 Add support to set the header credentials' encoding mode with options.credentialsEncodingMode.

3.2.0

New features

  • #298 Add support for custom scope separator by using options.scopeSeparator configuration

Improvements

  • #290 Valid token presence is verified on access token creation
  • #290 Valid tokenType presence is verified on .revoke calls

Maintainance

  • #289 Remove dev lodash library from tests
  • #285 Update ava test runner to v3
  • #287 Update chance-access-token dev library to v2
  • #288 Update nyc instrumentation dev library to v15
  • #297 Add tests for empty credentials support
  • #291 Improve library documentation. Separate API reference from main documentation

3.1.0

New features

  • #277 Add support to parse access tokens's expire_at property as UNIX timestamps

3.0.1

Publishing changes

  • #273 Deprecate unsupported library versions

3.0.0

Breaking changes

  • #260 Use @hapi/wreck v15. This version changes how a baseUrl is resolved against a path, affecting how auth.tokenHost, auth.tokenPath, auth.authorizeHost and auth.authorizePath are resolved when using the .getToken methods. See @hapi/wreck breaking changes to better understand potential issues that may arise.

  • #260 Use new Node.js WHATWG URL api instead of the legacy url module. This change affects how auth.authorizeHost and auth.authorizePath are resolved when using the authorizationCode.authorizeURL method.

  • #256 Users can override the grant_type parameter when performing a token exchange throught the .getToken method. Useful in cases where the auth server uses a value different from the standard.

  • #256 Token exchange methods no longer mutate provided arguments

  • #255 Follow up to 20 redirects by default
  • #200 #256 Change default multiple scope encoding from using comma to spaces on all token exchange methods
  • #88 Change JSON response parsing mode from smart to strict. Since the OAuth2 specification indicates only JSON responses are valid, any non-JSON response throws an error instead of resolving into a Buffer. Use http.json = true to restore the previous behavior.

New features

  • #270 All token exchange methods now accept an optional argument to override non-essential http options or read parsing options.

  • #268 All token exchange methods can be called without arguments

  • #263 Use @hapi/joi v16. No breaking changes are expected.

2.5.2

Publishing changes

  • #262 Use files package option instead of .npmignore

Documentation improvements

  • #267 Better document encoding of values for the token exchange process

2.5.1

New examples

  • #249 Add dropbox usage example

Development dependencies upgradess

  • #254 Upgrade codebase to eslint v6 and airbnb-base-eslint configuration v14
  • #253 Upgrade nock to v11
  • #252 Use ava instead of mocha as test runner
  • #252 Use ava built-in assertions library instead of chai

2.5.0

Dependencies upgrades

  • #250 Upgrade date-fns library to v2

2.4.0

Dependencies upgrades

  • #235 Upgrade Joi version to v15 (@hapi/joi)

Development dependencies updates

  • #244 Upgrade mocha test runner to v6
  • #244 Upgrade nyc to v14
  • #244 Upgrade development dependencies to latest version available

2.3.0

Dependencies upgrades

  • #242 Upgrade debug dependency to v4

2.2.1

  • Fix Joi schema missusage

2.2.0

  • Fix access token expiration properties omission

2.1.0 (Not published)

  • Ignore access token date properties when not available

v2.0.1

  • Add support to revoke accessToken and refreshToken in a single call with revokeAll

v2.0.0

  • Replace internal request library to wreck
  • Replace bluebird with native promise implementation
  • Replace callback interface with async/await
  • Improve integration tests coverage

v1.5.1

  • Add support to specify scopes as array in getToken method
  • Add support to empty strings and visual ASCII characters on clientId/clientSecret options

v1.5.0

  • Update debug dependency
  • Add support to encode the authorization headers

v1.4.0

  • Update dependencies
  • 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.
  • Update code to comply with more linter rules.
  • Fixed examples in README to return on error.
  • Added a working example example.
  • Clone params and configuration passed
  • Changed public api to, to make it consistent. Changed shortcut names to full names.
  • Changed public api to allow different sites for /authorize and /tokens
  • Added strict schema validation to module options.
  • Does not override expires_at property if passed into accessToken.create.

v0.8.0 (1 August 2016)

  • Upgraded code to strict mode.
  • Upgraded all the code base to es6.
  • Updated linter settings to meet the new es6 code requirements.
  • Fixed shared value for access token, causing tokens to be overriding.

v0.7.0 (22 April 2016)

  • Replaced internal logger by the debug module logger.
  • Fixed some project metadata.

v0.6.0 (04 April 2016)

  • Added optional sending support to the body auth params.
  • Updated license information.
  • Updated main dependencies version.
  • Fixed leaked token when a refresh token was used.

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.
  • Added support for passing arguments to the refresh token action.
  • Added project badges.
  • Code general cleanup and applied code styleguide.
  • Created CONTRIBUTING guides! (Separated from README)
  • Fixed bug, which resolved promises even if the token wasn´t retrieved. #64

v0.3.0 (29 November 2015)

  • Better documentation!
  • Added support for promise based API

v0.2.1 (17 October 2014)

  • Adds revocation token method
  • Not using headers if access_token is defined as a part of the URL.
  • Changes from Pascal Case to Camel Case in the API.
  • Adds Bearer Header for requests.

v0.1.7 (16 May 2013)

  • Now compatible with Github

v0.1.6 (24 Jan 2013)

  • Updated name convention on using simple oauth2 configuration block.

v0.1.5 (24 Jan 2013)

  • Token expiration is now dinamically defined through the expires_in field returned with the access token from the OAuth2 server

v0.1.4 (22 Jan 2013)

  • Fixed missing Basic Auth that somehow is not created from the request library

v0.1.3 (22 Jan 2013)

  • Fixed bug on AccessToken#expired() as it had the inverse logic
  • AccessToken#refresh() now returns an AccessToken object

v0.1.2 (22 Jan 2013)

  • Updated documentation

v0.1.1 (21 Jan 2013)

  • Added Password credentials flow

v0.1.0 (21 Jan 2013)

  • First version Node client for OAuth2