npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@instadukan/grant

v5.1.1

Published

OAuth Proxy

Downloads

2

Readme

Grant

npm-version travis-ci coveralls-status

OAuth Proxy

180+ Supported Providers / OAuth Playground

23andme | 500px | acton | acuityscheduling | aha | amazon | angellist | arcgis | asana | assembla | atlassian | auth0 | authentiq | aweber | axosoft | baidu | basecamp | battlenet | beatport | bitbucket | bitly | box | buffer | campaignmonitor | cas | cheddar | clio | cognito | coinbase | concur | constantcontact | coursera | dailymotion | deezer | delivery | deputy | deviantart | digitalocean | discogs | discord | disqus | docusign | dribbble | dropbox | ebay | echosign | ecwid | edmodo | egnyte | etsy | eventbrite | evernote | eyeem | facebook | familysearch | feedly | fitbit | flattr | flickr | flowdock | formstack | foursquare | freeagent | freelancer | freshbooks | fusionauth | geeklist | genius | getbase | getpocket | gitbook | github | gitlab | gitter | goodreads | google | groove | gumroad | harvest | hellosign | heroku | homeaway | hootsuite | ibm | iconfinder | idme | idonethis | imgur | infusionsoft | instagram | intuit | jamendo | jumplead | kakao | line | linkedin | live | livechat | logingov | lyft | mailchimp | mailup | mailxpert | mapmyfitness | mastodon | medium | meetup | mention | microsoft | mixcloud | mixer | moxtra | myob | naver | nest | nokotime | nylas | okta | onelogin | openstreetmap | optimizely | patreon | paypal | phantauth | pinterest | plurk | podio | producthunt | projectplace | pushbullet | qq | ravelry | redbooth | reddit | runkeeper | salesforce | shoeboxed | shopify | skyrock | slack | slice | smartsheet | smugmug | snapchat | socialpilot | socrata | soundcloud | spotify | square | stackexchange | stocktwits | stormz | strava | stripe | surveygizmo | surveymonkey | thingiverse | ticketbud | timelyapp | todoist | trakt | traxo | trello | tripit | tumblr | twitch | twitter | typeform | uber | underarmour | unsplash | upwork | uservoice | vend | venmo | verticalresponse | viadeo | vimeo | visualstudio | vk | wechat | weekdone | weibo | withings | wordpress | wrike | xero | xing | yahoo | yammer | yandex | zeit | zendesk | zoom

Table of Contents

Migration Guide: from v4 to v5


Handlers

Express

npm install grant-express
var express = require('express')
var session = require('express-session')
var grant = require('grant-express')

var app = express()
// REQUIRED: any session store - see /examples/handler-express
app.use(session({secret: 'grant'}))
// mount grant
app.use(grant({/*configuration - see below*/}))

Koa

npm install grant-koa
var Koa = require('koa')
var session = require('koa-session')
var grant = require('grant-koa')

var app = new Koa()
// REQUIRED: any session store - see /examples/handler-koa
app.keys = ['grant']
app.use(session(app))
// mount grant
app.use(grant({/*configuration - see below*/}))

Hapi

npm install grant-hapi
var Hapi = require('hapi')
var yar = require('yar')
var grant = require('grant-hapi')

var server = new Hapi.Server()
server.register([
  // REQUIRED: any session store - see /examples/handler-hapi
  {plugin: yar, options: {cookieOptions: {password: 'grant', isSecure: false}}},
  // mount grant
  {plugin: grant(), options: {/*configuration - see below*/}}
])

Configuration

Configuration: Basics

{
  "defaults": {
    "origin": "http://localhost:3000",
    "transport": "session",
    "state": true
  },
  "google": {
    "key": "...",
    "secret": "...",
    "scope": ["openid"],
    "nonce": true,
    "custom_params": {"access_type": "offline"},
    "callback": "/hello"
  },
  "twitter": {
    "key": "...",
    "secret": "...",
    "callback": "/hi"
  }
}
  • defaults - default configuration for all providers
    • origin - where your client server can be reached http://localhost:3000 | https://site.com ...
    • transport - a transport to use to deliver the response data in your callback route
    • state - generate random state string on each authorization attempt
  • provider - any supported provider google | twitter ...
    • key - consumer_key or client_id of your OAuth app
    • secret - consumer_secret or client_secret of your OAuth app
    • scope - array of OAuth scopes to request
    • nonce - generate random nonce string on each authorization attempt (OpenID Connect only)
    • custom_params - custom authorization parameters
    • callback - relative route or absolute URL to receive the response data /hello | https://site.com/hey ...

Configuration: Description

Key | Location | Description :-| :-: | :- Authorization Server | request_url | oauth.json | OAuth 1.0a only, first step authorize_url | oauth.json | OAuth 2.0 first step, OAuth 1.0a second step access_url | oauth.json | OAuth 2.0 second step, OAuth 1.0a third step oauth | oauth.json | OAuth version number scope_delimiter | oauth.json | String delimiter used for concatenating multiple scopes token_endpoint_auth_method | [provider] | Authentication method for the token endpoint token_endpoint_auth_signing_alg | [provider] | Signing algorithm for the token endpoint Client Server | origin | defaults | Where your server and Grant can be reached prefix | defaults | Path prefix for the Grant internal routes state | defaults | Random state string for OAuth2 nonce | defaults | Random nonce string for OpenID Connect pkce | defaults | PKCE support response | defaults | Response data to receive transport | defaults | A way to deliver the response data callback | [provider] | Relative or absolute URL to receive the response data overrides | [provider] | Static configuration overrides for a provider dynamic | [provider] | Configuration keys that can be overridden dynamically over HTTP Client App | key client_id consumer_key | [provider] | The client_id or consumer_key of your OAuth app secret client_secret consumer_secret | [provider] | The client_secret or consumer_secret of your OAuth app scope | [provider] | List of scopes to request custom_params | [provider] | Custom authorization parameters and their values subdomain | [provider] | String to embed into the authorization server URLs public_key | [provider] | Public PEM or JWK private_key | [provider] | Private PEM or JWK redirect_uri | generated | Absolute redirect URL of the OAuth app Grant | name | generated | Provider's name [provider] | generated | Provider's name as key profile_url | profile.json | User profile URL

Configuration: Values

Key | Location | Value :- | :-: | :-: Authorization Server | request_url | oauth.json | 'https://api.twitter.com/oauth/request_token' authorize_url | oauth.json | 'https://api.twitter.com/oauth/authenticate' access_url | oauth.json | 'https://api.twitter.com/oauth/access_token' oauth | oauth.json | 2 1 scope_delimiter | oauth.json | ',' ' ' token_endpoint_auth_method | [provider] | 'client_secret_post' 'client_secret_basic' 'private_key_jwt' token_endpoint_auth_signing_alg | [provider] | 'RS256' 'ES256' 'PS256' Client Server | origin | defaults | 'http://localhost:3000' https://site.com prefix | defaults | '/connect' /oauth '' state | defaults | true nonce | defaults | true pkce | defaults | true response | defaults | ['tokens', 'raw', 'jwt', 'profile'] transport | defaults | 'querystring' 'session' 'state' callback | [provider] | '/hello' 'https://site.com/hey' overrides | [provider] | {something: {scope: ['..']}} dynamic | [provider] | ['scope', 'subdomain'] Client App | key client_id consumer_key | [provider] | '123' secret client_secret consumer_secret | [provider] | '123' scope | [provider] | ['openid', '..'] custom_params | [provider] | {access_type: 'offline'} subdomain | [provider] | 'myorg' public_key | [provider] | '..PEM..' '{..JWK..}' private_key | [provider] | '..PEM..' '{..JWK..}' redirect_uri |generated | 'http://localhost:3000/connect/twitter/callback' Grant | name |generated | name: 'twitter' [provider] |generated | twitter: true profile_url | profile.json | 'https://api.twitter.com/1.1/users/show.json'

Configuration: Scopes

Grant relies on configuration gathered from 6 different places:

  1. The first place Grant looks for configuration is the built-in oauth.json file located in the config folder.

  2. The second place Grant looks for configuration is the defaults key, specified in the user's configuration. These defaults are applied for every provider in the user's configuration.

  3. The third place for configuration is the provider itself. All providers in the user's configuration inherit every option defined for them in the oauth.json file, and all options defined inside the defaults key. Having oauth.json file and a defaults configuration is only a convenience. You can define all available options directly for a provider.

  4. The fourth place for configuration are the provider's overrides. The static overrides inherit their parent provider, essentially creating new provider of the same type.

  5. The fifth place for configuration is the dynamic state override. The request/response lifecycle state of your HTTP framework of choice can be used to dynamically override configuration.

  6. The sixth place for configuration, that potentially can override all of the above, and make all of the above optional, is the dynamic HTTP override.


Connect

Connect: Origin

{
  "defaults": {
    "origin": "http://localhost:3000"
  }
}

The origin is where your client server is listening to and can be reached.

You login by navigating to the /connect/:provider route where :provider is a key in your configuration, usually one of the officially supported ones, but you can define your own as well. Additionally you can login through a static override defined for that provider by navigating to the /connect/:provider/:override? route.

Connect: Prefix

By default Grant operates on the following two routes:

/connect/:provider/:override?
/connect/:provider/callback

However, the default /connect prefix can be configured:

{
  "defaults": {
    "origin": "http://localhost:3000",
    "prefix": "/oauth"
  }
}

Connect: Redirect URI

The redirect_uri of your OAuth app should follow this format:

[origin][prefix]/[provider]/callback

Where origin and prefix have to match the ones set in your configuration, and provider is a provider key found in your configuration.

For example: http://localhost:3000/connect/google/callback

This redirect URI is used internally by Grant. Depending on the transport being used you will receive the response data in the callback route or absolute URL configured for that provider.

Connect: Custom Parameters

Some providers may employ custom authorization parameters, that you can configure using the custom_params option:

{
  "google": {
    "custom_params": {"access_type": "offline", "prompt": "consent"}
  },
  "reddit": {
    "custom_params": {"duration": "permanent"}
  },
  "trello": {
    "custom_params": {"name": "my app", "expiration": "never"}
  }
}

Connect: OpenID Connect

The openid scope is required, and the nonce is optional but recommended:

{
  "google": {
    "scope": ["openid"],
    "nonce": true
  }
}

Grant does not verify the signature of the returned id_token by default.

However, the following two claims of the id_token are being validated:

  1. aud - is the token intended for my OAuth app?
  2. nonce - does it tie to a request of my own?

Connect: PKCE

PKCE can be enabled for all providers or for a specific provider only:

{
  "google": {
    "pkce": true
  }
}

Providers that do not support PKCE will ignore the additional parameters being sent.

Connect: Static Overrides

Provider sub configurations can be configured using the overrides key:

{
  "github": {
    "key": "...", "secret": "...",
    "scope": ["public_repo"],
    "callback": "/hello",
    "overrides": {
      "notifications": {
        "key": "...", "secret": "...",
        "scope": ["notifications"]
      },
      "all": {
        "scope": ["repo", "gist", "user"],
        "callback": "/hey"
      }
    }
  }
}

Navigate to:

  • /connect/github to request the public_repo scope
  • /connect/github/notifications to request the notifications scope using another OAuth App (key and secret)
  • /connect/github/all to request a bunch of scopes and also receive the response data in another callback route

Callback

Callback: Data

By default the response data is returned in your callback route or absolute URL encoded as querystring.

Depending on the transport being used the response data can also be returned in the session or in the state object.

The amount of the returned data can also be controlled using the response option.

OAuth 2.0

{
  id_token: '...',
  access_token: '...',
  refresh_token: '...',
  raw: {
    id_token: '...',
    access_token: '...',
    refresh_token: '...',
    some: 'other data'
  }
}

The refresh_token is optional. The id_token is returned only for OpenID Connect providers requesting the openid scope.

OAuth 1.0a

{
  access_token: '...',
  access_secret: '...',
  raw: {
    oauth_token: '...',
    oauth_token_secret: '...',
    some: 'other data'
  }
}

Error

{
  error: {
    some: 'error data'
  }
}

Callback: Transport

querystring

By default Grant will encode the OAuth response data as querystring in your callback route or absolute URL:

{
  "github": {
    "callback": "https://site.com/hello"
  }
}

This is useful when using Grant as OAuth Proxy. However this final https://site.com/hello?access_token=... redirect can potentially leak private data in your server logs, especially when sitting behind reverse proxy.

session

For local callback routes the session transport is recommended:

{
  "defaults": {
    "transport": "session"
  },
  "github": {
    "callback": "/hello"
  }
}

This will make the OAuth response data available in the session object instead:

req.session.grant.response // Express
ctx.session.grant.response // Koa
req.yar.get('grant').response // Hapi

state

Lastly the request/response lifecycle state can be used as well:

{
  "defaults": {
    "transport": "state"
  }
}

In this case callback route is not needed, and it will be ignored if provided. The response data will be available in the request/response lifecycle state instead:

res.locals.grant.response // Express
ctx.state.grant.response // Koa
req.plugins.grant.response // Hapi

Callback: Response

By default Grant returns all of the available tokens and the raw response data returned from the Authorization server:

{
  id_token: '...',
  access_token: '...',
  refresh_token: '...',
  raw: {
    id_token: '...',
    access_token: '...',
    refresh_token: '...',
    some: 'other data'
  }
}

querystring

When using the querystring transport it might be a good idea to limit the response data:

{
  "defaults": {
    "response": ["tokens"]
  }
}

This will return only the tokens available, without the raw response data.

This is useful when using Grant as OAuth Proxy. Encoding potentially large amounts of data as querystring can lead to incompatibility issues with some servers and browsers, and generally is considered a bad practice.

session

Using the session transport is generally safer, but it also depends on the implementation of your session store.

In case your session store encodes the entire session in a cookie, not just the session ID, some servers may reject the HTTP request because of HTTP headers size being too big.

{
  "google": {
    "response": ["tokens"]
  }
}

This will return only the tokens available, without the raw response data.

jwt

Grant can also return even larger response data by including the decoded JWT for OpenID Connect providers that return id_token:

{
  "google": {
    "response": ["tokens", "raw", "jwt"]
  }
}

This will make the decoded JWT available in the response data:

{
  id_token: '...',
  access_token: '...',
  refresh_token: '...',
  raw: {
    id_token: '...',
    access_token: '...',
    refresh_token: '...',
    some: 'other data'
  }
  jwt: {id_token: {header: {}, payload: {}, signature: '...'}}
}

Make sure you include all response keys that you want returned when configuring the response data explicitly.

profile

Outside of the regular OAuth flow, Grant can request the user profile as well:

{
  "google": {
    "response": ["tokens", "profile"]
  }
}

Additionaly a profile key will be available in the response data:

{
  access_token: '...',
  refresh_token: '...',
  profile: {some: 'user data'}
}

The profile key contains either the raw response data returned from the user profile endpoint or an error message.

Not all of the supported providers have their profile_url set, and some of them might require custom parameters. Usually the user profile endpoint is only accessible if you request certain scopes.

Callback: Session

Grant uses session to persist state between HTTP redirects occurring during the OAuth flow. This session, however, was never meant to be used as persistent storage, even if that's totally possible.

Once you receive the response data, in your callback route you are free to destroy that session.

However, there are a few session keys returned in your callback route, that you may find useful:

Key | Availability | Description :-- | :-- | :-- provider | Always | The provider name this authorization was called for override | Depends on URL | The static override name used for this authorization dynamic | Depends on request type | The dynamic override configuration passed for this authorization state | OAuth 2.0 only | OAuth 2.0 state string that was generated nonce | OpenID Connect only | OpenID Connect nonce string that was generated code_verifier | PKCE only | The code verifier that was generated for PKCE request | OAuth 1.0a only | Data returned from the first request of the OAuth 1.0a flow response | Depends on transport used | The final response data


Dynamic Configuration

Dynamic: Instance

Every Grant instance have a config property attached to it:

var grant = Grant(require('./config'))
console.log(grant.config)

You can use the config property to alter the Grant's behavior during runtime without having to restart your server.

Keep in mind that this property contains the generated configuration that Grant uses internally, and changes to that configuration affects the entire Grant instance!

Dynamic: State

The request/response lifecycle state can be used to alter your configuration on every request:

res.locals.grant = {dynamic: {subdomain: 'usershop'}} // Express
ctx.state.grant = {dynamic: {subdomain: 'usershop'}} // Koa
request.plugins.grant = {dynamic: {subdomain: 'usershop'}} // Hapi

Note that the request/response lifecycle state is not controlled by the dynamic configuration, meaning that you can override any configuration key.

Any allowed dynamic configuration key sent through HTTP GET/POST request will override the identical one set in state.

Dynamic: HTTP

The dynamic configuration allows certain configuration keys to be set dynamically over HTTP GET/POST request.

For example shopify requires your shop name to be embedded into the OAuth URLs, so it makes sense to allow the subdomain configuration key to be set dynamically:

{
  "shopify": {
    "dynamic": ["subdomain"]
  }
}

Then you can have a web form in your website allowing the user to specify the shop name:

<form action="/connect/shopify" method="POST" accept-charset="utf-8">
  <input type="text" name="subdomain" value="" />
  <button>Login</button>
</form>

Keep in mind that when making a POST request to the /connect/:provider/:override? route you have to mount the body-parser middleware for Express and Koa before mounting Grant:

// express
var parser = require('body-parser')
app.use(parser.urlencoded({extended: true}))
app.use(grant(config))
// koa
var parser = require('koa-bodyparser')
app.use(parser())
app.use(grant(config))

Alternatively you can make a GET request to the /connect/:provider/:override? route:

https://awesome.com/connect/shopify?subdomain=usershop

Note that dynamic configuration sent over HTTP GET/POST request override any other configuration.

Dynamic: OAuth Proxy

In case you really want to, you can allow dynamic configuration override of every configuration key for a provider:

{
  "github": {
    "dynamic": true
  }
}

And the most extreme case is allowing even non preconfigured providers to be used dynamically:

{
  "defaults": {
    "dynamic": true
  }
}

Essentially Grant is a completely transparent OAuth Proxy.


Misc

Misc: Redirect URI

The origin and the prefix configuration is used to generate the correct redirect_uri that Grant expects:

{
  "defaults": {
    "origin": "https://mysite.com"
  },
  "google": {},
  "twitter": {}
}

The above configuration is identical to:

{
  "google": {
    "redirect_uri": "https://mysite.com/connect/google/callback"
  },
  "twitter": {
    "redirect_uri": "https://mysite.com/connect/twitter/callback"
  }
}

Note that explicitly specifying the redirect_uri overrides the one generated by default.

Misc: Custom Providers

You can define your own provider by adding a key for it in your configuration. In this case all of the required configuration keys have to be specified:

{
  "defaults": {
    "origin": "http://localhost:3000"
  },
  "awesome": {
    "authorize_url": "https://awesome.com/authorize",
    "access_url": "https://awesome.com/token",
    "oauth": 2,
    "key": "...",
    "secret": "...",
    "scope": ["read", "write"]
  }
}

Take a look at the oauth.json file on how various providers are being configured.

Misc: Meta Configuration

You can document your configuration by adding custom keys to it:

{
  "google": {
    "meta": {
      "app": "My Awesome OAuth App",
      "owner": "[email protected]",
      "url": "https://url/to/manage/oauth/app"
    }
  }
}

Note that meta is an arbitrary key, but it cannot be one of the reserved keys.

Misc: Alternative Require

All middlewares can be required directly from grant (each pair is identical):

// Express
var Grant = require('grant-express')
var Grant = require('grant').express()
// Koa
var Grant = require('grant-koa')
var Grant = require('grant').koa()
// Hapi
var Grant = require('grant-hapi')
var Grant = require('grant').hapi()

Misc: Alternative Instantiation

Grant can be instantiated with or without using the new keyword:

var Grant = require('grant-express|koa|hapi')
// without using `new`
var grant = Grant(config)
// identical to
var grant = new Grant(config)

Additionally Hapi accepts the configuration in two different ways:

server.register([{plugin: grant(config)}])
// identical to
server.register([{plugin: grant(), options: config}])

Misc: Path Prefix

You can mount Grant under specific path prefix:

app.use('/oauth', grant(config)) // Express
app.use(mount('/oauth', grant(config))) // Koa - using koa-mount
server.register([{routes: {prefix: '/oauth'}, plugin: grant(config)}]) // Hapi

In this case the prefix configuration should reflect that + any other path parts that you may have:

{
  "defaults": {
    "origin": "http://localhost:3000",
    "prefix": "/oauth/login"
  }
}

In this case you login by navigating to: http://localhost:3000/oauth/login/:provider

And the redirect_uri of your OAuth app should be http://localhost:3000/oauth/login/:provider/callback

Optionally you can prefix your callback routes as well:

{
  "github": {
    "callback": "/oauth/login/hello"
  }
}

Misc: OAuth Quirks

Subdomain URLs

Some providers have dynamic URLs containing bits of user information embedded into them. Inside the main oauth.json configuration file such URLs contain a [subdomain] token embedded in them.

The subdomain option can be used to specify your company name, server region etc:

"shopify": {
  "subdomain": "mycompany"
},
"battlenet": {
  "subdomain": "us"
}

Then Grant will generate the correct OAuth URLs:

"shopify": {
  "authorize_url": "https://mycompany.myshopify.com/admin/oauth/authorize",
  "access_url": "https://mycompany.myshopify.com/admin/oauth/access_token"
},
"battlenet": {
  "authorize_url": "https://us.battle.net/oauth/authorize",
  "access_url": "https://us.battle.net/oauth/token"
}

Alternatively you can override the entire authorize_url and access_url in your configuration.

Sandbox OAuth URLs

Some providers may have Sandbox URLs to use while developing your app. To use them just override the entire request_url, authorize_url and access_url in your configuration (notice the sandbox bits):

"paypal": {
  "authorize_url": "https://www.sandbox.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize",
  "access_url": "https://api.sandbox.paypal.com/v1/identity/openidconnect/tokenservice"
},
"evernote": {
  "request_url": "https://sandbox.evernote.com/oauth",
  "authorize_url": "https://sandbox.evernote.com/OAuth.action",
  "access_url": "https://sandbox.evernote.com/oauth"
}

Sandbox Redirect URI

Very rarely you may need to override the redirect_uri that Grant generates for you.

For example Feedly supports only http://localhost as redirect URI of their Sandbox OAuth app, and it won't allow the correct http://localhost/connect/feedly/callback URL:

"feedly": {
  "redirect_uri": "http://localhost"
}

In this case you'll have to redirect the user to the [origin][prefix]/[provider]/callback route that Grant uses to execute the last step of the OAuth flow:

var qs = require('querystring')

app.get('/', (req, res) => {
  if (process.env.NODE_ENV === 'development' &&
      req.session.grant &&
      req.session.grant.provider === 'feedly' &&
      req.query.code
  ) {
    res.redirect(`/connect/${req.session.grant.provider}/callback?${qs.stringify(req.query)}`)
  }
})

As usual you will receive the response data in your final callback route.

Provider Quirks

Ebay

Set the Redirect URI of your OAuth app as usual [origin][prefix]/[provider]/callback. Then Ebay will generate a special string called RuName (eBay Redirect URL name) that you need to set as redirect_uri in Grant:

"ebay": {
  "redirect_uri": "RUNAME"
}

Flickr, Freelancer, Optimizely

Some providers are using custom authorization parameter to pass the requested scopes - Flickr perms, Freelancer advanced_scopes, Optimizely scopes, but you can use the regular scope option instead:

"flickr": {
  "scope": ["write"]
},
"freelancer": {
  "scope": ["1", "2"]
},
"optimizely": {
  "scope": ["all"]
}

Mastodon

Mastodon requires the entire domain of your server to be embedded in the OAuth URLs. However you should use the subdomain option:

"mastodon": {
  "subdomain": "mastodon.cloud"
}

SurveyMonkey

Set your Mashery user name as key and your application key as api_key:

"surveymonkey": {
  "key": "MASHERY_USER_NAME",
  "secret": "CLIENT_SECRET",
  "custom_params": {"api_key": "CLIENT_ID"}
}

VisualStudio

Set your Client Secret as secret not the App Secret:

"visualstudio": {
  "key": "APP_ID",
  "secret": "CLIENT_SECRET instead of APP_SECRET"
}