Git Product home page Git Product logo

grant's Introduction

Grant

npm-version test-ci-img test-cov-img snyk-vulnerabilities

OAuth Proxy

200+ Supported Providers / OAuth Playground

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

Table of Contents


Handlers

HTTP Frameworks

Express
var express = require('express')
var session = require('express-session')
var grant = require('grant').express()

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

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

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

fastify()
  .register(cookie)
  .register(session, {secret: 'grant', cookie: {secure: false}})
  .register(grant({/*configuration - see below*/}))

Serverless Functions

AWS Lambda
var grant = require('grant').aws({
  config: {/*configuration - see below*/}, session: {secret: 'grant'}
})

exports.handler = async (event) => {
  var {redirect, response} = await grant(event)
  return redirect || {
    statusCode: 200,
    headers: {'content-type': 'application/json'},
    body: JSON.stringify(response)
  }
}
Azure Function
var grant = require('grant').azure({
  config: {/*configuration - see below*/}, session: {secret: 'grant'}
})

module.exports = async (context, req) => {
  var {redirect, response} = await grant(req)
  return redirect || {
    status: 200,
    headers: {'content-type': 'application/json'},
    body: JSON.stringify(response)
  }
}
Google Cloud Function
var grant = require('grant').gcloud({
  config: {/*configuration - see below*/}, session: {secret: 'grant'}
})

exports.handler = async (req, res) => {
  var {response} = await grant(req, res)
  if (response) {
    res.statusCode = 200
    res.setHeader('content-type', 'application/json')
    res.end(JSON.stringify(response))
  }
}
Vercel
var grant = require('grant').vercel({
  config: {/*configuration - see below*/}, session: {secret: 'grant'}
})

module.exports = async (req, res) => {
  var {response} = await grant(req, res)
  if (response) {
    res.statusCode = 200
    res.setHeader('content-type', 'application/json')
    res.end(JSON.stringify(response))
  }
}

Examples

express / koa / hapi / fastify / aws / azure / gcloud / vercel

ES Modules and TypeScript


Configuration

Configuration: Basics

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

Configuration: Description

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

Configuration: Values

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

Configuration: Scopes

Grant relies on configuration gathered from 6 different places:

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

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

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

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

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

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


Connect

Connect: Origin

The origin is where your client server can be reached:

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

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

Connect: Prefix

By default Grant operates on the following two routes:

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

However, the default /connect prefix can be configured:

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

Connect: Redirect URI

The redirect_uri of your OAuth app should follow this format:

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

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

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

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

Connect: Custom Parameters

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

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

Connect: OpenID Connect

The openid scope is required, and generating a random nonce string is optional but recommended:

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

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

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

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

Connect: PKCE

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

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

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

Connect: Static Overrides

Provider sub configurations can be configured using the overrides key:

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

Navigate to:

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

Callback

Callback: Data

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

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

The amount of the returned data can be controlled by using the response configuration.

OAuth 2.0

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

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

OAuth 1.0a

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

Error

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

Callback: Transport

querystring

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

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

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

session

For local callback routes the session transport is recommended:

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

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

req.session.grant.response // Express
ctx.session.grant.response // Koa
req.yar.get('grant').response // Hapi
req.session.grant.response // Fastify
(await session.get()).grant.response // Serverless Function

state

The request/response lifecycle state can be used as well:

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

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

res.locals.grant.response // Express
ctx.state.grant.response // Koa
req.plugins.grant.response // Hapi
res.grant.response // Fastify
var {response} = await grant(...) // Serverless Function

Callback: Response

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

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

querystring

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

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

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

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

session

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

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

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

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

jwt

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

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

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

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

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

profile

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

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

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

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

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

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

Callback: Session

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

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

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

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

Dynamic Configuration

Dynamic: Instance

Every Grant instance have a config property attached to it:

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

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

This property contains the generated configuration used internally by Grant, and changes made to that configuration affects the entire Grant instance!

Dynamic: State

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

var state = {dynamic: {subdomain: 'usershop'}}
res.locals.grant = state // Express
ctx.state.grant = state // Koa
req.plugins.grant = state // Hapi
req.grant = state // Fastify
await grant(..., state) // Serverless Function

This is useful in cases when you want to configure Grant dynamically with potentially sensitive data that you don't want to send over HTTP.

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

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

Dynamic: HTTP

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

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

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

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

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

Making a POST request to the /connect/:provider/:override? route requires a form body parser middleware:

.use(require('body-parser').urlencoded({extended: true})) // Express
.use(require('koa-bodyparser')()) // Koa
.register(require('@fastify/formbody')) // Fastify

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

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

Any dynamic configuration sent over HTTP GET/POST request overrides any other configuration.

Dynamic: OAuth Proxy

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

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

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

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

Essentially Grant is a completely transparent OAuth Proxy.


Misc

Misc: Redirect URI

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

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

The above configuration is identical to:

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

Explicitly specifying the redirect_uri overrides the one generated by default.

Misc: Custom Providers

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

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

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

Misc: Meta Configuration

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

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

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

Misc: Handler Constructors

Grant supports different ways of instantiation:

// Express or any other handler
var grant = require('grant').express()(config)
var grant = require('grant').express()({config, ...})
var grant = require('grant').express(config)
var grant = require('grant').express({config, ...})
var grant = require('grant')({handler: 'express', config, ...})

Using the new keyword is optional:

var Grant = require('grant').express()
var grant = Grant(config)
var grant = new Grant(config)

Additionally Hapi accepts the configuration in two different ways:

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

Misc: Path Prefix

You can mount Grant under specific path prefix:

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

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

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

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

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

Optionally you can prefix your callback routes as well:

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

Misc: Request

The underlying HTTP client can be configured using the request option:

var grant = require('grant').express({
  config,
  request: {agent, timeout: 5000}
})

Fancy request logs are available too:

npm i --save-dev request-logs
DEBUG=req,res,json node app.js

Misc: ES Modules and TypeScript

Import Grant in your .mjs files:

import express from 'express'
import session from 'express-session'
import grant from 'grant'
import config from './config.json'

express()
  .use(session({}))
  .use(grant.express(config))

Importing a .json file may require additional flag:

node --experimental-json-modules app.mjs

Grant ships with extensive type definitions for TypeScript. Additonal type definitions and examples can be found here.

Misc: OAuth Quirks

Subdomain URLs

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

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

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

Then Grant will generate the correct OAuth URLs:

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

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

Sandbox OAuth URLs

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

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

Sandbox Redirect URI

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

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

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

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

var qs = require('querystring')

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

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

Provider Quirks

Ebay

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

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

Flickr, Freelancer, Optimizely

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

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

Mastodon

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

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

Openstreetmap

Openstreetmap OAuth 2.0 applications have to use the openstreetmap2 provider:

"openstreetmap2": {
  "state": true,
  "scope": [
    "openid",
    "read_prefs"
  ]
}

SurveyMonkey

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

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

Twitter

Twitter OAuth 1.0a custom scope parameter can be specified in two ways:

"twitter": {
  "custom_params": {"x_auth_access_type": "read"}
}
"twitter": {
  "scope": ["read"]
}

Twitter OAuth 2.0 applications have to use the twitter2 provider:

"twitter2": {
  "state": true,
  "pkce": true,
  "scope": [
    "users.read",
    "tweet.read"
  ]
}

VisualStudio

Set your Client Secret as secret not the App Secret:

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

grant's People

Contributors

10allday avatar abdonrd avatar asaf avatar askmike avatar brogowski avatar coolalpaca avatar deskoh avatar flight9 avatar francois2metz avatar hdeadman avatar hochm avatar janejeon avatar joelkennedy avatar lisilinhart avatar mlafleur avatar nicholaiii avatar nk-gears avatar plmercereau avatar polnikale avatar raphaelschwinger avatar rijkvanzanten avatar rmonnier9 avatar sambernard avatar silasru avatar simov avatar slaskis avatar weseetech avatar willin avatar y0hami avatar ziogaschr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

grant's Issues

Github oauth: redirect_ui mismatch

Hey,

I'm using grant for github auth in my app and the redirect uri seems to equal myapp.com/connect/github/callback&state= instead of myapp.com/connect/github/callback.

Here's my config:

{
    server: {
      protocol: 'http'
    , host: 'http://myapp.org'
    }
  , github: {
      key: 'key'
    , secret: 'secret'
    , scope: []
    , callback: '/login_github_callback'
    }
  }

Changelog

Can we get a changelog put together for this package?

User/password authentication strategy / custom oAuth provider

I just started a new webapp-project using the application framework Strapi which offers authentication via grant. I want my own authentication in the webapp but am "forced" to use grant.

Is there an easy way to set up/fake my own oAuth provider, will I need to use middleware like koa-oauth-server or is there even a simple user/pw strategy for grant?

customized redirect URL ?

README says that:

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

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

But in my application I'd like to use a customized redirect URL, for example:

Is it possible ?

Use jwt instead of cookie?

I would like to use response data from each provider to create a json web token instead of the generated cookie.

How might I be able to do this using grant?

Problem with Trello

I'm trying to connect to Trello but it doesn't seem to be working.

Here's my config:

"trello": {
    "key": "***",
    "secret": "***",
    "scope": ["read"],
    "callback": "/authorise/trello",
    "custom_params": {"name":"test", "expiration":"never"}
},

Neither the Allow or Deny buttons are working. Looking at the console when clicking Allow it seems to do a POST call to https://trello.com/1/token/approve which is cancelled.

The post data contains: approve, requestKey, signature params.

Any idea what I've done wrong here?

Problem when using multiple scopes in facebook

Hi,

I am using grant express and trying to make the facebook example work. The twitter and e.g. moves examples work fine. With facebook there is a problem though. After testing it occurs only when there are multiple scopes defined in the config.

{
  "server": {
    "protocol": "http",
    "host": "localhost:3000"
  },
  "facebook": {
    "key": "(key)",
    "secret": "(secret)",
    "callback": "/handle_facebook_callback",
    "scope": [
      "public_profile",      
      "user_groups",
      "user_likes"
    ]
  }
}

When running, facebook fails to properly redirect back and the query string in the debug shows the scope parameters as url encoded comma separated list:

...&scope=public_profile%2Cuser_groups%2Cuser_likes

With a facebook error message. "Sorry, something went wrong."

When I replace (manually) in the query string with

...&scope=public_profile&scope=user_groups&scope=user_likes

it works fine. Regular commas also don't work manually in the querystring.

What am I doing wrong? I am inclined to think I am missing something totally obvious...

Thanks!

using grant locally.

ha any one manged to get this to work locally?

I've tried the following with varying levels of failure:
make domain name /etc/hosts and use that, which all most worked (URL issues),
use "http:/localhost:8000/connect/github" sort ofworked with some but not offten.
use "http://127.0.0.1:8000/connect/github" much the same no auth.

Tried the examples... got much the same results.
would using a domain pointed to my local ip and network address work?

Food for thought

Not so much an issue: I just saw this config.json from microsoft azure cloud service video.

Here it is:

screenshot_2015-08-02_18-48-51

Due to the nature of where I found this video, I feel I must explain myself. I was re-evaluating freedom-clouddom, and was forgiving video as a medium of what should be encyclopedic information which is a tangent of actually looking for surveying software, modular, deployable. (know any?).

Specific information through the login process

Hi, thank you for this amazing project!
I have this requirement and I'm wondering if I can accomplish it with your library. Depending on some parameters, just after the login I have to assign a different role to the logged user.
This means that I'd want to specify "log the user with the provider and after assign him the role X".
I cannot instantiate two provider for the same type (and I don't need to), but how can I "inform" the callback that the login process has started in one way or another, that the role X has been requested?

GitHub Oauth: redirect_uri_mismatch

I've been having some issues getting GitHub oauth working with Grant. I already have BitBucket Oauth set up correctly, so I'm using the library correctly. My setup:

GitHub
My callback URL in GitHub is set to http://local-kernl.com/api/v1/oauth/github/

local-kernl.com is an entry in my /etc/hosts file that directs the user to a virtual machine (vagrant) with Nginx installed. Nginx then acts as a reverse proxy to localhost:3000 where my Node app lives.

Node
My Node config looks like:

grant = new Grant({
  "server": {
    "protocol": "http",
    "host": "local-kernl.com",
    "transport": "session",
    "state": true
  },
  "bitbucket": {
    "__provider": {
        "oauth2": true
    },
    "key": "bitbucket-key",
    "secret": "bitbucket-secret",
    "callback": "/api/v1/oauth/bitbucket/",
  },
  "github": {
    "key": "github-key",
    "secret": "github-secret",
    "callback": "/api/v1/oauth/github/",
    "scope": [
      "public_repo",
      "repo",
      "repo_deployment",
      "repo:status"
    ]
  },
});

For BitBucket, when I hit /connect/bitbucket/ it makes the requests as expected and authorizes my app. With GitHub(/connect/github/) though, I get the response:

error=redirect_uri_mismatch
error_description=The redirect_uri MUST match the registered callback URL for this application.

The error is pretty obvious, but it doesn't look like I have the urls mismatched. I've tried several different iterations of this, including having it go straight to localhost:3000 with no luck. I read through your blog post @ https://scotch.io/tutorials/implement-oauth-into-your-express-koa-or-hapi-applications-using-grant, which I seem to be following correctly

Any help or ideas would be greatly appreciated. Thanks!

Problems with Yahoo

I'm using Node and Express 3 and tried the following:

var Grant = require('grant-express')
  , grant = new Grant({
"server": { 
  "protocol" : "http",
  "host" : "[my host]:[my port]"
},
"yahoo": {
  "key": "[OAUTH CONSUMER KEY]",
  "secret" : "[OAUTH SECRET]",
  "callback" : "[host and path for callback]"
}
});

var app = express()
app.use(express.logger())
app.use(express.cookieParser())
app.use(express.cookieSession({secret:'very secret'}))
// mount grant
app.use(grant)

When I hit the [host]/connect/yahoo URL, I get the following:

{
  "error": {
    "oauth_problem": "consumer_key_unknown"
  }
}

When I try the same consumer key and secret on the OAuth Playground app on your Heroku instance, with the Yahoo provider, it works fine.

Google authentication issue

I am using Grant for OAuth2 authentication with google in my express app. I supplied all the parameters in the config.json :

  {
    "server": {
    "protocol": "https",
    "host": "thooslo-com-shaunakde.c9.io"
  },
  "google":{
    "authorize_url": "https://accounts.google.com/o/oauth2/auth",
    "access_url": "https://accounts.google.com/o/oauth2/token",
    "oauth": 2,
    "custom_parameters": ["access_type"],
    "scope_delimiter":" ",
    "scope":["https://www.googleapis.com/auth/youtube","https://www.googleapis.com/auth/drive"],
    "client_id":"39109025743-veaeooi4v9ooirabeseujn8u2ohjbqf7.apps.googleusercontent.com",
    "client_secret":"DO8ozwoFqtP654jzi-wPQF10",
    "callback": "/users"
  }
  }

But it still refuses to send all the parameters. I get a "client_id" not sent error:

Error: invalid_request

Missing required parameter: client_id

Learn more
Request Details

    scope=https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/drive
    response_type=code
    redirect_uri=https://thooslo-com-shaunakde.c9.io/connect/google/callback

I modified the library to print out the URL and this is indeed the case:

Starting child process with 'node ./bin/www'
https://accounts.google.com/o/oauth2/auth?response_type=code&redirect_uri=https%3A%2F%2Fthooslo-com-shaunakde.c9.io%2Fconnect%2Fgoogle%2Fcallback&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fyoutube%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive
GET /connect/google 302 26.492 ms - 574

I did manage to get the first step to work once, by some permutation, but then it failed on client_secret not found.

Is there something I am doing wrong? The library seems to be non buggy.

Express empty req.session.grant

config:

{
    "server": {
        "protocol": "http",
        "host": "localhost:3000"
    },
    "intuit": {
        "request_url": "https://oauth.intuit.com/oauth/v1/get_request_token",
        "authorize_url": "https://appcenter.intuit.com/Connect/Begin",
        "access_url": "https://oauth.intuit.com/oauth/v1/get_access_token",
        "oauth": 1,
        "key": "mykey",
        "secret": "mysecret",
        "callback": "/api/connect/intuit",
        "custom_params": {
            "datasources": {
                "quickbooks": true,
                "payments" : false
            }
        }
    }
}

app.js

var Session = require('express-session')
    , session = Session({secret: 'very secret', resave: true, saveUninitialized: true})
    , Grant = require('grant-express')
    , grant = new Grant(config.connect);

app.use(session);
app.use(grant);

app.get('/api/connect/intuit', function (req, res) {
    console.log('----------------------------------------------------');
    console.log(req);
    console.log('----------------------------------------------------');
});

I'm getting {"error":"Grant: missing session or misconfigured provider"}.
When logging req.session in grant/lib/consumer/express.js:98 I get:

{ cookie: 
   { path: '/',
     _expires: null,
     originalMaxAge: null,
     httpOnly: true } }

So it seems like the grant details aren't being updated to the session.

I was using this example as reference: https://github.com/simov/grant/tree/master/example/express

What am I missing?

Set state by default?

Now that I think of it, we should just generated random state by default, right? This is the secure approach and grant is already using session (which it might as well use to store state).

Any reason for us to do a dynamic overwrite manually?

Avoiding sessions

Is there a reason why Grant requires the use of sessions and cookies?

Order of app.use(mount(grant)) and app.use(router(app))

It seems if I do it in this order:

app.use(router(app));
app.use(mount(grant));

Then on my final callback, eg. /handle_oauth_response route, ctx.params is not populated.

If I do it in reversed order, eg.

app.use(mount(grant));
app.use(router(app));

Then things are fine, I can get /login/:provider as ctx.params.provider.

I haven't had the chance to look at it more closely, could be an incompatibility between koa-router v4 and v3 (I am using v4, grant-koa is on v3).

But I believe the final url is out of grant's scope right? Are they also reserved routes?

Path prefix

I have an api that I have mounted on an url like this:
http://localhost/v2/social/

My provider callbacks are configured like this:
/v2/social/connect/twitter/done

The callbacks in between however, do not know about the /v2/social part. These callbacks will come back to http://localhost/connect/twitter/callback.

I tried setting the grant.server.host to localhost/v2/social, but this didn't work. I dived a bit into the source code and added a quick fix to be able to specify path prefix options. I tried it with express and it seems to work.

Here is what I did: arjanfrans@b18df70

In the config I then have something like this:

{
  server: {
    protocol: 'http',
    host: 'localhost',
    transport: 'session',
    path: '/v2/social'
  },
  twitter: {
    key: 'keyhere',
    secret: 'secrethere'
    callback: '/connect/twitter/done'
  }
}

To me it seems like a missing feature. It would be nice to see it integrated. I could work on a proper pull request if I have some time next week.

Thoughts?

Thanks.

Can't use reserved words as custom parameters

Some providers have custom parameters that can't be provided because they are reserved. Typically, Trello has a name parameter that is used to show the application name on the authentication page. It would be nice to be able to use reserved words as custom parameters.

grant-express app.use(session({secret:'grant'})) question

Hi, this is not really an issue just a question I couldn't find answer to anywhere.
What is the secret: 'grant' part stands for? I see it in different forms everywhere like secret: 'very secret'
am I supposed to replace 'grant'/'very secret' with a different value? what is it used for in the session function?

Thank you very much!

CORS issue with Facebook/Twitter in Backbone request

Hello. I configured grant on my hapijs server and it's working great but when I try to make a request to myappp:9000/connect/facebook (as well with twitter endpoint) using a Backbone model i'm getting a CORS error message and model's promise is failing. I've enabled CORS on my hapijs server and I'm pretty sure this is not an issue with grant but maybe you could help me to solve it without change everything on my backend. I've running my frontend in myapp.com:3000 and my backend in myapp.com:9000 and basically what I need is to perform a request from my Backbone frontend and get a redirection to facebook/twitter login screen, after the user log in, the model should be filled with the information i'm returning from my custom endpoint (which is the one that connects to facebook/twitter). Thanks a lot !

adding concur provider

A colleague created a fork in order to add concur as a provider to grant.

master...szafarcin:master

Wondering if there is a best practice on how to add new providers to grant? Can you assess the above fork on how practical it would be to merge it back into grant?

Thanks

Grant/Purest use with shopify

Hi, You might have noticed my tweet. I'm trying to use Grant and Purest for an app that I'm writing. The testing was going well. I was able to authenticate in test but once I deployed to Heroku, I ran into "Oauth error invalid_request: The redirect_uri is missing or not whitelisted" error. I mapped it in exactly the same way you did in the Grant demo app but am still getting this error.

As well, I'm not totally clear on how to use Purest. I have a clear idea of the REST api call for shopify but don't see what parameters I need to supply to and in what structure to use it for Shopify. Any and all help will be greatly appreciated.

Kind Regards,

John (legendsofthesport.co)

Allow custom providers

Any plans on allowing custom providers?

In config.init you could merge the passed in options into the result.

Using Grant without sessions

For our APP, we arent using any Sessions but instead, using JWT tokens. Is there a way to use Grant without having to use sessions?

"response.raw" not containing extra parameters

Using this configuration:

var connectConfig = {
            "server": {
                "protocol": "http",
                "host": "localhost:3000",
                "transport": "session",
            },
            "intuit": {
                "request_url": "https://oauth.intuit.com/oauth/v1/get_request_token",
                "authorize_url": "https://appcenter.intuit.com/Connect/Begin",
                "access_url": "https://oauth.intuit.com/oauth/v1/get_access_token",
                "oauth": 1,
                "custom_parameters": ["realmId", "dataSource"],
                "key": "MY_KEY",
                "secret": "MY_SECRET",
                "callback": "/oauth/connect/intuit"
            }
        }
        ;
app.use(new Grant(connectConfig));

When I print console.log(req.session.grant.response.raw); I get:

{ oauth_token_secret: 'THE_TOKEN_SECRET',
  oauth_token: 'THE_TOKEN' }

Even though I do see a request to the default callback, with those params:
http://localhost:3000/connect/intuit/callback?oauth_token=THE_TOKEN&oauth_verifier=VERIFIER&realmId=A_CORRECT_REALM_ID&dataSource=QBO

I'm guessing I'm just doing something wrong here... Any help would be greatly appreciated :)

Client Credential grant_type

Great awesome library! Does Grant-Express handle Client Credential grant type (without authorization code). If so, can I find how to set it up?

In config.json, I set it up:

  "custom": {
    "access_url": "https://myapitprovider/token",
    "oauth": 2,
    "key": "xxxxx",
    "secret": "xxxxxx",
    "callback": "/handle_callback"
  }

Thanks.

New koa consumer module fail to load

I think you're doing the right thing to split the consumers out of the main module but because I don't have express in my app it fails to load express when I require grant-koa because all consumers are required in index.js.

Perhaps they should be split into separate repositories with separate tests, so they're tested more like they will be used instead?

Oauth callback comes with empty object {}

I am a bit new to Hapi, and may be its just a config issue but I am not able to set up google auth in my service with grant.

Config

var grantconfig = {
  'server': {
    'protocol': 'http',
    'host': 'localhost:3333',
    'callback': '/callback',
    'transport': 'session',
    'state': true
  },
  'google': {
    'key': GOOGLE_CLIENT_ID,
    'secret': GOOGLE_CLIENT_SECRET,
    'scope': ['email', 'profile' ],
    'state': 'secret122',
    'callback': '/handle_google_callback'
  },
};

Server.js

var Hapi = require('hapi');
var Good = require('good');
var Path = require('path');
var yar = require('yar');
var grantconfig = require('./grantconfig');
var Grant = require('grant-hapi');
var grant = new Grant();
var server = new Hapi.Server();


server.connection({
  host: 'localhost',
  port: 3333
});


server.route({
  method: 'GET',
  path: '/handle_google_callback',
  handler: function (request, reply) {

    reply(JSON.stringify(request.query));
  }
});


server.register([
  {
    register: grant,
    options: grantconfig
  },
  {
    register: yar,
    options: {cookieOptions: {password: 'grant', isSecure: false}} 
  },
  {
    register: Good,
    options: {
      reporters: [{
        reporter: require('good-console'),
        events: {
          response: '*',
          log: '*'
        }
      }]
    }
  }  
], function(err){
  if(err){
    throw err; // something bad happened loading the plugin.
  }


  server.start(function(){
    console.log('Server running at:', server.info.uri);
  });
});

And This is response in the server.

150726/185255.451, [response], http://localhost:3333: get /connect/google/callback {"code":"5d09c0185472d78fa55a","state":"secret122"} 302 (1733ms) 
150726/185257.188, [response], http://localhost:3333: get /handle_google_callback {} 200 (2ms) 

As you can see, /handle_google_callback is not getting anything in response.
Can you please spot the issue?

koa-grant: How to get the user info from session

I want to find a way to get the user info from the session after login.

For example:

// suppose user have login
router.get('/demo', function *(next) {
  if (!this.session.grant) {
    this.redirect('/login');
  } else {
   // get the user info from DB which I saved after user login successfully,
   //    eg, saved  in `/hanlde_provider_callback
    user = yield getUserInfo(this.session.grant.userId);
  }
}

Seems I can't add a new property to session in the /handle_provider_callback, so I don't how to connect the special session with the db item (I want to store users in my db). Do you have any idea?

Thank you.

Does not work with hapi-auth-jwt2

If I add to my working code the npm module hapi-auth-jwt2, then all calls to /connect/provider returns 401.
How I added it:
as plugin in hapi require('hapi-auth-jwt2')
with a configuration

    server.auth.strategy('jwt', 'jwt', {
      key: config.JWT.SERIAL,
      validateFunc: jwt.validate,
      verifyOptions: {
        algorithms: [ config.JWT.ALGORITHM ],
        ignoreExpiration: true
      },
      headerKey: config.JWT.HEADER
    });

    server.auth.default('jwt');

Then the routes for grant have the configuration for disable jwt:

    config: {
      auth: false
    }

It returns the body
{"statusCode":401,"error":"Unauthorized","message":"Missing authentication"}
and the headers

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Token
content-type: application/json; charset=utf-8
cache-control: no-cache
vary: accept-encoding
content-encoding: gzip
Date: Wed, 26 Oct 2016 08:30:58 GMT
Connection: keep-alive
Transfer-Encoding: chunked

Do you have an idea why this is happening and could it be resolved by me or you?

How to debug?

I am trying to get the amazon provider to work, I'm having problems but I have no idea what the problem is. I have Facebook working. How does one debug this? I'm thinking of writing a simple server using just the node https server (since it seems like Amazon only works with https, not http). Any help, ideas, suggestions? Thanks

Supply additional headers with request

Hi there,

First, big props for this lib! Very easy to setup ๐Ÿ‘ I am trying to setup a connection with the discogs oauth api, but they require to send an additional user-agent header. How can I configure this in the grant lib? Here's my setup:

var express = require('express')
var logger = require('morgan')
var session = require('express-session')
var Grant = require('grant-express')

var grant = new Grant({
  'server': {
    protocol: 'http',
    transport: 'session',
    state: true,
  },
  'discogs': {
    key: process.env.DISCOGS_CONSUMER_KEY,
    secret: process.env.DISCOGS_CONSUMER_KEY,
    callback: '/handle_discogs_callback',
  },
})

var app = express()
app.use(logger('dev'))
app.use(session({ name: 'grant', secret: 'very secret', saveUninitialized: false, resave: false }))
app.use(grant)

app.get('/handle_discogs_callback', (req, res) => {
  res.end(JSON.stringify(req.query))
});

app.listen(4000, () => {
  console.log('Express server listening on port ' + 4000)
});

Session managment with Hapijs

I'm using Grant with Facebook and Twitter and it works great but the problem is when I try to manage the session. The plugin generates a session called grant when it redirects to the facebook pr twitter login, and not when you logged in successfully. Do I need to use a custom session using yar ? Btw, awesome work ! Thanks.

Koa2 implementation question

Any thoughts on how to handle Koa consumer after Koa2 released?

Chrome 55 released today and there is progress on a Node7 release that will ship with V8 5.5.
Node may land with official async/await support in less than a month.
Same for Koa2.

Would you ship a Koa2 version or replace existing one?
Thanks.

Session Issues

I'm trying to use grant with koa, but my boss is pretty insistent that we not use session store for ANYTHING except the auth flows. So I can't just do what you examples do:

app.use(session(app)

I'm using the koa-joi-router and I tried this:

router.use('/connect', session(app))

to limit it to just the grant endpoints but I keep getting an error that I the session is missing or misconfigured. Based on some logs I added to grant in my node_modules folder, it looks like the redirect comes back and grant can't find session.grant or a provider. I added this to the callback generator around line 119:

    var grant = this.session.grant || {}
    var provider = config.provider(app.config, grant)
    var flow = flows[provider.oauth]
    console.log('callback invoked', this.session, provider);

which spits out: callback invoked {} {}.

Any suggestions or workarounds?

Change provider config dynamically within the backend

From what I understand, is that you can override provider configuration by posting a form to an override route.

I need to override the provider config, but this is not controlled from a form. I have a database that contains keys and secrets. I want to override provider configurations within my backend application, by doing a query to my database to get the key and secret from a provider.

I achieved this by putting in a callback that is called when a connect is done (not a very elegant solution though):
https://gist.github.com/arjanfrans/71c180e7b3274545e2a500b2f8db2233#file-express-js-L10
https://gist.github.com/arjanfrans/71c180e7b3274545e2a500b2f8db2233#file-express-js-L71

Inside this callback I do my database query and then override the config with my key and secret added.

I basically need the dynamic override ride, without the form part. Is what I am trying to achieve possible with the current version of Grant?

Invalid cookie value with Hapi

I get this error from grant when using with hapi:
{"statusCode":400,"error":"Bad Request","message":"Invalid cookie value"}

So I tried the examples in the git repo. The express example works as expected, and I can log into facebook with no issues.
The hapi example gets the same error (above) as my code. I'm using a copy of the same config file with both examples.
I'm using this url to test both: http://localhost:3000/connect/facebook

I've tried logging out of facebook and clearing my browser cache, but it didn't help.

Alternative on transporting access token

Currently the design is to do another redirect with GET, where querystring contains the access token. 2 things of this approach concerns me:

  1. For oauth 1, this can potentially be abused as we expose a GET route that have side-effects. Unlike oauth 2, access token does not expire, which makes it plausible through CSRF.
  2. This approach means extra security consideration are needed, for example web logs now contains user access token and secret, and logs can be less protected than database.

/connect/:provider/callback route is safe because the GET route is called with a randomized state.

In my previous projects I usually do that through sessions, it means:

  1. Access token and secret are not exposed, even to users.
  2. HTTPS + Signed cookies makes it a lot harder (if not impossible) to craft an attack on the final callback.
  3. Session cookies allow us to do things like oauth timeout (make sure oauth is started and completed within a reason timeframe)

Just something to consider.

Bump koa dependencies

Is there a repo for grant-koa, the meta package locked koa-session to 3.0.0 and it throws errors when used with 3.1.0

Having meta package also lead to a few problems: we can't contribute easily or debug package (ie. temporally fork the repo and set package.json to use forked/grant)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.