<commit_before>
# Grant

[![npm-version]][npm] [![travis-ci]][travis] [![coveralls-status]][coveralls]


## 180+ Supported Providers / [OAuth Playground][grant-oauth]

[`23andme`](https://api.23andme.com) | [`500px`](https://github.com/500px/api-documentation) | [`acton`](https://developer.act-on.com) | [`acuityscheduling`](https://developers.acuityscheduling.com) | [`aha`](https://www.aha.io/api) | [`amazon`](https://login.amazon.com/documentation) | [`angellist`](https://angel.co/api) | [`arcgis`](https://developers.arcgis.com) | [`asana`](https://asana.com/developers) | [`assembla`](http://api-docs.assembla.cc/) | [`auth0`](https://auth0.com/docs) | [`authentiq`](https://www.authentiq.com/developers) | [`axosoft`](http://developer.axosoft.com) | [`baidu`](http://developer.baidu.com/ms/oauth) | [`basecamp`](https://github.com/basecamp/bcx-api) | [`battlenet`](https://dev.battle.net) | [`beatport`](https://oauth-api.beatport.com) | [`bitbucket`](https://developer.atlassian.com/bitbucket/api/2/reference/) | [`bitly`](https://dev.bitly.com) | [`box`](https://developer.box.com) | [`buffer`](https://dev.buffer.com) | [`campaignmonitor`](https://www.campaignmonitor.com/api) | [`cheddar`](https://cheddarapp.com/developer) | [`clio`](http://api-docs.clio.com) | [`coinbase`](https://developers.coinbase.com) | [`concur`](https://developer.concur.com) | [`constantcontact`](https://developer.constantcontact.com) | [`coursera`](https://building.coursera.org) | [`dailymile`](https://www.dailymile.com/api/documentation) | [`dailymotion`](https://developer.dailymotion.com) | [`deezer`](https://developers.deezer.com) | [`delivery`](https://developers.delivery.com) | [`deputy`](https://www.deputy.com/api-doc/) | [`deviantart`](https://www.deviantart.com/developers/) | [`digitalocean`](https://developers.digitalocean.com) | [`discogs`](https://www.discogs.com/developers/) | [`discord`](https://discordapp.com/developers/docs/intro) | [`disqus`](https://disqus.com/api/docs) | [`docusign`](https://docs.docusign.com) | [`dribbble`](https://developer.dribbble.com) | [`dropbox`](https://www.dropbox.com/developers) | [`ebay`](https://go.developer.ebay.com) | [`echosign`](https://secure.echosign.com/public/docs/restapi/v3) | [`ecwid`](https://developers.ecwid.com) | [`edmodo`](https://partnerships.edmodo.com) | [`egnyte`](https://developers.egnyte.com) | [`etsy`](https://www.etsy.com/developers) | [`eventbrite`](https://www.eventbrite.com/developer/v3/) | [`evernote`](https://dev.evernote.com) | [`everyplay`](https://developers.everyplay.com) | [`eyeem`](https://github.com/eyeem/Public-API) | [`facebook`](https://developers.facebook.com) | [`familysearch`](https://www.familysearch.org/developers/) | [`feedly`](https://developer.feedly.com) | [`fitbit`](https://dev.fitbit.com) | [`flattr`](http://developers.flattr.net) | [`flickr`](https://www.flickr.com/services) | [`flowdock`](https://www.flowdock.com/api) | [`fluidsurveys`](http://docs.fluidsurveys.com) | [`formstack`](https://developers.formstack.com) | [`foursquare`](https://developer.foursquare.com) | [`freeagent`](https://dev.freeagent.com) | [`freshbooks`](https://www.freshbooks.com/developers) | [`geeklist`](http://hackers.geekli.st) | [`genius`](https://docs.genius.com) | [`getbase`](https://developers.getbase.com) | [`getpocket`](https://getpocket.com/developer) | [`gitbook`](https://developer.gitbook.com) | [`github`](https://developer.github.com) | [`gitlab`](https://docs.gitlab.com/ce/api/) | [`gitter`](https://developer.gitter.im) | [`goodreads`](https://www.goodreads.com/api) | [`google`](https://developers.google.com) | [`groove`](https://www.groovehq.com/docs) | [`gumroad`](https://gumroad.com/api) | [`harvest`](https://help.getharvest.com/api-v2/) | [`hellosign`](https://www.hellosign.com/api) | [`heroku`](https://devcenter.heroku.com/categories/platform-api) | [`homeaway`](https://www.homeaway.com/platform) | [`iconfinder`](https://developer.iconfinder.com) | [`idme`](https://developer.id.me) | [`idonethis`](https://i-done-this.readme.io/docs) | [`imgur`](https://apidocs.imgur.com) | [`infusionsoft`](https://developer.infusionsoft.com) | [`instagram`](https://instagram.com/developer) | [`intuit`](https://developer.intuit.com) | [`jamendo`](https://devportal.jamendo.com/) | [`jawbone`](https://jawbone.com/up/developer) | [`jumplead`](https://developer.jumplead.com) | [`kakao`](https://developers.kakao.com) | [`letsfreckle`](https://developer.letsfreckle.com) | [`linkedin`](https://developer.linkedin.com) | [`live`](https://msdn.microsoft.com/en-us/library/hh243647.aspx) | [`lyft`](https://developer.lyft.com) | [`mailchimp`](https://developer.mailchimp.com) | [`mailup`](http://help.mailup.com/display/mailupapi/REST+API) | [`mapmyfitness`](https://developer.underarmour.com) | [`mastodon`](https://docs.joinmastodon.org/) | [`medium`](https://developers.medium.com) | [`meetup`](https://www.meetup.com/meetup_api/) | [`microsoft`](https://developer.microsoft.com/en-us/graph) | [`mixcloud`](https://www.mixcloud.com/developers) | [`mixer`](https://dev.mixer.com) | [`moves`](https://dev.moves-app.com) | [`moxtra`](https://developer.moxtra.com) | [`mydigipass`](https://developer.mydigipass.com) | [`myob`](http://developer.myob.com) | [`nest`](https://developers.nest.com) | [`nylas`](https://docs.nylas.com) | [`okta`](https://developer.okta.com/) | [`onelogin`](https://developers.onelogin.com) | [`openstreetmap`](https://wiki.openstreetmap.org/wiki/API_v0.6) | [`optimizely`](https://developers.optimizely.com) | [`patreon`](https://docs.patreon.com) | [`paypal`](https://developer.paypal.com) | [`pinterest`](https://developers.pinterest.com) | [`plurk`](https://www.plurk.com/API) | [`podio`](https://developers.podio.com) | [`producteev`](https://www.producteev.com/api/doc) | [`producthunt`](https://api.producthunt.com/v1/docs) | [`projectplace`](https://service.projectplace.com/apidocs) | [`pushbullet`](https://docs.pushbullet.com) | [`ravelry`](https://www.ravelry.com/api) | [`redbooth`](https://redbooth.com/api) | [`reddit`](https://www.reddit.com/dev/api) | [`runkeeper`](https://runkeeper.com/developer/healthgraph/) | [`salesforce`](https://developer.salesforce.com) | [`shoeboxed`](https://github.com/Shoeboxed/api) | [`shopify`](https://developers.shopify.com) | [`skyrock`](http://www.skyrock.com/developer) | [`slack`](https://api.slack.com) | [`slice`](https://developer.slice.com) | [`smartsheet`](https://smartsheet-platform.github.io/api-docs) | [`smugmug`](https://api.smugmug.com) | [`socialpilot`](https://developer.socialpilot.co) | [`socrata`](https://dev.socrata.com) | [`soundcloud`](https://developers.soundcloud.com) | [`spotify`](https://developer.spotify.com) | [`square`](https://squareup.com/developers) | [`stackexchange`](https://api.stackexchange.com) | [`stocktwits`](https://api.stocktwits.com/developers) | [`stormz`](https://developer.stormz.me) | [`strava`](https://developers.strava.com) | [`stripe`](https://stripe.com/docs) | [`surveygizmo`](https://apihelp.surveygizmo.com) | [`surveymonkey`](https://developer.surveymonkey.com) | [`thingiverse`](https://www.thingiverse.com/developers) | [`ticketbud`](https://api.ticketbud.com) | [`timelyapp`](https://dev.timelyapp.com) | [`todoist`](https://developer.todoist.com) | [`trakt`](https://docs.trakt.apiary.io) | [`traxo`](https://developer.traxo.com) | [`trello`](https://developers.trello.com) | [`tripit`](https://www.tripit.com/developer) | [`tumblr`](https://www.tumblr.com/docs/en/api/v2) | [`twitch`](https://dev.twitch.tv) | [`twitter`](https://developer.twitter.com) | [`typeform`](https://developer.typeform.com) | [`uber`](https://developer.uber.com) | [`underarmour`](https://developer.underarmour.com) | [`unsplash`](https://unsplash.com/documentation) | [`upwork`](https://developers.upwork.com) | [`uservoice`](https://developer.uservoice.com) | [`vend`](https://developers.vendhq.com) | [`venmo`](https://developers.braintreepayments.com/guides/venmo/overview/) | [`verticalresponse`](http://developers.verticalresponse.com) | [`viadeo`](https://partners.viadeo.com) | [`vimeo`](https://developer.vimeo.com) | [`visualstudio`](https://docs.microsoft.com/en-us/vsts/integrate/get-started/authentication/oauth?view=vsts) | [`vk`](https://vk.com/dev) | [`weekdone`](https://weekdone.com/developer) | [`weibo`](http://open.weibo.com) | [`withings`](http://developer.withings.com) | [`wordpress`](https://developer.wordpress.com) | [`wrike`](https://developers.wrike.com) | [`xero`](https://developer.xero.com) | [`xing`](https://dev.xing.com) | [`yahoo`](https://developer.yahoo.com) | [`yammer`](https://developer.yammer.com/docs) | [`yandex`](https://tech.yandex.com) | [`zendesk`](https://developer.zendesk.com)


## Table of Contents

- **[Providers][grant]**
- **Middleware**
  - [Express][express]
  - [Koa][koa]
  - [Hapi][hapi]
- **Configuration**
  - [Basics][configuration]
  - [Redirect URL][redirect-url]
  - [Reserved Routes][reserved-routes]
  - [Path Prefix][path-prefix]
  - [OpenID Connect][openid-connect]
  - [Custom Parameters][custom-parameters]
  - [Static Overrides][static-overrides]
  - [Dynamic Override][dynamic-override]
- **Advanced Configuration**
  - [Reserved Keys][reserved-keys]
  - [Custom Providers][custom-providers]
  - [Development Environments][development-environments]
  - [Subdomain][subdomain]
  - [Sandbox OAuth URLs][sandbox-oauth-urls]
  - [Sandbox Redirect URI][sandbox-redirect-uri]
  - [More Dynamic Overrides][more-dynamic-overrides]
  - [Quirks][quirks]
- **[Response Data][response-data]**
- **Misc**
  - [Alternative Require][alternative-require]
  - [Alternative Instantiation][alternative-instantiation]
  - [Programmatic Access][programmatic-access]
  - [Session vs Querystring][session-vs-querystring]
  - [Redirect URI][redirect-uri]
  - [Meta Configuration][meta-configuration]
  - [Get User Profile][get-user-profile]
- **[Examples][grant-examples]**
- **[Changelog][changelog]**


## Express

```bash
npm install grant-express
```

```js
var express = require('express')
var session = require('express-session')
var grant = require('grant-express')

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


## Koa

```bash
npm install grant-koa
```

```js
var Koa = require('koa')
var session = require('koa-session')
var mount = require('koa-mount')
var grant = require('grant-koa')

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


## Hapi

```bash
npm install grant-hapi
```

```js
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/hapi-session-stores
  {plugin: yar, options: {cookieOptions: {password: '<PASSWORD>', isSecure: false}}},
  // mount grant
  {plugin: grant(), options: {/*configuration - see below*/}}
])
```


## Configuration

```js
{
  "defaults": {
    "protocol": "http",
    "host": "localhost:3000",
    "callback": "/callback",
    "transport": "session",
    "state": true
  },
  "provider1": {
    "key": "...",
    "secret": "...",
    "scope": ["scope1", "scope2", ...],
    "callback": "/provider1/callback"
  },
  "provider2": {...},
  ...
}
```

- **defaults** - default configuration for all providers *(previously this option was called `server`)*
  - **protocol** - either `http` or `https`
  - **host** - your server's host name `localhost:3000` | `dummy.com:5000` | `mysite.com` ...
  - **path** - [path prefix][path-prefix] to use for the Grant middleware *(defaults to empty string if omitted)*
  - **callback** - common callback route for all providers in your config `/callback` | `/done` ...
  - **transport** - transport to use to deliver the [response data][response-data] in your final callback route `querystring` | `session` *(defaults to querystring if omitted)*
  - **state** - generate random state string on each authorization attempt `true` | `false` *(OAuth2 only, defaults to false if omitted)*
- **provider1** - any [supported provider][grant] `facebook` | `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
  - **callback** - specific callback route to use for this provider only `/callback` | `/done` ...
  - **custom_params** - custom [authorization parameters][custom-parameters]
  - **nonce** - generate random nonce string on each authorization attempt `true` | `false` *([OpenID Connect][openid-connect] only, defaults to false if omitted)*
  - **dynamic** - list of options that can be [overridden dynamically][dynamic-override] `['subdomain', 'scope']`

> Each provider can override any of the default options. The `defaults` key is completely optional.

> Additionally every provider can override any of the [reserved keys][reserved-keys], some of which are [predefined internally][oauth-config].


## Redirect URL

For `redirect` URL of your OAuth application you should **always** use this format:

```
[protocol]://[host]/connect/[provider]/callback
```

Where `protocol` and `host` should match the ones from which you initiate the OAuth flow, and `provider` is the provider's name from the list of [supported providers][grant].

This `redirect` URL is used internally by Grant. You will receive the [response data][response-data] from the OAuth flow inside the route specified in the `callback` key of your Grant configuration.

> See the [Path Prefix][path-prefix] section on how to configure the redirect URL when using the `path` configuration option.


## Reserved Routes

Grant operates on the following routes:

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


## Path Prefix

You can mount Grant under specific path prefix:

```js
// Express
app.use('/path/prefix', grant(config))
// Koa
app.use(mount('/path/prefix', grant(config)))
// Hapi
server.register([{routes: {prefix: '/path/prefix'}, plugin: grant(config)}])
```

In this case it is required to specify the path prefix using the `path` configuration option for the `defaults` key:

```js
{
  "defaults": {
    "protocol": "...",
    "host": "...",
    "path": "/path/prefix"
  }
}
```

Lastly that path prefix should be specified in your OAuth application's redirect URL as well:

```
[protocol]://[host][path]/connect/[provider]/callback
```

In case you want your callback routes prefixed, set them accordingly:

```js
{
  "facebook": {
    "callback": "/path/prefix/handle_facebook_callback"
  }
}
```


## OpenID Connect

The `nonce` option is **recommended** when requesting the `openid` scope:

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

Grant **does not** verify the signature of the returned `id_token` because that requires discovery, caching, and expiration of the provider's public keys.

However, Grant tries to decode the `id_token` and verifies the following two claims *(returns error respectively)*:

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

For convenience the [response data][response-data] contains the decoded `id_token`.

> Take a look at the OpenID Connect [example][openid-connect-example].

## Custom Parameters

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

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

> Alternatively any custom parameter that is not a [reserved key][reserved-keys], and is listed under the `custom_parameters` array for that [provider][oauth-config], can be defined along with the rest of the options.


## Static Overrides

You can add arbitrary `{object}` keys inside your provider's configuration to create sub configurations that override the *global* settings for that provider:

```js
// navigate to /connect/facebook
"facebook": {
  "key": "...",
  "secret": "...",
  // by default request publish permissions
  "scope": ["publish_actions", "publish_stream"],
  // set specific callback route on your server for this provider
  "callback": "/facebook/callback",
  // navigate to /connect/facebook/groups
  "groups": {
    // request only group permissions
    "scope": ["user_groups", "friends_groups"]
  },
  // navigate to /connect/facebook/pages
  "pages": {
    // request only page permissions
    "scope": ["manage_pages"],
    // additionally use specific callback route on your server for this override
    "callback": "/facebook_pages/callback"
  }
}
```

> The custom key names cannot be one of the [reserved keys][reserved-keys].


## Dynamic Override

In some cases you may want to allow the user to override certain parts of your configuration dynamically.

For example for `shopify` you have to embed the user's shop name into the OAuth URLs, so it makes sense to allow the [`subdomain` option][subdomain] to be overridden dynamically:

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

Then you can have a form on your website to allow the user to specify the shop name:

```html
<form action="/connect/shopify" method="post" accept-charset="utf-8">
  <input type="text" name="subdomain" value="" />
  <button>submit</button>
</form>
```

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

```js
// 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(mount(grant(config)))
```

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

```js
https://mywebsite.com/connect/shopify?subdomain=usershop
```


## Reserved Keys

List of all [reserved keys][reserved-json] and their typical location:

Key | Location | Description
:---| :--- | :---
request_url | [oauth.json][oauth-config] | OAuth1/step1
authorize_url | [oauth.json][oauth-config] | OAuth1/step2 or OAuth2/step1
access_url | [oauth.json][oauth-config] | OAuth1/step3 or OAuth2/step2
oauth | [oauth.json][oauth-config] | OAuth version number
scope_delimiter | [oauth.json][oauth-config] | string delimiter used for concatenating multiple scopes
custom_parameters | [oauth.json][oauth-config] | list of known custom authorization parameters
protocol, host, path | `defaults` | used to generate `redirect_uri`
transport | `defaults` | [transport][session-vs-querystring] to use to deliver the response data in your final `callback` route
state | `defaults` | toggle random `state` string generation for OAuth2
key | `[provider]` | OAuth app key, reserved aliaes: `consumer_key` and `client_id`
secret | `[provider]` | OAuth app secret, reserved aliases: `consumer_secret` and `client_secret`
scope | `[provider]` | list of scopes to request
custom_params | `[provider]` | custom authorization [parameters][custom-parameters] and their values
subdomain | `[provider]` | string to be [embedded][subdomain] in `request_url`, `authorize_url` and `access_url`
nonce | `[provider]` | toggle random `nonce` string generation for [OpenID Connect][openid-connect] providers
callback | `[provider]` | final callback route on your server to receive the [response data][response-data]
dynamic | `[provider]` | allow [dynamic override][dynamic-override] of configuration
name | generated | provider's [name][grant], used to generate `redirect_uri`
[provider] | generated | provider's [name][grant] as key
redirect_uri | generated | OAuth app [redirect URI][redirect-uri], generated using `protocol`, `host`, `path` and `name`
overrides | generated | all keys containing `{object}` value are extracted here as [static overrides][static-overrides]


## Custom Providers

In case you have a private OAuth provider that you don't want to be part of the [officially supported][grant] ones, you can define it in your configuration by adding a custom key for it.

In this case you have to specify all of the required provider keys by yourself:

```js
{
  "defaults": {
    "protocol": "https",
    "host": "mywebsite.com"
  },
  "mywebsite": {
    "authorize_url": "https://mywebsite.com/authorize",
    "access_url": "https://mywebsite.com/token",
    "oauth": 2,
    "key": "[CLIENT_ID]",
    "secret": "[CLIENT_SECRET]",
    "scope": ["read", "write"]
  }
}
```

> Refer to the Grant's [OAuth configuration][oauth-config] to see how various providers are configured.


## Development Environments

You can easily configure different development environments:

```js
{
  "development": {
    "defaults": {"protocol": "http", "host": "dummy.com:3000"},
    "facebook": {
      "key": "development OAuth app credentials",
      "secret": "development OAuth app credentials"
    },
    "twitter": {...}, ...
  },
  "staging": {
    "defaults": {"protocol": "https", "host": "staging.mywebsite.com"},
    "facebook": {
      "key": "staging OAuth app credentials",
      "secret": "staging OAuth app credentials"
    },
    "twitter": {...}, ...
  },
  "production": {
    "defaults": {"protocol": "https", "host": "mywebsite.com"},
    "facebook": {
      "key": "production OAuth app credentials",
      "secret": "production OAuth app credentials"
    },
    "twitter": {...}, ...
  }
}
```

Then you can pass the environment flag:

```bash
NODE_ENV=production node app.js
```

And use it in your application:

```js
var config = require('./config.json')
var grant = Grant(config[process.env.NODE_ENV || 'development'])
```


## Subdomain

Some providers have dynamic URLs containing bits of user information embedded in them.

The `subdomain` option can be used to specify your company name, server region or whatever else is required:

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

Then Grant will generate the correct OAuth URLs:

```js
"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 for testing. To use them just override the entire `request_url`, `authorize_url` and `access_url` in your configuration *(notice the `sandbox` bits)*:

```js
"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 default `redirect_uri` that Grant [generates for you][redirect-uri].

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

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

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

```js
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][response-data] in your final `callback` route.


## More Dynamic Overrides

In case you really want to, you can allow [dynamic overriding][dynamic-override] of every option for a provider:

```json
{
  "facebook": {
    "dynamic": true
  }
}
```

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

```json
{
  "defaults": {
    "dynamic": true
  }
}
```

> Essentially Grant is an [OAuth proxy][oauth-proxy-example].


## Quirks


#### Ebay

Set the redirect URL of your OAuth app as usual `[protocol]://[host]/connect/ebay/callback`. Then Ebay will generate a special string called *RuName (eBay Redirect URL name)* that you need to set as `redirect_uri` in Grant:

```js
"ebay": {
  "redirect_uri": "[RUNAME]"
}
```


#### Flickr, Optimizely

Flickr uses a custom authorization parameter to pass its scopes called `perms`, and Optimizely uses `scopes`. However you should use the regular `scope` option in your configuration:

```js
"flickr": {
  "scope": ["write"]
}
"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:

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


#### SurveyMonkey

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

```js
"surveymonkey": {
  "key": "[MASHERY_USER_NAME]",
  "secret": "[CLIENT_SECRET]",
  "api_key": "[CLIENT_ID]"
}
```


#### Fitbit, LinkedIn, ProjectPlace

Initially these were OAuth1 providers, so the `fitbit`, `linkedin` and `projectplace` names are used for that. To use their OAuth2 flow append `2` at the end of their names:

```js
"fitbit2": {
  // then navigate to /connect/fitbit2
},
"linkedin2": {
  // then navigate to /connect/linkedin2
},
"projectplace2": {
  // then navigate to /connect/projectplace2
}
```


#### VisualStudio

Set your Client Secret as `secret` not the App Secret:

```js
"visualstudio": {
  "key": "[APP_ID]",
  "secret": "[CLIENT_SECRET not APP_SECRET]"
}
```


## Response Data

The OAuth response data is returned as *querystring* in your **final** callback - the one you specify using the `callback` key in your Grant configuration.

Alternatively the response data can be returned inside the *session*, see the [configuration][configuration] section above and the [session transport][session-transport-example] example.


### OAuth2

The `access_token` and the `refresh_token` *(if present)* are accessible directly. The `id_token` *(OpenID Connect only)* contains the decoded JWT, and `raw` contains the raw response data:

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


### OAuth1

The `access_token` and the `access_secret` are accessible directly, `raw` contains the raw response data:

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


### Error

In case of an error, the `error` key will be populated with the raw error data:

```js
{
  error: {
    some: 'error data'
  }
}
```


## Alternative Require

Alternatively you can require the middlewares from `grant` *(each pair is identical)*:

```js
// 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()
```


## Alternative Instantiation

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

```js
var Grant = require('grant-express/koa/hapi')
var grant = Grant(config)
// identical to:
var grant = new Grant(config)
```

Additionally Hapi can accept the configuration in two different ways:

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


## Programmatic Access

Every Grant instance have a `config` property attached to it:

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

It contains the _generated_ configuration data that Grant uses internally.

> You can use the `config` property to alter the Grant's behavior during runtime.


## Session vs Querystring<commit_msg>Update docs<commit_after>
# Grant

[![npm-version]][npm] [![travis-ci]][travis] [![coveralls-status]][coveralls]


## 180+ Supported Providers / [OAuth Playground][grant-oauth]

[`23andme`](https://api.23andme.com) | [`500px`](https://github.com/500px/api-documentation) | [`acton`](https://developer.act-on.com) | [`acuityscheduling`](https://developers.acuityscheduling.com) | [`aha`](https://www.aha.io/api) | [`amazon`](https://login.amazon.com/documentation) | [`angellist`](https://angel.co/api) | [`arcgis`](https://developers.arcgis.com) | [`asana`](https://asana.com/developers) | [`assembla`](http://api-docs.assembla.cc/) | [`auth0`](https://auth0.com/docs) | [`authentiq`](https://www.authentiq.com/developers) | [`axosoft`](http://developer.axosoft.com) | [`baidu`](http://developer.baidu.com) | [`basecamp`](https://github.com/basecamp/bcx-api) | [`battlenet`](https://dev.battle.net) | [`beatport`](https://oauth-api.beatport.com) | [`bitbucket`](https://developer.atlassian.com/bitbucket/api/2/reference/) | [`bitly`](https://dev.bitly.com) | [`box`](https://developer.box.com) | [`buffer`](https://buffer.com/developers) | [`campaignmonitor`](https://www.campaignmonitor.com/api) | [`cheddar`](https://cheddarapp.com/developer) | [`clio`](http://api-docs.clio.com) | [`coinbase`](https://developers.coinbase.com) | [`concur`](https://developer.concur.com) | [`constantcontact`](https://developer.constantcontact.com) | [`coursera`](https://building.coursera.org) | [`dailymile`](https://www.dailymile.com/api/documentation) | [`dailymotion`](https://developer.dailymotion.com) | [`deezer`](https://developers.deezer.com) | [`delivery`](https://developers.delivery.com) | [`deputy`](https://www.deputy.com/api-doc/) | [`deviantart`](https://www.deviantart.com/developers/) | [`digitalocean`](https://developers.digitalocean.com) | [`discogs`](https://www.discogs.com/developers/) | [`discord`](https://discordapp.com/developers/docs/intro) | [`disqus`](https://disqus.com/api/docs) | [`docusign`](https://docs.docusign.com) | [`dribbble`](https://developer.dribbble.com) | [`dropbox`](https://www.dropbox.com/developers) | [`ebay`](https://developer.ebay.com) | [`echosign`](https://secure.echosign.com/public/docs/restapi/v3) | [`ecwid`](https://developers.ecwid.com) | [`edmodo`](https://partnerships.edmodo.com) | [`egnyte`](https://developers.egnyte.com) | [`etsy`](https://www.etsy.com/developers) | [`eventbrite`](https://www.eventbrite.com/developer/v3/) | [`evernote`](https://dev.evernote.com) | [`everyplay`](https://developers.everyplay.com) | [`eyeem`](https://github.com/eyeem/Public-API) | [`facebook`](https://developers.facebook.com) | [`familysearch`](https://www.familysearch.org/developers/) | [`feedly`](https://developer.feedly.com) | [`fitbit`](https://dev.fitbit.com) | [`flattr`](http://developers.flattr.net) | [`flickr`](https://www.flickr.com/services) | [`flowdock`](https://www.flowdock.com/api) | [`fluidsurveys`](http://docs.fluidsurveys.com) | [`formstack`](https://developers.formstack.com) | [`foursquare`](https://developer.foursquare.com) | [`freeagent`](https://dev.freeagent.com) | [`freshbooks`](https://www.freshbooks.com/developers) | [`geeklist`](http://hackers.geekli.st) | [`genius`](https://docs.genius.com) | [`getbase`](https://developers.getbase.com) | [`getpocket`](https://getpocket.com/developer) | [`gitbook`](https://developer.gitbook.com) | [`github`](https://developer.github.com) | [`gitlab`](https://docs.gitlab.com/ce/api/) | [`gitter`](https://developer.gitter.im) | [`goodreads`](https://www.goodreads.com/api) | [`google`](https://developers.google.com) | [`groove`](https://www.groovehq.com/docs) | [`gumroad`](https://gumroad.com/api) | [`harvest`](https://help.getharvest.com/api-v2/) | [`hellosign`](https://www.hellosign.com/api) | [`heroku`](https://devcenter.heroku.com/categories/platform-api) | [`homeaway`](https://www.homeaway.com/platform) | [`iconfinder`](https://developer.iconfinder.com) | [`idme`](https://developer.id.me) | [`idonethis`](https://i-done-this.readme.io/docs) | [`imgur`](https://apidocs.imgur.com) | [`infusionsoft`](https://developer.infusionsoft.com) | [`instagram`](https://instagram.com/developer) | [`intuit`](https://developer.intuit.com) | [`jamendo`](https://devportal.jamendo.com/) | [`jawbone`](https://jawbone.com/up/developer) | [`jumplead`](https://developer.jumplead.com) | [`kakao`](https://developers.kakao.com) | [`letsfreckle`](https://developer.letsfreckle.com) | [`linkedin`](https://developer.linkedin.com) | [`live`](https://msdn.microsoft.com/en-us/library/hh243647.aspx) | [`lyft`](https://developer.lyft.com) | [`mailchimp`](https://developer.mailchimp.com) | [`mailup`](http://help.mailup.com/display/mailupapi/REST+API) | [`mapmyfitness`](https://developer.underarmour.com) | [`mastodon`](https://docs.joinmastodon.org/) | [`medium`](https://developers.medium.com) | [`meetup`](https://www.meetup.com/meetup_api/) | [`microsoft`](https://developer.microsoft.com/en-us/graph) | [`mixcloud`](https://www.mixcloud.com/developers) | [`mixer`](https://dev.mixer.com) | [`moves`](https://dev.moves-app.com) | [`moxtra`](https://developer.moxtra.com) | [`mydigipass`](https://developer.mydigipass.com) | [`myob`](http://developer.myob.com) | [`nest`](https://developers.nest.com) | [`nylas`](https://docs.nylas.com) | [`okta`](https://developer.okta.com/) | [`onelogin`](https://developers.onelogin.com) | [`openstreetmap`](https://wiki.openstreetmap.org/wiki/API_v0.6) | [`optimizely`](https://developers.optimizely.com) | [`patreon`](https://docs.patreon.com) | [`paypal`](https://developer.paypal.com) | [`pinterest`](https://developers.pinterest.com) | [`plurk`](https://www.plurk.com/API) | [`podio`](https://developers.podio.com) | [`producteev`](https://www.producteev.com/api/doc) | [`producthunt`](https://api.producthunt.com/v1/docs) | [`projectplace`](https://service.projectplace.com/apidocs) | [`pushbullet`](https://docs.pushbullet.com) | [`ravelry`](https://www.ravelry.com/api) | [`redbooth`](https://redbooth.com/api) | [`reddit`](https://www.reddit.com/dev/api) | [`runkeeper`](https://runkeeper.com/developer/healthgraph/) | [`salesforce`](https://developer.salesforce.com) | [`shoeboxed`](https://github.com/Shoeboxed/api) | [`shopify`](https://developers.shopify.com) | [`skyrock`](http://www.skyrock.com/developer) | [`slack`](https://api.slack.com) | [`slice`](https://developer.slice.com) | [`smartsheet`](https://smartsheet-platform.github.io/api-docs) | [`smugmug`](https://api.smugmug.com) | [`socialpilot`](https://developer.socialpilot.co) | [`socrata`](https://dev.socrata.com) | [`soundcloud`](https://developers.soundcloud.com) | [`spotify`](https://developer.spotify.com) | [`square`](https://squareup.com/developers) | [`stackexchange`](https://api.stackexchange.com) | [`stocktwits`](https://api.stocktwits.com/developers) | [`stormz`](https://developer.stormz.me) | [`strava`](https://developers.strava.com) | [`stripe`](https://stripe.com/docs) | [`surveygizmo`](https://apihelp.surveygizmo.com) | [`surveymonkey`](https://developer.surveymonkey.com) | [`thingiverse`](https://www.thingiverse.com/developers) | [`ticketbud`](https://api.ticketbud.com) | [`timelyapp`](https://dev.timelyapp.com) | [`todoist`](https://developer.todoist.com) | [`trakt`](https://docs.trakt.apiary.io) | [`traxo`](https://developer.traxo.com) | [`trello`](https://developers.trello.com) | [`tripit`](https://www.tripit.com/developer) | [`tumblr`](https://www.tumblr.com/docs/en/api/v2) | [`twitch`](https://dev.twitch.tv) | [`twitter`](https://developer.twitter.com) | [`typeform`](https://developer.typeform.com) | [`uber`](https://developer.uber.com) | [`underarmour`](https://developer.underarmour.com) | [`unsplash`](https://unsplash.com/documentation) | [`upwork`](https://developers.upwork.com) | [`uservoice`](https://developer.uservoice.com) | [`vend`](https://developers.vendhq.com) | [`venmo`](https://developers.braintreepayments.com/guides/venmo/overview/) | [`verticalresponse`](http://developers.verticalresponse.com) | [`viadeo`](https://partners.viadeo.com) | [`vimeo`](https://developer.vimeo.com) | [`visualstudio`](https://docs.microsoft.com/en-us/vsts/integrate/get-started/authentication/oauth?view=vsts) | [`vk`](https://vk.com/dev) | [`weekdone`](https://weekdone.com/developer) | [`weibo`](http://open.weibo.com) | [`withings`](http://developer.withings.com) | [`wordpress`](https://developer.wordpress.com) | [`wrike`](https://developers.wrike.com) | [`xero`](https://developer.xero.com) | [`xing`](https://dev.xing.com) | [`yahoo`](https://developer.yahoo.com) | [`yammer`](https://developer.yammer.com/docs) | [`yandex`](https://tech.yandex.com) | [`zendesk`](https://developer.zendesk.com)


## Table of Contents

- **[Providers][grant]**
- **Middleware**
  - [Express][express]
  - [Koa][koa]
  - [Hapi][hapi]
- **Configuration**
  - [Basics][configuration]
  - [Redirect URL][redirect-url]
  - [Reserved Routes][reserved-routes]
  - [Path Prefix][path-prefix]
  - [OpenID Connect][openid-connect]
  - [Custom Parameters][custom-parameters]
  - [Static Overrides][static-overrides]
  - [Dynamic Override][dynamic-override]
- **Advanced Configuration**
  - [Reserved Keys][reserved-keys]
  - [Custom Providers][custom-providers]
  - [Development Environments][development-environments]
  - [Subdomain][subdomain]
  - [Sandbox OAuth URLs][sandbox-oauth-urls]
  - [Sandbox Redirect URI][sandbox-redirect-uri]
  - [More Dynamic Overrides][more-dynamic-overrides]
  - [Quirks][quirks]
- **[Response Data][response-data]**
- **Misc**
  - [Alternative Require][alternative-require]
  - [Alternative Instantiation][alternative-instantiation]
  - [Programmatic Access][programmatic-access]
  - [Session vs Querystring][session-vs-querystring]
  - [Redirect URI][redirect-uri]
  - [Meta Configuration][meta-configuration]
  - [Get User Profile][get-user-profile]
- **[Examples][grant-examples]**
- **[Changelog][changelog]**


## Express

```bash
npm install grant-express
```

```js
var express = require('express')
var session = require('express-session')
var grant = require('grant-express')

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


## Koa

```bash
npm install grant-koa
```

```js
var Koa = require('koa')
var session = require('koa-session')
var mount = require('koa-mount')
var grant = require('grant-koa')

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


## Hapi

```bash
npm install grant-hapi
```

```js
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/hapi-session-stores
  {plugin: yar, options: {cookieOptions: {password: '<PASSWORD>', isSecure: false}}},
  // mount grant
  {plugin: grant(), options: {/*configuration - see below*/}}
])
```


## Configuration

```js
{
  "defaults": {
    "protocol": "http",
    "host": "localhost:3000",
    "callback": "/callback",
    "transport": "session",
    "state": true
  },
  "provider1": {
    "key": "...",
    "secret": "...",
    "scope": ["scope1", "scope2", ...],
    "callback": "/provider1/callback"
  },
  "provider2": {...},
  ...
}
```

- **defaults** - default configuration for all providers *(previously this option was called `server`)*
  - **protocol** - either `http` or `https`
  - **host** - your server's host name `localhost:3000` | `dummy.com:5000` | `mysite.com` ...
  - **path** - [path prefix][path-prefix] to use for the Grant middleware *(defaults to empty string if omitted)*
  - **callback** - common callback route for all providers in your config `/callback` | `/done` ...
  - **transport** - transport to use to deliver the [response data][response-data] in your final callback route `querystring` | `session` *(defaults to querystring if omitted)*
  - **state** - generate random state string on each authorization attempt `true` | `false` *(OAuth2 only, defaults to false if omitted)*
- **provider1** - any [supported provider][grant] `facebook` | `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
  - **callback** - specific callback route to use for this provider only `/callback` | `/done` ...
  - **custom_params** - custom [authorization parameters][custom-parameters]
  - **nonce** - generate random nonce string on each authorization attempt `true` | `false` *([OpenID Connect][openid-connect] only, defaults to false if omitted)*
  - **dynamic** - list of options that can be [overridden dynamically][dynamic-override] `['subdomain', 'scope']`

> Each provider can override any of the default options. The `defaults` key is completely optional.

> Additionally every provider can override any of the [reserved keys][reserved-keys], some of which are [predefined internally][oauth-config].


## Redirect URL

For `redirect` URL of your OAuth application you should **always** use this format:

```
[protocol]://[host]/connect/[provider]/callback
```

Where `protocol` and `host` should match the ones from which you initiate the OAuth flow, and `provider` is the provider's name from the list of [supported providers][grant].

This `redirect` URL is used internally by Grant. You will receive the [response data][response-data] from the OAuth flow inside the route specified in the `callback` key of your Grant configuration.

> See the [Path Prefix][path-prefix] section on how to configure the redirect URL when using the `path` configuration option.


## Reserved Routes

Grant operates on the following routes:

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


## Path Prefix

You can mount Grant under specific path prefix:

```js
// Express
app.use('/path/prefix', grant(config))
// Koa
app.use(mount('/path/prefix', grant(config)))
// Hapi
server.register([{routes: {prefix: '/path/prefix'}, plugin: grant(config)}])
```

In this case it is required to specify the path prefix using the `path` configuration option for the `defaults` key:

```js
{
  "defaults": {
    "protocol": "...",
    "host": "...",
    "path": "/path/prefix"
  }
}
```

Lastly that path prefix should be specified in your OAuth application's redirect URL as well:

```
[protocol]://[host][path]/connect/[provider]/callback
```

In case you want your callback routes prefixed, set them accordingly:

```js
{
  "facebook": {
    "callback": "/path/prefix/handle_facebook_callback"
  }
}
```


## OpenID Connect

The `nonce` option is **recommended** when requesting the `openid` scope:

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

Grant **does not** verify the signature of the returned `id_token` because that requires discovery, caching, and expiration of the provider's public keys.

However, Grant tries to decode the `id_token` and verifies the following two claims *(returns error respectively)*:

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

For convenience the [response data][response-data] contains the decoded `id_token`.

> Take a look at the OpenID Connect [example][openid-connect-example].

## Custom Parameters

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

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

> Alternatively any custom parameter that is not a [reserved key][reserved-keys], and is listed under the `custom_parameters` array for that [provider][oauth-config], can be defined along with the rest of the options.


## Static Overrides

You can add arbitrary `{object}` keys inside your provider's configuration to create sub configurations that override the *global* settings for that provider:

```js
// navigate to /connect/facebook
"facebook": {
  "key": "...",
  "secret": "...",
  // by default request publish permissions
  "scope": ["publish_actions", "publish_stream"],
  // set specific callback route on your server for this provider
  "callback": "/facebook/callback",
  // navigate to /connect/facebook/groups
  "groups": {
    // request only group permissions
    "scope": ["user_groups", "friends_groups"]
  },
  // navigate to /connect/facebook/pages
  "pages": {
    // request only page permissions
    "scope": ["manage_pages"],
    // additionally use specific callback route on your server for this override
    "callback": "/facebook_pages/callback"
  }
}
```

> The custom key names cannot be one of the [reserved keys][reserved-keys].


## Dynamic Override

In some cases you may want to allow the user to override certain parts of your configuration dynamically.

For example for `shopify` you have to embed the user's shop name into the OAuth URLs, so it makes sense to allow the [`subdomain` option][subdomain] to be overridden dynamically:

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

Then you can have a form on your website to allow the user to specify the shop name:

```html
<form action="/connect/shopify" method="post" accept-charset="utf-8">
  <input type="text" name="subdomain" value="" />
  <button>submit</button>
</form>
```

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

```js
// 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(mount(grant(config)))
```

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

```js
https://mywebsite.com/connect/shopify?subdomain=usershop
```


## Reserved Keys

List of all [reserved keys][reserved-json] and their typical location:

Key | Location | Description
:---| :--- | :---
request_url | [oauth.json][oauth-config] | OAuth1/step1
authorize_url | [oauth.json][oauth-config] | OAuth1/step2 or OAuth2/step1
access_url | [oauth.json][oauth-config] | OAuth1/step3 or OAuth2/step2
oauth | [oauth.json][oauth-config] | OAuth version number
scope_delimiter | [oauth.json][oauth-config] | string delimiter used for concatenating multiple scopes
custom_parameters | [oauth.json][oauth-config] | list of known custom authorization parameters
protocol, host, path | `defaults` | used to generate `redirect_uri`
transport | `defaults` | [transport][session-vs-querystring] to use to deliver the response data in your final `callback` route
state | `defaults` | toggle random `state` string generation for OAuth2
key | `[provider]` | OAuth app key, reserved aliaes: `consumer_key` and `client_id`
secret | `[provider]` | OAuth app secret, reserved aliases: `consumer_secret` and `client_secret`
scope | `[provider]` | list of scopes to request
custom_params | `[provider]` | custom authorization [parameters][custom-parameters] and their values
subdomain | `[provider]` | string to be [embedded][subdomain] in `request_url`, `authorize_url` and `access_url`
nonce | `[provider]` | toggle random `nonce` string generation for [OpenID Connect][openid-connect] providers
callback | `[provider]` | final callback route on your server to receive the [response data][response-data]
dynamic | `[provider]` | allow [dynamic override][dynamic-override] of configuration
name | generated | provider's [name][grant], used to generate `redirect_uri`
[provider] | generated | provider's [name][grant] as key
redirect_uri | generated | OAuth app [redirect URI][redirect-uri], generated using `protocol`, `host`, `path` and `name`
overrides | generated | all keys containing `{object}` value are extracted here as [static overrides][static-overrides]


## Custom Providers

In case you have a private OAuth provider that you don't want to be part of the [officially supported][grant] ones, you can define it in your configuration by adding a custom key for it.

In this case you have to specify all of the required provider keys by yourself:

```js
{
  "defaults": {
    "protocol": "https",
    "host": "mywebsite.com"
  },
  "mywebsite": {
    "authorize_url": "https://mywebsite.com/authorize",
    "access_url": "https://mywebsite.com/token",
    "oauth": 2,
    "key": "[CLIENT_ID]",
    "secret": "[CLIENT_SECRET]",
    "scope": ["read", "write"]
  }
}
```

> Refer to the Grant's [OAuth configuration][oauth-config] to see how various providers are configured.


## Development Environments

You can easily configure different development environments:

```js
{
  "development": {
    "defaults": {"protocol": "http", "host": "dummy.com:3000"},
    "facebook": {
      "key": "development OAuth app credentials",
      "secret": "development OAuth app credentials"
    },
    "twitter": {...}, ...
  },
  "staging": {
    "defaults": {"protocol": "https", "host": "staging.mywebsite.com"},
    "facebook": {
      "key": "staging OAuth app credentials",
      "secret": "staging OAuth app credentials"
    },
    "twitter": {...}, ...
  },
  "production": {
    "defaults": {"protocol": "https", "host": "mywebsite.com"},
    "facebook": {
      "key": "production OAuth app credentials",
      "secret": "production OAuth app credentials"
    },
    "twitter": {...}, ...
  }
}
```

Then you can pass the environment flag:

```bash
NODE_ENV=production node app.js
```

And use it in your application:

```js
var config = require('./config.json')
var grant = Grant(config[process.env.NODE_ENV || 'development'])
```


## Subdomain

Some providers have dynamic URLs containing bits of user information embedded in them.

The `subdomain` option can be used to specify your company name, server region or whatever else is required:

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

Then Grant will generate the correct OAuth URLs:

```js
"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 for testing. To use them just override the entire `request_url`, `authorize_url` and `access_url` in your configuration *(notice the `sandbox` bits)*:

```js
"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 default `redirect_uri` that Grant [generates for you][redirect-uri].

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

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

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

```js
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][response-data] in your final `callback` route.


## More Dynamic Overrides

In case you really want to, you can allow [dynamic overriding][dynamic-override] of every option for a provider:

```json
{
  "facebook": {
    "dynamic": true
  }
}
```

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

```json
{
  "defaults": {
    "dynamic": true
  }
}
```

> Essentially Grant is an [OAuth proxy][oauth-proxy-example].


## Quirks


#### Ebay

Set the redirect URL of your OAuth app as usual `[protocol]://[host]/connect/ebay/callback`. Then Ebay will generate a special string called *RuName (eBay Redirect URL name)* that you need to set as `redirect_uri` in Grant:

```js
"ebay": {
  "redirect_uri": "[RUNAME]"
}
```


#### Flickr, Optimizely

Flickr uses a custom authorization parameter to pass its scopes called `perms`, and Optimizely uses `scopes`. However you should use the regular `scope` option in your configuration:

```js
"flickr": {
  "scope": ["write"]
}
"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:

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


#### SurveyMonkey

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

```js
"surveymonkey": {
  "key": "[MASHERY_USER_NAME]",
  "secret": "[CLIENT_SECRET]",
  "api_key": "[CLIENT_ID]"
}
```


#### Fitbit, LinkedIn, ProjectPlace

Initially these were OAuth1 providers, so the `fitbit`, `linkedin` and `projectplace` names are used for that. To use their OAuth2 flow append `2` at the end of their names:

```js
"fitbit2": {
  // then navigate to /connect/fitbit2
},
"linkedin2": {
  // then navigate to /connect/linkedin2
},
"projectplace2": {
  // then navigate to /connect/projectplace2
}
```


#### VisualStudio

Set your Client Secret as `secret` not the App Secret:

```js
"visualstudio": {
  "key": "[APP_ID]",
  "secret": "[CLIENT_SECRET not APP_SECRET]"
}
```


## Response Data

The OAuth response data is returned as *querystring* in your **final** callback - the one you specify using the `callback` key in your Grant configuration.

Alternatively the response data can be returned inside the *session*, see the [configuration][configuration] section above and the [session transport][session-transport-example] example.


### OAuth2

The `access_token` and the `refresh_token` *(if present)* are accessible directly. The `id_token` *(OpenID Connect only)* contains the decoded JWT, and `raw` contains the raw response data:

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


### OAuth1

The `access_token` and the `access_secret` are accessible directly, `raw` contains the raw response data:

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


### Error

In case of an error, the `error` key will be populated with the raw error data:

```js
{
  error: {
    some: 'error data'
  }
}
```


## Alternative Require

Alternatively you can require the middlewares from `grant` *(each pair is identical)*:

```js
// 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()
```


## Alternative Instantiation

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

```js
var Grant = require('grant-express/koa/hapi')
var grant = Grant(config)
// identical to:
var grant = new Grant(config)
```

Additionally Hapi can accept the configuration in two different ways:

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


## Programmatic Access

Every Grant instance have a `config` property attached to it:

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

It contains the _generated_ configuration data that Grant uses internally.

> You can use the `config` property to alter the Grant's behavior during runtime.

> Keep in mind that this affects the entire Grant instance! [Dynamic override][dynamic-override] might be more appropriate.


## Session vs Querystring
{'fraction_non_alphanumeric': 0.1858085808580858, 'fraction_numerical': 0.002779225290950148, 'mean_word_length': 4.766903736351798, 'pattern_counts': {'":': 236, '<': 15, '<?xml version=': 0, '>': 40, 'https://': 360, 'lorem ipsum': 0, 'www.': 58, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3884591', 'n_tokens_mistral': 19440, 'n_tokens_neox': 18514, 'n_words': 4472}