Comparing version 3.4.0 to 3.5.0
## Change Log | ||
### v3.5.0 (2015/08/30) | ||
- `Changed` better OAuth2 [random state string](https://github.com/simov/grant/commit/e1cf1e468846e5b2e75f65d8bdf4794a88619c37) | ||
- `Added` ability to override the [redirect_uri](https://github.com/simov/grant#sandbox-redirect-uri) | ||
- `Added` ability to configure Grant without having a *server* key | ||
- `Added` generic error handler for missing or misconfigured provider | ||
- `Added` introduced `custom_params` option for safer way to define [custom authorization parameters](https://github.com/simov/grant#custom-parameters) | ||
- `Added` improved documentation about all configuration [quirks](https://github.com/simov/grant#quirks) | ||
- `Added` official support for 5 new providers | ||
### v3.4.0 (2015/07/20) | ||
- `Changed` better configuration initialization | ||
- `Changed` bumped module dependency versions | ||
- `Changed` migrated *rdio* to [OAuth2](https://github.com/simov/grant/blob/3.4.0/config/oauth.json#L420-L424) | ||
- `Changed` updated the *trakt* [urls](https://github.com/simov/grant/blob/3.4.0/config/oauth.json#L542-L546) | ||
- `Added` [custom_parameters](https://github.com/simov/grant/blob/3.4.0/config/oauth.json#L655) for *yandex* | ||
- `Added` docs about the [programmatic access](https://github.com/simov/grant#programmatic-access) | ||
- `Added` docs about how to utilize [sandbox urls](https://github.com/simov/grant#custom-parameters) | ||
- `Added` official support for 3 more providers | ||
- `Changed` bumped module dependency versions | ||
- `Changed` migrated *rdio* to [OAuth2](https://github.com/simov/grant/blob/master/config/oauth.json#L420-L424) | ||
- `Changed` updated the *trakt* [urls](https://github.com/simov/grant/blob/master/config/oauth.json#L543-L544) | ||
- `Added` [custom_parameters](https://github.com/simov/grant/blob/master/config/oauth.json#L655) for *yandex* | ||
- `Added` official support for 3 new providers | ||
### v3.3.3 (2015/06/24) | ||
- `Added` official support for 9 more providers | ||
- `Added` official support for 9 new providers | ||
### v3.3.2 (2015/06/05) | ||
- `Changed` a few minor changes to the project's meta files | ||
- `Added` official support for 2 more providers | ||
- `Added` official support for 2 new providers | ||
### v3.3.1 (2015/05/21) | ||
- `Added` official support for 10 more providers | ||
- `Added` official support for 10 new providers | ||
@@ -64,3 +72,3 @@ ### v3.3.0 (2015/05/17) | ||
- `Changed` the [response data](https://github.com/simov/grant#response-data) format, now containing a `raw` key in it | ||
- `Changed` [custom authorization parameters](https://github.com/simov/grant#quirks) regarding token expiration are no longer part of the scope array | ||
- `Changed` [custom authorization parameters](https://github.com/simov/grant#custom-parameters) regarding token expiration are no longer part of the scope array | ||
@@ -67,0 +75,0 @@ |
@@ -308,3 +308,6 @@ { | ||
"scope_delimiter": " ", | ||
"custom_parameters": ["access_type"] | ||
"custom_parameters": [ | ||
"access_type", "approval_prompt", "login_hint", "include_granted_scopes", | ||
"prompt" | ||
] | ||
}, | ||
@@ -421,2 +424,14 @@ "harvest": { | ||
}, | ||
"pushbullet": { | ||
"authorize_url": "https://www.pushbullet.com/authorize", | ||
"access_url": "https://api.pushbullet.com/oauth2/token", | ||
"oauth": 2 | ||
}, | ||
"ravelry": { | ||
"request_url": "https://www.ravelry.com/oauth/request_token", | ||
"authorize_url": "https://www.ravelry.com/oauth/authorize", | ||
"access_url": "https://www.ravelry.com/oauth/access_token", | ||
"oauth": 1, | ||
"scope_delimiter": " " | ||
}, | ||
"rdio": { | ||
@@ -544,2 +559,7 @@ "authorize_url": "https://www.rdio.com/oauth2/authorize", | ||
}, | ||
"todoist": { | ||
"authorize_url": "https://todoist.com/oauth/authorize", | ||
"access_url": "https://todoist.com/oauth/access_token", | ||
"oauth": 2 | ||
}, | ||
"trakt": { | ||
@@ -560,3 +580,3 @@ "authorize_url": "https://api-v2launch.trakt.tv/oauth/authorize", | ||
"oauth": 1, | ||
"custom_parameters": ["scope", "expiration"] | ||
"custom_parameters": ["name", "expiration"] | ||
}, | ||
@@ -626,2 +646,7 @@ "tripit": { | ||
}, | ||
"weibo": { | ||
"authorize_url": "https://api.weibo.com/oauth2/authorize", | ||
"access_url": "https://api.weibo.com/oauth2/access_token", | ||
"oauth": 2 | ||
}, | ||
"withings": { | ||
@@ -639,2 +664,7 @@ "request_url": "https://oauth.withings.com/account/request_token", | ||
}, | ||
"wrike": { | ||
"authorize_url": "https://www.wrike.com/oauth2/authorize", | ||
"access_url": "https://www.wrike.com/oauth2/token", | ||
"oauth": 2 | ||
}, | ||
"xing": { | ||
@@ -641,0 +671,0 @@ "request_url": "https://api.xing.com/v1/request_token", |
@@ -18,6 +18,12 @@ [ | ||
"secret", | ||
"consumer_key", | ||
"consumer_secret", | ||
"client_id", | ||
"client_secret", | ||
"scope", | ||
"redirect_uri", | ||
"name", | ||
"overrides" | ||
"overrides", | ||
"custom_params" | ||
] |
'use strict' | ||
var crypto = require('crypto') | ||
var dcopy = require('deep-copy') | ||
@@ -11,12 +12,47 @@ | ||
// oauth credentials transform | ||
exports.credentials = function (provider, options) { | ||
var key, secret | ||
// generate provider options | ||
exports.initProvider = function (provider, options, server, name) { | ||
// merge provider options with user options | ||
// cleanup empty values custom_params | ||
if (options.custom_params) { | ||
var params = options.custom_params | ||
for (var key in params) { | ||
if (!params[key]) delete params[key] | ||
} | ||
if (!Object.keys(params).length) { | ||
delete options.custom_params | ||
} | ||
} | ||
// set reserved keys | ||
this.reserved.forEach(function (key) { | ||
var value = options[key] || server[key] || provider[key] | ||
if (value) { | ||
provider[key] = value | ||
} | ||
}) | ||
// transformations | ||
// provider shortcuts | ||
if (name) { | ||
provider[name] = true | ||
provider.name = name | ||
} | ||
// oauth credentials | ||
var key = null, secret = null | ||
if (provider.oauth == 1) { | ||
key = options.consumer_key || provider.key | ||
secret = options.consumer_secret || provider.secret | ||
key = provider.consumer_key || provider.key | ||
secret = provider.consumer_secret || provider.secret | ||
} | ||
else if (provider.oauth == 2) { | ||
key = options.client_id || provider.key | ||
secret = options.client_secret || provider.secret | ||
key = provider.client_id || provider.key | ||
secret = provider.client_secret || provider.secret | ||
} | ||
@@ -29,86 +65,41 @@ if (key) { | ||
} | ||
} | ||
// oauth scope transform | ||
exports.scope = function (provider, options) { | ||
var scope = options.scope || provider.scope | ||
if (!scope) return | ||
provider.scope = (scope instanceof Array) | ||
? scope.join(provider.scope_delimiter||',') | ||
: scope | ||
if (provider.copy && typeof scope === 'object') { | ||
provider.scope = JSON.stringify(scope) | ||
// oauth scope | ||
if (provider.scope) { | ||
if (provider.scope instanceof Array) { | ||
provider.scope = provider.scope.join(provider.scope_delimiter||',') | ||
} | ||
else if (typeof provider.scope == 'object') { | ||
provider.scope = JSON.stringify(provider.scope) | ||
} | ||
} | ||
} | ||
// oauth state transform | ||
exports.state = function (provider) { | ||
var state | ||
if (typeof provider.state == 'string' || typeof provider.state == 'number') { | ||
state = provider.state.toString() | ||
} | ||
else if (typeof provider.state == 'boolean' && provider.state) { | ||
state = (Math.floor(Math.random() * 999999) + 1).toString() | ||
} | ||
return state | ||
} | ||
// override provider | ||
exports.override = function (provider, options) { | ||
var override = dcopy(provider) | ||
for (var key in options) { | ||
if (!options[key]) continue | ||
override[key] = options[key] | ||
} | ||
this.transform(override, options) | ||
return override | ||
} | ||
// apply multiple transformations | ||
exports.transform = function (provider, options) { | ||
this.credentials(provider, options) | ||
this.scope(provider, options) | ||
} | ||
// generate provider options | ||
exports.initProvider = function (key, config) { | ||
// oauth provider settings | ||
var provider = dcopy(this.oauth[key]||{}) | ||
// oauth application options | ||
var options = config[key]||{} | ||
// provider shortcuts | ||
provider[key] = true | ||
provider.name = key | ||
// set reserved keys | ||
this.reserved.forEach(function (key) { | ||
var value = options[key] || config.server[key] || provider[key] | ||
if (value) { | ||
provider[key] = value | ||
} | ||
}) | ||
// custom parameters | ||
// custom_parameters | ||
if (provider.custom_parameters) { | ||
var params = provider.custom_params || {} | ||
for (var key in options) { | ||
if (typeof options[key] === 'string' && | ||
this.reserved.indexOf(key) == -1 && | ||
if (this.reserved.indexOf(key) == -1 && | ||
provider.custom_parameters.indexOf(key) != -1) { | ||
provider[key] = options[key] | ||
params[key] = options[key] | ||
} | ||
} | ||
if (Object.keys(params).length) { | ||
provider.custom_params = params | ||
} | ||
} | ||
// static overrides | ||
var overrides = {} | ||
for (var key in options) { | ||
if (provider.custom_parameters && | ||
provider.custom_parameters.indexOf(key) != -1) continue | ||
if (this.reserved.indexOf(key) == -1 && | ||
key != 'scope' && | ||
typeof options[key] === 'object') { | ||
overrides[key] = this.override(provider, options[key]) | ||
overrides[key] = this.initProvider(dcopy(provider), options[key], {}) | ||
} | ||
@@ -120,3 +111,3 @@ } | ||
this.transform(provider, options) | ||
return provider | ||
@@ -127,22 +118,50 @@ } | ||
exports.init = function (config) { | ||
config = config||{} | ||
var result = {} | ||
config = config || {} | ||
var server = config.server || {} | ||
// generate provider options | ||
var result = {} | ||
for (var key in config) { | ||
var provider = this.initProvider(key, config) | ||
result[provider.name] = provider | ||
if (key == 'server') continue | ||
var provider = dcopy(this.oauth[key]||{}) | ||
, options = config[key]||{} | ||
var generated = this.initProvider(provider, options, server, key) | ||
result[generated.name] = generated | ||
} | ||
result.server = config.server||{} | ||
result.server = server | ||
return result | ||
} | ||
// oauth state transform | ||
exports.state = function (provider) { | ||
var state | ||
if (typeof provider.state == 'string' || typeof provider.state == 'number') { | ||
state = provider.state.toString() | ||
} | ||
else if (typeof provider.state == 'boolean' && provider.state) { | ||
state = crypto.randomBytes(10).toString('hex') | ||
} | ||
return state | ||
} | ||
// get provider on connect | ||
exports.provider = function (config, session) { | ||
var provider = config[session.provider] | ||
var name = session.provider | ||
, provider = config[name] | ||
if (!provider) { | ||
provider = this.initProvider(session.provider, config) | ||
config[provider.name] = provider | ||
if (this.oauth[name]) { | ||
var provider = dcopy(this.oauth[name]) | ||
, options = {} | ||
, server = config.server || {} | ||
provider = this.initProvider(provider, options, server, name) | ||
config[provider.name] = provider | ||
} else { | ||
provider = {} | ||
} | ||
} | ||
if (session.override && provider.overrides) { | ||
@@ -152,5 +171,10 @@ var override = provider.overrides[session.override] | ||
} | ||
if (session.dynamic) { | ||
provider = this.override(provider, session.dynamic) | ||
var provider = dcopy(provider) | ||
, options = session.dynamic | ||
, server = config.server || {} | ||
provider = this.initProvider(provider, options, server) | ||
} | ||
if (provider.state) { | ||
@@ -160,3 +184,4 @@ provider = dcopy(provider) | ||
} | ||
return provider | ||
} |
@@ -32,6 +32,10 @@ 'use strict' | ||
req.session.grant = { | ||
provider:req.params.provider, | ||
override:req.params.override, | ||
dynamic:req.query | ||
provider:req.params.provider | ||
} | ||
if (req.params.override) { | ||
req.session.grant.override = req.params.override | ||
} | ||
if (Object.keys(req.query||{}).length) { | ||
req.session.grant.dynamic = req.query | ||
} | ||
@@ -43,6 +47,10 @@ connect(req, res) | ||
req.session.grant = { | ||
provider:req.params.provider, | ||
override:req.params.override, | ||
dynamic:req.body | ||
provider:req.params.provider | ||
} | ||
if (req.params.override) { | ||
req.session.grant.override = req.params.override | ||
} | ||
if (Object.keys(req.body||{}).length) { | ||
req.session.grant.dynamic = req.body | ||
} | ||
@@ -80,6 +88,15 @@ connect(req, res) | ||
} | ||
else { | ||
var err = {error:'Grant: missing or misconfigured provider'} | ||
if (provider.callback) { | ||
res.redirect(provider.callback + '?' + qs.stringify(err)) | ||
} else { | ||
res.end(JSON.stringify(err)) | ||
} | ||
} | ||
} | ||
app.get('/connect/:provider/callback', function (req, res) { | ||
var grant = req.session.grant | ||
var grant = req.session.grant || {} | ||
var provider = config.provider(app.config, grant) | ||
@@ -119,2 +136,11 @@ var flow = flows[provider.oauth] | ||
} | ||
else { | ||
var err = {error:'Grant: missing session or misconfigured provider'} | ||
if (provider.callback) { | ||
res.redirect(provider.callback + '?' + qs.stringify(err)) | ||
} else { | ||
res.end(JSON.stringify(err)) | ||
} | ||
} | ||
}) | ||
@@ -121,0 +147,0 @@ |
@@ -30,8 +30,17 @@ 'use strict' | ||
if (!req.session) throw new Error('Grant: register session plugin first') | ||
req.session.set('grant', { | ||
provider:req.params.provider, | ||
override:req.params.override||undefined, | ||
dynamic:(req.method == 'post') ? (req.payload||{}) : (req.query||{}) | ||
}) | ||
var session = { | ||
provider:req.params.provider | ||
} | ||
if (req.params.override) { | ||
session.override = req.params.override | ||
} | ||
if (req.method == 'get' && Object.keys(req.query||{}).length) { | ||
session.dynamic = req.query | ||
} | ||
if (req.method == 'post' && Object.keys(req.payload||{}).length) { | ||
session.dynamic = req.payload | ||
} | ||
req.session.set('grant', session) | ||
connect(req, res) | ||
@@ -69,2 +78,11 @@ } | ||
} | ||
else { | ||
var err = {error:'Grant: missing or misconfigured provider'} | ||
if (provider.callback) { | ||
res.redirect(provider.callback + '?' + qs.stringify(err)) | ||
} else { | ||
res(JSON.stringify(err)) | ||
} | ||
} | ||
} | ||
@@ -76,3 +94,3 @@ | ||
handler: function (req, res) { | ||
var grant = req.session.get('grant') | ||
var grant = req.session.get('grant') || {} | ||
var provider = config.provider(self.config, grant) | ||
@@ -113,2 +131,11 @@ var flow = flows[provider.oauth] | ||
} | ||
else { | ||
var err = {error:'Grant: missing session or misconfigured provider'} | ||
if (provider.callback) { | ||
res.redirect(provider.callback + '?' + qs.stringify(err)) | ||
} else { | ||
res(JSON.stringify(err)) | ||
} | ||
} | ||
} | ||
@@ -115,0 +142,0 @@ }) |
@@ -39,6 +39,10 @@ 'use strict' | ||
this.session.grant = { | ||
provider:provider, | ||
override:override, | ||
dynamic:this.request.query | ||
provider:provider | ||
} | ||
if (override) { | ||
this.session.grant.override = override | ||
} | ||
if (Object.keys(this.request.query||{}).length) { | ||
this.session.grant.dynamic = this.request.query | ||
} | ||
@@ -50,6 +54,10 @@ yield connect | ||
this.session.grant = { | ||
provider:provider, | ||
override:override, | ||
dynamic:this.request.body | ||
provider:provider | ||
} | ||
if (override) { | ||
this.session.grant.override = override | ||
} | ||
if (Object.keys(this.request.body||{}).length) { | ||
this.session.grant.dynamic = this.request.body | ||
} | ||
@@ -93,6 +101,15 @@ yield connect | ||
} | ||
else { | ||
var err = {error:'Grant: missing or misconfigured provider'} | ||
if (provider.callback) { | ||
this.response.redirect(provider.callback + '?' + qs.stringify(err)) | ||
} else { | ||
this.body = JSON.stringify(err) | ||
} | ||
} | ||
} | ||
function* callback () { | ||
var grant = this.session.grant | ||
var grant = this.session.grant || {} | ||
var provider = config.provider(app.config, grant) | ||
@@ -138,2 +155,11 @@ var flow = flows[provider.oauth] | ||
} | ||
else { | ||
var err = {error:'Grant: missing session or misconfigured provider'} | ||
if (provider.callback) { | ||
this.response.redirect(provider.callback + '?' + qs.stringify(err)) | ||
} else { | ||
this.body = JSON.stringify(err) | ||
} | ||
} | ||
} | ||
@@ -140,0 +166,0 @@ |
@@ -24,3 +24,3 @@ 'use strict' | ||
if (provider.subdomain) { | ||
url = url.replace('[subdomain]',provider.subdomain) | ||
url = url.replace('[subdomain]', provider.subdomain) | ||
} | ||
@@ -37,3 +37,4 @@ request.post(url, options, function (err, res, body) { | ||
if (!step1.oauth_token) { | ||
var error = (Object.keys(step1).length) ? step1 : {error:'Grant: request_url'} | ||
var error = (Object.keys(step1).length) | ||
? step1 : {error:'Grant: OAuth1 missing oauth_token parameter'} | ||
return provider.callback + '?' + utils.toQuerystring({}, error, true) | ||
@@ -45,9 +46,13 @@ } | ||
} | ||
if (provider.custom_parameters) { | ||
provider.custom_parameters.forEach(function (key) { | ||
params[key] = (provider.flickr && key == 'perms') | ||
? provider.scope | ||
: provider[key] | ||
}) | ||
if (provider.custom_params) { | ||
for (var key in provider.custom_params) { | ||
params[key] = provider.custom_params[key] | ||
} | ||
} | ||
if (provider.flickr) { | ||
params.perms = provider.scope | ||
} | ||
if (provider.ravelry || provider.trello) { | ||
params.scope = provider.scope | ||
} | ||
if (provider.tripit) { | ||
@@ -57,3 +62,3 @@ params.oauth_callback = utils.redirect_uri(provider) | ||
if (provider.subdomain) { | ||
url = url.replace('[subdomain]',provider.subdomain) | ||
url = url.replace('[subdomain]', provider.subdomain) | ||
} | ||
@@ -65,3 +70,4 @@ return url + '?' + qs.stringify(params) | ||
if (!step2.oauth_token) { | ||
var error = (Object.keys(step2).length) ? step2 : {error:'Grant: authorize_url'} | ||
var error = (Object.keys(step2).length) | ||
? step2 : {error:'Grant: OAuth1 missing oauth_token parameter'} | ||
return done(utils.toQuerystring({}, error, true)) | ||
@@ -86,3 +92,3 @@ } | ||
if (provider.subdomain) { | ||
url = url.replace('[subdomain]',provider.subdomain) | ||
url = url.replace('[subdomain]', provider.subdomain) | ||
} | ||
@@ -89,0 +95,0 @@ request.post(url, options, function (err, res, body) { |
@@ -17,15 +17,12 @@ 'use strict' | ||
} | ||
if (provider.custom_params) { | ||
for (var key in provider.custom_params) { | ||
params[key] = provider.custom_params[key] | ||
} | ||
} | ||
if (provider.basecamp) { | ||
params.type = 'web_server' | ||
} | ||
if (provider.surveymonkey) { | ||
params.api_key = provider.api_key | ||
} | ||
if (provider.custom_parameters) { | ||
provider.custom_parameters.forEach(function (key) { | ||
params[key] = provider[key] | ||
}) | ||
} | ||
if (provider.subdomain) { | ||
url = url.replace('[subdomain]',provider.subdomain) | ||
url = url.replace('[subdomain]', provider.subdomain) | ||
} | ||
@@ -37,3 +34,4 @@ return url + '?' + qs.stringify(params) | ||
if (!step1.code) { | ||
var error = (Object.keys(step1).length) ? step1 : {error:'Grant: authorize_url'} | ||
var error = (Object.keys(step1).length) | ||
? step1 : {error:'Grant: OAuth2 missing code parameter'} | ||
return done(utils.toQuerystring({}, error, true)) | ||
@@ -58,5 +56,2 @@ } | ||
} | ||
if (provider.surveymonkey) { | ||
options.qs = {api_key:provider.api_key} | ||
} | ||
if (provider.reddit) { | ||
@@ -67,4 +62,7 @@ delete options.form.client_id | ||
} | ||
if (provider.surveymonkey) { | ||
options.qs = {api_key:provider.custom_params.api_key} | ||
} | ||
if (provider.subdomain) { | ||
url = url.replace('[subdomain]',provider.subdomain) | ||
url = url.replace('[subdomain]', provider.subdomain) | ||
} | ||
@@ -71,0 +69,0 @@ request.post(url, options, function (err, res, body) { |
@@ -7,2 +7,5 @@ 'use strict' | ||
exports.redirect_uri = function (provider) { | ||
if (provider.redirect_uri) { | ||
return provider.redirect_uri | ||
} | ||
var url = [ | ||
@@ -9,0 +12,0 @@ provider.protocol, |
{ | ||
"name": "grant", | ||
"version": "3.4.0", | ||
"version": "3.5.0", | ||
"description": "OAuth Middleware for Express, Koa and Hapi", | ||
@@ -33,7 +33,7 @@ | ||
"devDependencies": { | ||
"mocha" : "2.2.4", | ||
"should" : "5.2.0", | ||
"istanbul" : "0.3.13", | ||
"coveralls" : "2.11.2", | ||
"eslint" : "0.19.0", | ||
"mocha" : "2.x.x", | ||
"should" : "7.x.x", | ||
"istanbul" : "0.x.x", | ||
"coveralls" : "2.x.x", | ||
"eslint" : "1.x.x", | ||
@@ -44,13 +44,12 @@ "express" : "4.x.x", | ||
"koa" : "0.x.x", | ||
"koa-route" : "2.4.0", | ||
"thunkify" : "2.1.2", | ||
"koa" : "1.x.x", | ||
"koa-route" : "2.x.x", | ||
"thunkify" : "2.x.x", | ||
"koa-session" : "3.x.x", | ||
"koa-bodyparser" : "1.x.x", | ||
"koa-mount" : "1.3.0", | ||
"koa-router" : "3.7.0", | ||
"koa-qs" : "2.0.0", | ||
"koa-bodyparser" : "2.x.x", | ||
"koa-mount" : "1.x.x", | ||
"koa-qs" : "2.x.x", | ||
"hapi" : "8.x.x", | ||
"hapi" : "9.x.x", | ||
"yar" : "3.x.x" | ||
@@ -75,4 +74,4 @@ }, | ||
"lint-lib" : "eslint lib/ && echo Lint lib passed", | ||
"lint-test" : "eslint --config test/.eslintrc test/ && echo Lint test passed" | ||
"lint-test" : "eslint test/ && echo Lint test passed" | ||
} | ||
} |
249
README.md
@@ -7,5 +7,5 @@ | ||
## 100+ Supported Providers / [OAuth Playground][playground] | ||
## 100+ Supported Providers / [OAuth Playground][grant-oauth] | ||
[`23andme`](https://api.23andme.com) | [`500px`](http://developers.500px.com) | [`acton`](https://developer.act-on.com) | [`amazon`](http://login.amazon.com/documentation) | [`angellist`](https://angel.co/api) | [`appnet`](https://developers.app.net) | [`asana`](https://asana.com/developers) | [`assembla`](http://api-doc.assembla.com) | [`basecamp`](https://github.com/basecamp/bcx-api) | [`beatport`](https://oauth-api.beatport.com) | [`beatsmusic`](https://developer.beatsmusic.com) | [`bitbucket`](https://confluence.atlassian.com/display/BITBUCKET) | [`bitly`](http://dev.bitly.com) | [`box`](https://developers.box.com) | [`buffer`](https://dev.buffer.com) | [`campaignmonitor`](https://www.campaignmonitor.com/api) | [`cheddar`](https://cheddarapp.com/developer) | [`coinbase`](https://developers.coinbase.com) | [`constantcontact`](https://developer.constantcontact.com) | [`copy`](https://developers.copy.com) | [`coursera`](https://tech.coursera.org) | [`dailymile`](http://www.dailymile.com/api/documentation) | [`dailymotion`](https://developer.dailymotion.com) | [`deezer`](http://developers.deezer.com) | [`delivery`](https://developers.delivery.com) | [`deviantart`](https://www.deviantart.com/developers/) | [`digitalocean`](https://developers.digitalocean.com) | [`discogs`](http://www.discogs.com/developers) | [`disqus`](https://disqus.com/api/docs) | [`dribbble`](http://developer.dribbble.com) | [`dropbox`](https://www.dropbox.com/developers) | [`echosign`](https://secure.echosign.com/public/docs/restapi/v3) | [`edmodo`](https://developers.edmodo.com) | [`elance`](https://www.elance.com/q/api2) | [`etsy`](https://www.etsy.com/developers) | [`eventbrite`](http://developer.eventbrite.com) | [`evernote`](https://dev.evernote.com) | [`everyplay`](https://developers.everyplay.com) | [`eyeem`](https://www.eyeem.com/developers) | [`facebook`](https://developers.facebook.com) | [`familysearch`](https://familysearch.org/developers) | [`feedly`](https://developer.feedly.com) | [`fitbit`](http://dev.fitbit.com) | [`flattr`](http://developers.flattr.net) | [`flickr`](https://www.flickr.com/services) | [`flowdock`](https://www.flowdock.com/api) | [`foursquare`](https://developer.foursquare.com) | [`freshbooks`](https://www.freshbooks.com/developers) | [`geeklist`](http://hackers.geekli.st) | [`getpocket`](http://getpocket.com/developer) | [`github`](https://developer.github.com) | [`gitlab`](http://doc.gitlab.com/ce/api) | [`gitter`](https://developer.gitter.im) | [`goodreads`](https://www.goodreads.com/api) | [`google`](https://developers.google.com) | [`harvest`](https://github.com/harvesthq/api) | [`heroku`](https://devcenter.heroku.com/categories/platform-api) | [`imgur`](https://api.imgur.com) | [`instagram`](https://instagram.com/developer) | [`jawbone`](https://jawbone.com/up/developer) | [`kakao`](https://developers.kakao.com) | [`linkedin`](https://developer.linkedin.com) | [`live`](https://msdn.microsoft.com/en-us/library/dn783283.aspx) | [`mailchimp`](https://apidocs.mailchimp.com) | [`mapmyfitness`](https://developer.underarmour.com) | [`meetup`](http://www.meetup.com/meetup_api) | [`mixcloud`](https://www.mixcloud.com/developers) | [`moves`](https://dev.moves-app.com) | [`myob`](http://developer.myob.com) | [`odesk`](https://developers.odesk.com) | [`openstreetmap`](http://wiki.openstreetmap.org/wiki/API_v0.6) | [`paypal`](https://developer.paypal.com) | [`plurk`](http://www.plurk.com/API) | [`podio`](https://developers.podio.com) | [`rdio`](http://www.rdio.com/developers) | [`redbooth`](https://redbooth.com/api) | [`reddit`](http://www.reddit.com/dev/api) | [`runkeeper`](http://developer.runkeeper.com) | [`salesforce`](https://developer.salesforce.com) | [`shoeboxed`](https://github.com/Shoeboxed/api) | [`shopify`](https://docs.shopify.com/api) | [`skyrock`](http://www.skyrock.com/developer) | [`slack`](https://api.slack.com) | [`slice`](https://developer.slice.com) | [`socrata`](http://dev.socrata.com) | [`soundcloud`](https://developers.soundcloud.com) | [`spotify`](https://developer.spotify.com) | [`square`](https://connect.squareup.com) | [`stackexchange`](https://api.stackexchange.com) | [`stocktwits`](http://stocktwits.com/developers) | [`stormz`](http://developer.stormz.me) | [`strava`](http://strava.github.io/api) | [`stripe`](https://stripe.com/docs) | [`surveygizmo`](http://apihelp.surveygizmo.com) | [`surveymonkey`](https://developer.surveymonkey.com) | [`thingiverse`](http://www.thingiverse.com/developers) | [`trakt`](http://docs.trakt.apiary.io) | [`traxo`](https://developer.traxo.com) | [`trello`](https://trello.com/docs) | [`tripit`](https://www.tripit.com/developer) | [`tumblr`](https://www.tumblr.com/docs/en/api/v2) | [`twitch`](http://dev.twitch.tv) | [`twitter`](https://dev.twitter.com) | [`uber`](https://developer.uber.com) | [`underarmour`](https://developer.underarmour.com) | [`upwork`](https://developers.upwork.com) | [`uservoice`](https://developer.uservoice.com) | [`vend`](https://developers.vendhq.com) | [`vimeo`](https://developer.vimeo.com) | [`vk`](http://vk.com/dev) | [`withings`](http://oauth.withings.com/api) | [`wordpress`](https://developer.wordpress.com) | [`xing`](https://dev.xing.com) | [`yahoo`](https://developer.yahoo.com) | [`yammer`](https://developer.yammer.com) | [`yandex`](https://tech.yandex.com) | [`zendesk`](https://developer.zendesk.com) | ||
[`23andme`](https://api.23andme.com) | [`500px`](http://developers.500px.com) | [`acton`](https://developer.act-on.com) | [`amazon`](http://login.amazon.com/documentation) | [`angellist`](https://angel.co/api) | [`appnet`](https://developers.app.net) | [`asana`](https://asana.com/developers) | [`assembla`](http://api-doc.assembla.com) | [`basecamp`](https://github.com/basecamp/bcx-api) | [`beatport`](https://oauth-api.beatport.com) | [`beatsmusic`](https://developer.beatsmusic.com) | [`bitbucket`](https://confluence.atlassian.com/display/BITBUCKET) | [`bitly`](http://dev.bitly.com) | [`box`](https://developers.box.com) | [`buffer`](https://dev.buffer.com) | [`campaignmonitor`](https://www.campaignmonitor.com/api) | [`cheddar`](https://cheddarapp.com/developer) | [`coinbase`](https://developers.coinbase.com) | [`constantcontact`](https://developer.constantcontact.com) | [`copy`](https://developers.copy.com) | [`coursera`](https://tech.coursera.org) | [`dailymile`](http://www.dailymile.com/api/documentation) | [`dailymotion`](https://developer.dailymotion.com) | [`deezer`](http://developers.deezer.com) | [`delivery`](https://developers.delivery.com) | [`deviantart`](https://www.deviantart.com/developers/) | [`digitalocean`](https://developers.digitalocean.com) | [`discogs`](http://www.discogs.com/developers) | [`disqus`](https://disqus.com/api/docs) | [`dribbble`](http://developer.dribbble.com) | [`dropbox`](https://www.dropbox.com/developers) | [`echosign`](https://secure.echosign.com/public/docs/restapi/v3) | [`edmodo`](https://developers.edmodo.com) | [`elance`](https://www.elance.com/q/api2) | [`etsy`](https://www.etsy.com/developers) | [`eventbrite`](http://developer.eventbrite.com) | [`evernote`](https://dev.evernote.com) | [`everyplay`](https://developers.everyplay.com) | [`eyeem`](https://www.eyeem.com/developers) | [`facebook`](https://developers.facebook.com) | [`familysearch`](https://familysearch.org/developers) | [`feedly`](https://developer.feedly.com) | [`fitbit`](http://dev.fitbit.com) | [`flattr`](http://developers.flattr.net) | [`flickr`](https://www.flickr.com/services) | [`flowdock`](https://www.flowdock.com/api) | [`foursquare`](https://developer.foursquare.com) | [`freshbooks`](https://www.freshbooks.com/developers) | [`geeklist`](http://hackers.geekli.st) | [`getpocket`](http://getpocket.com/developer) | [`github`](https://developer.github.com) | [`gitlab`](http://doc.gitlab.com/ce/api) | [`gitter`](https://developer.gitter.im) | [`goodreads`](https://www.goodreads.com/api) | [`google`](https://developers.google.com) | [`harvest`](https://github.com/harvesthq/api) | [`heroku`](https://devcenter.heroku.com/categories/platform-api) | [`imgur`](https://api.imgur.com) | [`instagram`](https://instagram.com/developer) | [`jawbone`](https://jawbone.com/up/developer) | [`kakao`](https://developers.kakao.com) | [`linkedin`](https://developer.linkedin.com) | [`live`](https://msdn.microsoft.com/en-us/library/dn783283.aspx) | [`mailchimp`](https://apidocs.mailchimp.com) | [`mapmyfitness`](https://developer.underarmour.com) | [`meetup`](http://www.meetup.com/meetup_api) | [`mixcloud`](https://www.mixcloud.com/developers) | [`moves`](https://dev.moves-app.com) | [`myob`](http://developer.myob.com) | [`odesk`](https://developers.odesk.com) | [`openstreetmap`](http://wiki.openstreetmap.org/wiki/API_v0.6) | [`paypal`](https://developer.paypal.com) | [`plurk`](http://www.plurk.com/API) | [`podio`](https://developers.podio.com) | [`pushbullet`](https://docs.pushbullet.com/) | [`ravelry`](http://www.ravelry.com/api) | [`rdio`](http://www.rdio.com/developers) | [`redbooth`](https://redbooth.com/api) | [`reddit`](http://www.reddit.com/dev/api) | [`runkeeper`](http://developer.runkeeper.com) | [`salesforce`](https://developer.salesforce.com) | [`shoeboxed`](https://github.com/Shoeboxed/api) | [`shopify`](https://docs.shopify.com/api) | [`skyrock`](http://www.skyrock.com/developer) | [`slack`](https://api.slack.com) | [`slice`](https://developer.slice.com) | [`socrata`](http://dev.socrata.com) | [`soundcloud`](https://developers.soundcloud.com) | [`spotify`](https://developer.spotify.com) | [`square`](https://connect.squareup.com) | [`stackexchange`](https://api.stackexchange.com) | [`stocktwits`](http://stocktwits.com/developers) | [`stormz`](http://developer.stormz.me) | [`strava`](http://strava.github.io/api) | [`stripe`](https://stripe.com/docs) | [`surveygizmo`](http://apihelp.surveygizmo.com) | [`surveymonkey`](https://developer.surveymonkey.com) | [`thingiverse`](http://www.thingiverse.com/developers) | [`todoist`](https://developer.todoist.com) | [`trakt`](http://docs.trakt.apiary.io) | [`traxo`](https://developer.traxo.com) | [`trello`](https://trello.com/docs) | [`tripit`](https://www.tripit.com/developer) | [`tumblr`](https://www.tumblr.com/docs/en/api/v2) | [`twitch`](http://dev.twitch.tv) | [`twitter`](https://dev.twitter.com) | [`uber`](https://developer.uber.com) | [`underarmour`](https://developer.underarmour.com) | [`upwork`](https://developers.upwork.com) | [`uservoice`](https://developer.uservoice.com) | [`vend`](https://developers.vendhq.com) | [`vimeo`](https://developer.vimeo.com) | [`vk`](http://vk.com/dev) | [`weibo`](http://open.weibo.com) | [`withings`](http://oauth.withings.com/api) | [`wordpress`](https://developer.wordpress.com) | [`wrike`](https://developers.wrike.com) | [`xing`](https://dev.xing.com) | [`yahoo`](https://developer.yahoo.com) | [`yammer`](https://developer.yammer.com) | [`yandex`](https://tech.yandex.com) | [`zendesk`](https://developer.zendesk.com) | ||
@@ -16,3 +16,3 @@ | ||
- [Providers][grant] | ||
- Middleware | ||
- **Middleware** | ||
- [Express][express] | ||
@@ -22,7 +22,8 @@ - [Koa][koa] | ||
- [Reserved Routes for Grant][reserved-routes-for-grant] | ||
- Configuration | ||
- **Configuration** | ||
- [Basics][configuration] | ||
- [Redirect Url][redirect-url] | ||
- [Redirect URL][redirect-url] | ||
- [Static Overrides][static-overrides] | ||
- [Dynamic Override][dynamic-override] | ||
- **Advanced Configuration** | ||
- [Custom Parameters][custom-parameters] | ||
@@ -32,7 +33,9 @@ - [Custom Providers][custom-providers] | ||
- [Programmatic Access][programmatic-access] | ||
- [Response Data][response-data] | ||
- [Sandbox Redirect URI][sandbox-redirect-uri] | ||
- [Quirks][quirks] | ||
- **[Response Data][response-data]** | ||
- Misc | ||
- [Typical Flow][typical-flow] | ||
- [Get User Profile][get-user-profile] | ||
- [Examples][examples] | ||
- [Examples][grant-examples] | ||
@@ -135,3 +138,2 @@ | ||
"scope": ["scope1", "scope2", ...], | ||
"state": "some state", | ||
"callback": "/provider1/callback" | ||
@@ -149,3 +151,3 @@ }, | ||
- **transport** - transport to use to deliver the response data in your final callback `querystring` | `session` _(defaults to querystring if omitted)_ | ||
- **state** - generate 6 digit random state number on each authorization attempt `true` | `false` _(OAuth2 only, defaults to false 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` ... | ||
@@ -155,4 +157,4 @@ - **key** - `consumer_key` or `client_id` of your app | ||
- **scope** - array of OAuth scopes to request | ||
- **state** - OAuth state string to send | ||
- **callback** - specific callback to use for this provider _(overrides the global one specified under the `server` key)_ | ||
- **custom_params** - custom authorization parameters _(see the [Custom Parameters][custom-parameters] section)_ | ||
@@ -162,5 +164,5 @@ _(additionally any of the [reserved keys][reserved-keys] can be overriden for a provider)_ | ||
## Redirect Url | ||
## Redirect URL | ||
For `callback/redirect` url of your OAuth application you should **always** use this format | ||
For `redirect` URL of your OAuth application you should **always** use this format: | ||
@@ -171,5 +173,5 @@ ``` | ||
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] | ||
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 in the route specified in the `callback` key of your Grant configuration | ||
This `redirect` URL is used internally by Grant. You will receive the [response data][response-data] from the OAuth flow in the route specified in the `callback` key of your Grant configuration. | ||
@@ -179,3 +181,3 @@ | ||
You can add arbitrary _{object}_ keys inside your provider's configuration to create sub configurations that override the _global_ settings for that provider | ||
You can add arbitrary `{object}` keys inside your provider's configuration to create sub configurations that override the _global_ settings for that provider: | ||
@@ -211,3 +213,3 @@ ```js | ||
Additionally you can make a `POST` request to the `/connect/:provider/:override?` route to override your provider's configuration dynamically on each request | ||
Additionally you can make a `POST` request to the `/connect/:provider/:override?` route to override your provider's configuration dynamically on each request: | ||
@@ -223,3 +225,3 @@ ```html | ||
Keep in mind that in this case you'll have to mount the `body-parser` middleware for `express` or `koa` before mounting grant | ||
Keep in mind that in this case you'll have to mount the `body-parser` middleware for Express or Koa before mounting Grant: | ||
@@ -237,3 +239,3 @@ ```js | ||
Alternatively you can use a `GET` request with the `/connect/:provider/:override?` route | ||
Alternatively you can make a `GET` request to the `/connect/:provider/:override?` route: | ||
@@ -251,18 +253,26 @@ ```js | ||
- Some providers may employ custom authorization parameters outside of the ones specified in the [configuration][configuration] section. You can pass those custom parameters directly in your configuration, for example: Google - `access_type:'offline'`, Reddit - `duration:'permanent'`, Trello - `expiration:'never'`, and so on. Refer to the provider's OAuth documentation, and the Grant's [OAuth configuration][oauth-config] (search for `custom_parameters`) | ||
Some providers may employ custom authorization parameters outside of the ones specified in the [configuration][configuration] section. You can pass those custom parameters using the `custom_params` option: | ||
- Some providers require you to set your company name as a subdomain in the authorization urls. For example for Freshbooks, Shopify, Vend and Zendesk you can set that value through the `subdomain` option (alternatively you can override the entire `request_url`, `authorize_url` and `access_url` in your configuration) | ||
```js | ||
"google": { | ||
"custom_params": {"access_type":"offline"} | ||
}, | ||
"reddit": { | ||
"custom_params": {"duration":"permanent"} | ||
}, | ||
"trello": { | ||
"custom_params": {"name":"my app", "expiration":"never"} | ||
} | ||
``` | ||
- Some providers may have a _sandbox_ urls for testing. To use them just override the entire `request_url`, `authorize_url` and `access_url` in your configuration | ||
> Additionally any custom parameter that is not a [reserved][reserved-keys] key, and is listed under the `custom_parameters` array for that provider, can be defined along with the rest of the options. | ||
- For SurveyMonkey set your Mashery user name as `key` and your application key as `api_key` | ||
Refer to the provider's OAuth documentation, and the Grant's [OAuth configuration][oauth-config] *(search for `custom_parameters`)*. | ||
- To use the LinkedIn's OAuth2 flow you should use `linkedin2` as a provider name, instead of `linkedin` which is for OAuth1 | ||
## Custom Providers | ||
In case you have a private OAuth provider that you don't want to be part of the [officially supported][oauth-config] ones, you can still define it in your configuration by adding a custom key for it | ||
In case you have a private OAuth provider that you don't want to be part of the [officially supported][oauth-config] ones, you can define it in your configuration by adding a custom key for it. | ||
In this case you have to provide all of the required provider keys by yourself. Take a look at the [OAuth configuration][oauth-config] to see how the different types of flows are configured | ||
In this case you have to specify all of the required provider keys by yourself: | ||
@@ -275,8 +285,8 @@ ```js | ||
}, | ||
"custom1": { | ||
"mywebsite": { | ||
"authorize_url": "https://mywebsite.com/authorize", | ||
"access_url": "https://mywebsite.com/token", | ||
"oauth": 2, | ||
"key": "client_id", | ||
"secret": "client_secret", | ||
"key": "[CLIENT_ID]", | ||
"secret": "[CLIENT_SECRET]", | ||
"scope": ["read", "write"] | ||
@@ -287,6 +297,8 @@ } | ||
Take a look at the [OAuth configuration][oauth-config] to see how various providers are configured. | ||
## Development Environments | ||
You can easily configure different development environments | ||
You can easily configure different development environments: | ||
@@ -322,3 +334,3 @@ ```js | ||
Then you can pass the environment flag | ||
Then you can pass the environment flag: | ||
@@ -329,3 +341,3 @@ ```bash | ||
And use it in your application | ||
And use it in your application: | ||
@@ -340,3 +352,3 @@ ```js | ||
Once you initialize a new instance of Grant | ||
Once you initialize a new instance of Grant: | ||
@@ -347,16 +359,123 @@ ```js | ||
You get a special `config` _(`register.config` for Hapi)_ property attached to that instance. It contains the generated configuration data for all of the providers defined in your config file | ||
You get a special `config` _(`register.config` for Hapi)_ property attached to that instance. It contains the generated configuration data for all of the providers defined in your config file. | ||
> In case of dynamic access to a non pre-configured provider, it's automatically added to the `config` list on first access to the `/connect/:provider` route | ||
> In case of dynamic access to a non pre-configured provider, it is automatically added to the `config` list on first access to the `/connect/:provider` route. | ||
There is a `_config` property attached as well, which contains the data from the [config/oauth.json][oauth-config] file as well as all of the configuration methods used internally by Grant | ||
There is a `_config` property attached as well, which contains the data from the [config/oauth.json][oauth-config] file as well as all of the configuration methods used internally by Grant. | ||
> Typically you don't want to use the `_config` property directly. Also note that changes made to the `config` property are per Grant instance, where changes to the `_config` property are global | ||
> Typically you don't want to use the `_config` property directly. Also note that changes made to the `config` property are per Grant instance, where changes to the `_config` property are global. | ||
## Sandbox Redirect URI | ||
Very rarely you may need to override the default `redirect_uri` that Grant generates for you. | ||
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 case you override the `redirect_uri` in your config, 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('/', function (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)) | ||
} | ||
}) | ||
``` | ||
After that you will receive the results from the OAuth flow inside the route specified in the `callback` key of your configuration. | ||
## Quirks | ||
##### Subdomain | ||
Some providers require you to set your company name as a *subdomain* in the OAuth URLs. For example for Freshbooks, Shopify, Vend and Zendesk you can set that value through the `subdomain` option: | ||
```js | ||
"shopify": { | ||
"subdomain": "mycompany" | ||
} | ||
``` | ||
Then Grant will generate the correct OAuth URLs: | ||
```js | ||
"authorize_url": "https://mycompany.myshopify.com/admin/oauth/authorize", | ||
"access_url": "https://mycompany.myshopify.com/admin/oauth/access_token" | ||
``` | ||
> Alternatively you can override the entire `request_url`, `authorize_url` and `access_url` in your configuration. | ||
##### Sandbox 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" | ||
} | ||
``` | ||
##### Flickr | ||
Flickr uses a custom authorization parameter to pass its scopes called `perms`. However you should use the regular `scope` option in your configuration: | ||
```js | ||
"flickr": { | ||
"scope": ["write"] | ||
} | ||
``` | ||
##### SurveyMonkey | ||
For 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]" | ||
} | ||
``` | ||
To use the LinkedIn's OAuth2 flow you should use `linkedin2` as provider name, instead of `linkedin` which is for OAuth1: | ||
```js | ||
"linkedin2": { | ||
// then navigate to /connect/linkedin2 | ||
} | ||
``` | ||
## Response Data | ||
The OAuth response data is returned as a querystring in your **final** callback - the one you specify in the `callback` key of your Grant configuration | ||
The OAuth response data is returned as a querystring in your **final** callback - the one you specify in the `callback` key of your Grant configuration. | ||
Alternatively the response data can be returned in the session, see the [configuration][configuration] section above and the [session transport][session-transport-example] example | ||
Alternatively the response data can be returned in the session, see the [configuration][configuration] section above and the [session transport][session-transport-example] example. | ||
@@ -366,3 +485,3 @@ | ||
For OAuth1 the `access_token` and the `access_secret` are accessible directly, `raw` contains the raw response data | ||
For OAuth1 the `access_token` and the `access_secret` are accessible directly, `raw` contains the raw response data: | ||
@@ -384,3 +503,3 @@ ```js | ||
For OAuth2 the `access_token` and the `refresh_token` (if present) are accessible directly, `raw` contains the raw response data | ||
For OAuth2 the `access_token` and the `refresh_token` (if present) are accessible directly, `raw` contains the raw response data: | ||
@@ -402,3 +521,3 @@ ```js | ||
In case of an error, the `error` key will be populated with the raw error data | ||
In case of an error, the `error` key will be populated with the raw error data: | ||
@@ -416,6 +535,6 @@ ```js | ||
1. Register OAuth application on your provider's web site | ||
2. For `callback/redirect` url of your OAuth application **always** use this format | ||
1. Register OAuth application on your provider's web site. | ||
2. For `redirect` URL of your OAuth application **always** use this format: | ||
`[protocol]://[host]/connect/[provider]/callback` | ||
3. Create a `config.json` file containing | ||
3. Create a `config.json` file containing: | ||
@@ -428,4 +547,4 @@ ```js | ||
"facebook": { | ||
"key": "[APP_ID]", | ||
"secret": "[APP_SECRET]", | ||
"key": "[CLIENT_ID]", | ||
"secret": "[CLIENT_SECRET]", | ||
"callback": "/handle_facebook_response" | ||
@@ -439,3 +558,3 @@ }, | ||
``` | ||
4. Initialize Grant and mount it | ||
4. Initialize Grant and mount it: | ||
@@ -451,9 +570,9 @@ ```js | ||
app.use(grant) | ||
// or Koa (see above) | ||
// or Hapi (see above) | ||
// or Koa | ||
// or Hapi | ||
``` | ||
5. Navigate to `/connect/facebook` to initiate the OAuth flow for Facebook, or navigate to `/connect/twitter` to initiate the OAuth flow for Twitter | ||
6. Once the OAuth flow is completed you will receive the response data in the `/handle_facebook_response` route for Facebook, and in the `/handle_twitter_response` route for Twitter | ||
5. Navigate to `/connect/facebook` to initiate the OAuth flow for Facebook, or navigate to `/connect/twitter` to initiate the OAuth flow for Twitter. | ||
6. Once the OAuth flow is completed you will receive the response data in the `/handle_facebook_response` route for Facebook, and in the `/handle_twitter_response` route for Twitter. | ||
_(also take a look at the [examples][examples])_ | ||
_(also take a look at the [examples][grant-examples])_ | ||
@@ -463,5 +582,5 @@ | ||
Once you have your access tokens secured, you can start making authorized requests on behalf of your users. _**[Purest][purest]**_ is a great REST API library that supports **dozens** of REST API providers | ||
Once you have your access tokens secured, you can start making authorized requests on behalf of your users. **[Purest][purest]** is a generic REST API library that supports **hundreds** of REST API providers. | ||
For example, you may want to get the user's profile after the OAuth flow has completed | ||
For example, you may want to get the user's profile after the OAuth flow has completed: | ||
@@ -492,3 +611,5 @@ ```js | ||
> Full list of all providers and how to get their *user profile* endpoint can be found [here][purest-user]. | ||
## License | ||
@@ -499,5 +620,5 @@ | ||
[playground]: https://grant-oauth.herokuapp.com/ | ||
[purest]: https://github.com/simov/purest | ||
[request]: https://github.com/request/request | ||
[npm-version]: http://img.shields.io/npm/v/grant.svg?style=flat-square (NPM Version) | ||
[travis-ci]: https://img.shields.io/travis/simov/grant/master.svg?style=flat-square (Build Status) | ||
[coveralls-status]: https://img.shields.io/coveralls/simov/grant.svg?style=flat-square (Test Coverage) | ||
@@ -508,10 +629,10 @@ [npm]: https://www.npmjs.org/package/grant | ||
[npm-version]: http://img.shields.io/npm/v/grant.svg?style=flat-square (NPM Version) | ||
[travis-ci]: https://img.shields.io/travis/simov/grant/master.svg?style=flat-square (Build Status) | ||
[coveralls-status]: https://img.shields.io/coveralls/simov/grant.svg?style=flat-square (Test Coverage) | ||
[grant-oauth]: https://grant-oauth.herokuapp.com | ||
[purest]: https://github.com/simov/purest | ||
[purest-user]: https://github.com/simov/purest/blob/master/test/request/get.js | ||
[request]: https://github.com/request/request | ||
[oauth-config]: https://github.com/simov/grant/blob/master/config/oauth.json | ||
[reserved-keys]: https://github.com/simov/grant/blob/master/config/reserved.json | ||
[examples]: https://github.com/simov/grant/tree/master/example | ||
[grant-examples]: https://github.com/simov/grant/tree/master/example | ||
[session-transport-example]: https://github.com/simov/grant/blob/master/example/session-transport/app.js | ||
@@ -533,4 +654,6 @@ | ||
[programmatic-access]: #programmatic-access | ||
[sandbox-redirect-uri]: #sandbox-redirect-uri | ||
[quirks]: #quirks | ||
[response-data]: #response-data | ||
[typical-flow]: #typical-flow | ||
[get-user-profile]: #get-user-profile |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
79145
17
1524
628