What is grant?
The 'grant' npm package is a middleware for OAuth that allows you to easily integrate with various OAuth providers. It supports multiple frameworks like Express, Koa, Hapi, and more. It simplifies the process of setting up OAuth flows for authentication and authorization.
What are grant's main functionalities?
Express Integration
This code demonstrates how to integrate the 'grant' package with an Express application to handle OAuth authentication with Google. It sets up the necessary middleware and routes to handle the OAuth flow.
const express = require('express');
const session = require('express-session');
const Grant = require('grant-express');
const app = express();
app.use(session({secret: 'very secret'}));
app.use(new Grant({
defaults: {
protocol: 'http',
host: 'localhost:3000',
transport: 'session',
state: true
},
google: {
key: 'GOOGLE_CLIENT_ID',
secret: 'GOOGLE_CLIENT_SECRET',
scope: ['profile', 'email'],
callback: '/handle_google_callback'
}
}));
app.get('/handle_google_callback', (req, res) => {
res.json(req.session.grant.response);
});
app.listen(3000, () => {
console.log('Server listening on http://localhost:3000');
});
Koa Integration
This code demonstrates how to integrate the 'grant' package with a Koa application to handle OAuth authentication with GitHub. It sets up the necessary middleware and routes to handle the OAuth flow.
const Koa = require('koa');
const session = require('koa-session');
const Grant = require('grant-koa');
const app = new Koa();
app.keys = ['very secret'];
app.use(session(app));
app.use(new Grant({
defaults: {
protocol: 'http',
host: 'localhost:3000',
transport: 'session',
state: true
},
github: {
key: 'GITHUB_CLIENT_ID',
secret: 'GITHUB_CLIENT_SECRET',
scope: ['user'],
callback: '/handle_github_callback'
}
}));
app.use(async (ctx) => {
if (ctx.path === '/handle_github_callback') {
ctx.body = ctx.session.grant.response;
}
});
app.listen(3000, () => {
console.log('Server listening on http://localhost:3000');
});
Hapi Integration
This code demonstrates how to integrate the 'grant' package with a Hapi application to handle OAuth authentication with Twitter. It sets up the necessary middleware and routes to handle the OAuth flow.
const Hapi = require('@hapi/hapi');
const Grant = require('grant-hapi');
const start = async () => {
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
await server.register({
plugin: Grant,
options: {
defaults: {
protocol: 'http',
host: 'localhost:3000',
transport: 'session',
state: true
},
twitter: {
key: 'TWITTER_CONSUMER_KEY',
secret: 'TWITTER_CONSUMER_SECRET',
callback: '/handle_twitter_callback'
}
}
});
server.route({
method: 'GET',
path: '/handle_twitter_callback',
handler: (request, h) => {
return request.yar.get('grant').response;
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
start();
Other packages similar to grant
passport
Passport is a popular authentication middleware for Node.js. It supports a wide range of authentication strategies, including OAuth, OAuth2, OpenID, and more. Compared to 'grant', Passport offers more flexibility and a larger ecosystem of strategies, but it can be more complex to set up.
simple-oauth2
Simple OAuth2 is a library for integrating OAuth2 authentication in Node.js applications. It provides a straightforward API for obtaining access tokens and refreshing them. Compared to 'grant', Simple OAuth2 is more focused on OAuth2 and does not support as many frameworks out of the box.
bell
Bell is a Hapi plugin for third-party authentication using OAuth, OAuth2, and more. It is specifically designed for Hapi applications and provides a seamless integration with the Hapi framework. Compared to 'grant', Bell is more specialized for Hapi but does not support other frameworks.
Grant
500px
| amazon
| angellist
| appnet
| asana
| assembla
| basecamp
| bitbucket
| bitly
| box
| buffer
| cheddar
| coinbase
| dailymile
| dailymotion
| deezer
| deviantart
| digitalocean
| disqus
| dropbox
| edmodo
| elance
| eventbrite
| evernote
| everyplay
| eyeem
| facebook
| feedly
| fitbit
| flattr
| flickr
| flowdock
| foursquare
| freshbooks
| geeklist
| getpocket
| github
| gitter
| goodreads
| google
| harvest
| heroku
| imgur
| instagram
| jawbone
| linkedin
| live
| mailchimp
| meetup
| mixcloud
| moves
| odesk
| openstreetmap
| paypal
| podio
| rdio
| redbooth
| reddit
| runkeeper
| salesforce
| shopify
| skyrock
| slack
| slice
| soundcloud
| spotify
| stackexchange
| stocktwits
| stormz
| strava
| stripe
| traxo
| trello
| tripit
| tumblr
| twitch
| twitter
| uber
| vimeo
| vk
| withings
| wordpress
| xing
| yahoo
| yammer
| yandex
| zendesk
Express
npm install grant-express
var express = require('express')
var Grant = require('grant-express')
, grant = new Grant({})
var app = express()
app.use(grant)
app.use(cookieParser())
app.use(session())
Koa
npm install grant-koa
var koa = require('koa')
, mount = require('koa-mount')
, session = require('any session store')
var Grant = require('grant-koa')
, grant = new Grant({})
var app = koa()
app.keys = ['keys']
app.use(session(...))
app.use(mount(grant))
app.use(bodyParser())
Hapi
npm install grant-hapi
var Hapi = require('hapi')
, yar = require('yar')
var Grant = require('grant-hapi')
, grant = new Grant()
var server = new Hapi.Server()
server.register([{
register: grant,
options: {}
}, {
register: yar,
options: {cookieOptions: {password:'password', isSecure:false}}
}], function (err) {
server.start()
})
Reserved Routes for Grant
/connect/:provider/:override?
/connect/:provider/callback
Configuration
{
"server": {
"protocol": "http",
"host": "localhost:3000",
"callback": "/callback",
"transport": "session",
"state": true
},
"provider1": {
"key": "...",
"secret": "...",
"scope": ["scope1", "scope2", ...],
"state": "some state",
"callback": "/provider1/callback"
},
"provider2": {...},
...
}
- server - configuration about your server
- protocol - either
http
or https
- host - your server's host name
localhost:3000
| dummy.com:5000
| mysite.com
... - callback - common callback for all providers in your config
/callback
| /done
... - 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
(OAuth2 only, defaults to false if omitted)
- provider1 - any supported provider (see the list above)
facebook
| twitter
...
- key -
consumer_key
or client_id
of your app - secret -
consumer_secret
or client_secret
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)
Redirect Url
For callback/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 flow, and provider
is the provider's name from the list of supported providers
The path you specify in the callback
key in the Grant's configuration is where you'll receive the response data from the OAuth flow as a querystring, after the [protocol]://[host]/connect/[provider]/callback
route have been hit
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
"facebook": {
"key": "...",
"secret": "...",
"scope": ["publish_actions", "publish_stream"],
"callback": "/facebook/callback"
"groups": {
"scope": ["user_groups", "friends_groups"]
},
"pages": {
"scope": ["manage_pages"],
"callback": "/facebook_pages/callback"
}
}
Dynamic Override
Additionally you can make a POST
request to the /connect/:provider/:override?
route to override your provider's configuration dynamically on each request
<form action="/connect/facebook" method="post" accept-charset="utf-8">
<input name="state" type="text" value="" />
<input name="scope" type="checkbox" value="read" />
<input name="scope" type="checkbox" value="write" />
<button>submit</button>
</form>
Alternatively you can use a GET
request with the /connect/:provider/:override?
route
app.get('/connect_facebook', function (req, res) {
var state = (Math.floor(Math.random() * 999999) + 1)
res.redirect('/connect/facebook?state=' + state)
})
Quirks
- To use LinkedIn's OAuth2 flow you should use
linkedin2
for provider name, instead of linkedin
which is for OAuth1 - For Freshbooks, Shopify and Zendesk you should specify your company's sub domain name through the
subdomain
option - Some providers may employ custom authorization parameters outside of the ones specified in the 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 for more details
Response Data
The OAuth 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 section above and the session transport example
OAuth1
For OAuth1 the access_token
and the access_secret
are accessible directly, raw
contains the raw response data
{
access_token:'...',
access_secret:'...',
raw:{
oauth_token:'...',
oauth_token_secret:'...',
some:'other data'
}
}
OAuth2
For OAuth2 the access_token
and the refresh_token
(if present) are accessible directly, raw
contains the raw response data
{
access_token:'...',
refresh_token:'...',
raw:{
access_token:'...',
refresh_token:'...',
some:'other data'
}
}
Error
In case of an error, the error
key will be populated with the raw error data
{
error:{
some:'error data'
}
}
Typical Flow
- Register OAuth application on your provider's web site
- For
callback/redirect
url always use this format
[protocol]://[host]/connect/[provider]/callback
- Create a
config.json
file containig
"server": {
"protocol": "https",
"host": "mywebsite.com",
"callback": "/handle_oauth_response"
},
"facebook": {
"key": "client_id",
"secret": "client_secret",
"scope": ["user_about_me"]
},
"twitter": {
"key": "consumer_key",
"secret": "consumer_secret",
"callback": "/handle_twitter_response"
}
- Initialize Grant and mount it
var express = require('express')
, Grant = require('grant-express')
, grant = new Grant(require('./config.json'))
var app = express()
app.use(grant)
var koa = require('koa')
, mount = require('koa-mount')
, session = require('koa-session')
var Grant = require('grant-koa')
, grant = new Grant(require('./config.json'))
var app = koa()
app.keys = ['keys']
app.use(session(app))
app.use(mount(grant))
- Navigate to
/connect/facebook
to initiate the OAuth flow for Facebook, or navigate to /connect/twitter
to initiate the OAuth flow for Twitter - Once the OAuth flow is complete for Facebook you'll receive the response data as a querystring in the
/handle_oauth_response
route, and for Twitter in the /handle_twitter_response
route
What's Next
Once you have your access tokens secured, you can start making authorized requests on behalf of your users. Purest is a great REST API library that supports dozens of REST API providers
For example, you may want to get the user's profile after the OAuth flow has completed
var Purest = require('purest')
, facebook = new Purest({provider:'facebook'})
, twitter = new Purest({provider:'twitter',
key:'[CONSUMER_KEY]', secret:'[CONSUMER_SECRET]'})
facebook.query()
.get('me')
.auth('[ACCESS_TOKEN]')
.request(function (err, res, body) {
})
twitter.query()
.get('users/show')
.qs({screen_name:'nodejs'})
.auth('[ACCESS_TOKEN]', '[ACCESS_SECRET]')
.request(function (err, res, body) {
})
License
MIT