hapijs / bell Goto Github PK
View Code? Open in Web Editor NEWThird-party login plugin for hapi
License: Other
Third-party login plugin for hapi
License: Other
The client resource()
method puts POST payloads in the query. Also, some providers (I'm looking at your stupid face Twitter) require the form-encoded payload to be OAuth compliant which means strings with '!'
will not get encoded using normal encoding and break. This fixes it in a way that will work under all versions of node.
If you didn't use the Bell.oauth.Client
API, you are not affected by this change. If you did, you need to replace calls to client.request()
with the new client.resource()
.
It seems that this project lacks support for a passwordless login scheme. T would be helpful to know if a passwordless login scheme is within the scope of this project, and whether any considerations have been made to support this feature in the near future.
Replace nipple
with wreck
After successfull authentication, querystring are not retained for protected routes.
Ex. For route /auth/login/twitter
protected with twitter
auth strategy in required
mode
URL /auth/login/twitter?next=%2F/home
redirects to /auth/login/twitter
after authenticated successfully. Should it retain query params in redirected url after authenticated?
Is this valid behavior? If not, how we achieve it by using temporary state between the authorization flow?
A dependancy on http://passportjs.org/ to obtain support for other providers/strategies.
Notes:
Side issues:
Downstream issues:
Current client provides a get()
method that automatically parses the response. I need a way to get back the response stream untouched as well as have access to methods other than GET
.
I'm getting this error response using the Dropbox provider during the POST to https://api.dropbox.com/1/oauth2/token
. Looks like it was introduced here: 7b54667#diff-84fad1d3b3913ec86805e857580c5d54R199.
Is this a matter of the Dropbox API using a stricter implementation or is there something else going on here?
I'm actually using Bell and hapi-auth-cookie and I'm not sure which (or both) plugins would need to be involved since I don't quite understand yet how they interact, but I need to be able to send someone to a route to initiate auth and after they're successfully authenticated, redirect them to that URL.
It seems like this is a standard part of the OAUTH process, or at least once was, but I'm wondering if these plugins use that functionality and thus need to provide it themselves to effectively bring it back.
I'm trying to build a plugin to ease the use of bell and hapi-auth-cookie hapi-bell-cookie-auth-plugin, but just today I found another doing something similar https://github.com/hofan41/clapper and even more nicely written (though mine is very fresh in my defense).
I'm going to post this in hapi-auth-cookie also and will close on either side if/when it's clear that it's a one-sided issue.
For additional clarification, the key point there was, "I need to be able to send someone to a route to initiate auth and after they're successfully authenticated, redirect them to that URL."
Right now, I can control the final redirect, but if I put an auth strategy (using Bell) on a route, I cannot find any way to capture the ReturnUrl, then persist it in a way that can be retrieved (unique that that logical session) later.
After logging in with Yahoo, bell exposes the access token and token secret passed from Yahoo. This access token expires after 60 min. In order to easily refresh this token, a session_handle is needed, which Yahoo provides upon original login. Without this session_handle a user is required to re-login every 60 min in order to get a new access token.
It would be great it bell could retrieve the session_handle upon login, as it does the access token and token secret.
Yahoo documentation here: https://developer.yahoo.com/oauth/guide/oauth-refreshaccesstoken.html
Hi everyone,
I'm actually using Bell for Facebook and Google without any problem but I noticed that used API for both providers are deprecated.
Here's the documentation about Google: https://developers.google.com/accounts/docs/OAuth2LoginV1
And Facebook send this warning when I want to authenticate:
Is there any plan to update Facebook and Google providers code ?
Thank you
Hi Eran, I actually wanted to use Passport, but found this by chance. What is the equivalent of passports' "local-strategy"?
Google (along with others) pass back expires_in with the token and I'd like to store that to know when I should request a new token. It should be a very easy change to just add expires_in here: https://github.com/hapijs/bell/blob/master/lib/oauth.js#L213. Let me know if you want me to submit a pull request.
A Google OAuth example would be much appreciated. Thanks.
bell errors out with Failed obtaining github user profile
when using a custom uri option.
GitHub Enterprise requires API request paths be prefixed with /api/v3/
, unlike GitHub which needs no prefix but uses the different domain api.github.com
.
This should be very easy to fix. I'm working on it.
Feels that providers should be separate modules. What do you think?
With the following error -
"Authentication failed due to: Failed obtaining google user profile"
Can anyone verify the google.js example is working ? Am I doing something wrong ?
-Drew
Currently, it is not possible to configure some of the options in this plugin using environment variables, since some of the options are assumed to be boolean/number types, while environment variables are strings.
I would like to request that this be made possible by using Joi's nifty validation() function which will accept a boolean/number string and return a transformed object with the appropriate types.
Pull request incoming.
Hi all,
I cannot find a way to make bell usable with Facebook. Here is my server config:
server.register(Bell, function (err) {
server.auth.strategy('facebook', 'bell', {
provider: 'facebook',
password: 'password',
isSecure: false,
// Make sure to set a "Callback URL" and
// check the "Allow this application to be used to Sign in with Twitter"
// on the "Settings" tab in your Twitter application
clientId: 'myClientID', // Set client id
clientSecret: 'myClientSecret' // Set client secret
});
server.route({
method: '*',
path: '/bell/facebook',
config: {
auth: {
strategy: 'facebook',
mode: 'try'
},
handler: function (request, reply) {
if (!request.auth.isAuthenticated) {
return reply('Authentication failed due to: ' + request.auth.error.message);
} else {
reply('<pre>' + JSON.stringify(request.auth.credentials, null, 4) + '</pre>');
}
}
}
});
});
However i obtain always an Authentication failed due to: Failed obtaining facebook access token
I double checked my Facebook app developer page and on the basic settings I've configured a WebSite that point to http://thalion.local:3000/bell/facebook/ that's my server route for bell authenticatin
Also, on Advanced Settings I've included Valid OAuth Redirect URI to point to http://thalion.local:3000/bell/facebook/
I'm stucked without any idea. Any hints can be much appreciated!
Hi,
When the callback is called the authentication fails because the application can't obtain the google access token. I already double checked my configurations and everything seem ok.
Anyone could have some guess why this error is happening?
{ isAuthenticated: false, credentials: undefined, artifacts: undefined, session: { set: [ Function ], clear: [ Function ] }, mode: 'try', strategy: 'google', error: { [ Error: Failedobtaininggoogleaccesstoken ]data: '{\n "error" : "invalid_grant",\n "error_description" : "Invalid code."\n}', isBoom: true, output: { statusCode: 500, payload: [ Object ], headers: { } }, reformat: [ Function ] } }
I would like to have login using any of the fb, twitter, google or yahoo logins.
Is there a way to configure multiple providers for the auth strategy?
Once the Travelogue project was discontinued, it would be good to see the LDAP support in Bell.
Hi,
Is there a way to set the fields to return from the LinkedIn API?
e.g.: https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address)
Hi,
actually the expiration date of facebook access token won't be mapped properly.
You implemented a default mapping:
oauth.js - line 229: expiresIn: payload.expires_in
but the facebook payload attribute is called 'expires' only.
Cheers
Stephan
Please welcome https://github.com/ldesplat as the new maintainer of bell!
Hello,
My project is using Microsoft Azure with Active Directory.
Do you have some information about the integration of this feature with Bell Module ?
Thank you
I'm using bell at the server side while at the client side I'm using Angular. I call the /auth/facebook entrypoint at the server side by using $http but I get the error
No 'access-control-allow-origin' header is present on the requested resource.
Have you any suggestions how to use bell with angularjs frontend?
Clean up test to be in line with new standards.
I'm looking for a way to layer authentication strategies. For example I'd like someone who's authenticated with hapi-auth-basic
to also connect a twitter account using bell
.
Any ideas are much appreciated.
I have bell setup with hapi-auth-cookie following the structure of postmile but I don't have any idea on how to test my server. could you please write an example test here or at postmile repo.
Phabricator is a useful PM tool that we have been using that also ships with an oauth 2.0 api.
A new OAuth 2.0 property (useParamsAuth
) has been added to indicate if the client ID and client secret are sent in the Authorization header or as query parameters. The default is to use the Authorization header. The existing OAuth 2.0 providers have been updated to follow the specification.
I am using WSO2 and bell. I see that in bell in https://github.com/hapijs/bell/blob/master/lib/oauth.js#L191-L203
We send both the client_id and client_secret in the query and in the Authorization header. Looking at the source code of WSO2 it says that the standard does not allow both ways to be sent at the same time. I looked over the standard. rfc6749 especially section 2.3.1 and section 5.2 invalid_client . I do not see that listed.
WSO2 does not allow that behavior.
Either way, I think this could be exposed in another option when defining the provider (credTransport: ['basic', 'query']) with both as default to be backwards compatible? Better name? Better place to put it?
Thank You.
What's the trick to getting auth cookies to be set?
plugin.register(require('bell'), function(err) {
plugin.auth.strategy('facebook', 'bell', {
provider: 'facebook',
password: '12345',
cookie: 'auth',
clientId: settings.get('facebook.appId'),
clientSecret: settings.get('facebook.appSecret'),
isSecure: false,
isHttpOnly: true
});
plugin.route({
method: ['GET', 'POST'],
path: '/facebook',
config: {
auth: 'facebook',
handler: function(request, reply) {
var profile, provider, _ref;
_ref = request.auth.credentials, provider = _ref.provider, profile = _ref.profile;
return serializeUser(provider, profile).then(function(user) {
request.user = user;
return reply.redirect('/');
});
}
}
});
plugin.ext('onPreAuth', function(request, next) {
console.log('>>>>> pre', request.auth);
return next();
});
return plugin.ext('onPostAuth', function(request, next) {
console.log('>>>>> post', request.auth);
return next();
});
});
After initial redirect my request.auth
is always at authenticated state and cookie is never set. A test reply.state('foo', 'bar')
works fine and the cookie is preserved.
What am I doing wrong? I think I tried nearly everything.
When I try to use the facebook strategy, I get the following error:
Debug: auth, unauthenticated, error, facebook
Error: Missing facebook request token cookie
at Object.exports.create (D:\Info\coven-sso\node_modules\bell\node_modules\b
oom\lib\index.js:21:17)
at Object.exports.internal (D:\Info\coven-sso\node_modules\bell\node_modules
\boom\lib\index.js:262:99)
at Object.authenticate (D:\Info\coven-sso\node_modules\bell\lib\oauth.js:177
:31)
at D:\Info\coven-sso\node_modules\hapi\lib\auth.js:227:30
at internals.Protect.run (D:\Info\coven-sso\node_modules\hapi\lib\protect.js
:56:5)
at authenticate (D:\Info\coven-sso\node_modules\hapi\lib\auth.js:218:26)
at internals.Auth._authenticate (D:\Info\coven-sso\node_modules\hapi\lib\aut
h.js:348:5)
at internals.Auth.authenticate (D:\Info\coven-sso\node_modules\hapi\lib\auth
.js:177:17)
at D:\Info\coven-sso\node_modules\hapi\lib\request.js:370:13
at iterate (D:\Info\coven-sso\node_modules\hapi\node_modules\items\lib\index
.js:35:13)
Debug: internal, error
Error: Missing facebook request token cookie
at Object.exports.create (D:\Info\coven-sso\node_modules\bell\node_modules\b
oom\lib\index.js:21:17)
at Object.exports.internal (D:\Info\coven-sso\node_modules\bell\node_modules
\boom\lib\index.js:262:99)
at Object.authenticate (D:\Info\coven-sso\node_modules\bell\lib\oauth.js:177
:31)
at D:\Info\coven-sso\node_modules\hapi\lib\auth.js:227:30
at internals.Protect.run (D:\Info\coven-sso\node_modules\hapi\lib\protect.js
:56:5)
at authenticate (D:\Info\coven-sso\node_modules\hapi\lib\auth.js:218:26)
at internals.Auth._authenticate (D:\Info\coven-sso\node_modules\hapi\lib\aut
h.js:348:5)
at internals.Auth.authenticate (D:\Info\coven-sso\node_modules\hapi\lib\auth
.js:177:17)
at D:\Info\coven-sso\node_modules\hapi\lib\request.js:370:13
at iterate (D:\Info\coven-sso\node_modules\hapi\node_modules\items\lib\index
.js:35:13)
Here's my code (basicly your twitter example)
var Hapi = require('hapi');
var server = new Hapi.Server({ debug: { request: ['error'] } });
server.connection({ port: 3000 });
server.register(require('bell'), function (err) {
server.auth.strategy('facebook', 'bell', {
provider: 'facebook',
password: 'test',
clientId: '',
clientSecret: '',
isSecure: false
});
server.route({
method: ['GET', 'POST'],
path: '/login',
config: {
auth: 'facebook',
handler: function (request, reply) {
if (!request.auth.isAuthenticated) {
return reply('Authentication failed due to: ' + request.auth.error.message);
}
return reply.redirect('/home');
}
}
});
server.route({
method: ['GET'],
path: '/home',
config: {
handler: function (request, reply) {
console.log(request.auth.credentials);
return reply(JSON.stringify(request.auth.credentials));
}
}
});
server.start(function () {
console.log('Server running at:', server.info.uri);
});
});
So, it looks like clientSecret was changed to client_secret here:
96ef98c#diff-84fad1d3b3913ec86805e857580c5d54R199
and that breaks my code since when I try to set client_secret I get:
child "clientSecret" fails because ["clientSecret" is required] {"name":"ValidationError","details":[{"message":"\"clientSecret\" is required","path":"clientSecret","type":"any.required","context":{"key":"clientSecret"}}],"_object":{"ttl":31536000000,"domain":".gethuman.com","isSecure":false,"password":"MIICXgIBAAKBgQC4xBeP3h36ikta","cookie":"bell-facebook","clientId":"523625311006913","client_secret":"e8f655bd2b7ebecf977c274cd0c915dc","provider":{"useParamsAuth":true,"protocol":"oauth2","auth":"https://www.facebook.com/v2.3/dialog/oauth","token":"https://graph.facebook.com/v2.3/oauth/access_token","scope":["email"]},"name":"custom"}}
but then if I set clientSecret as I have been doing, I get:
Error validating client secret.
In debugging my Bell I can see that this is because client_secret is null here:
https://github.com/hapijs/bell/blob/master/lib/oauth.js#L199
I don't mind submitting a pull request to fix this but I noticed that clientSecret is actually used in other places of the code so perhaps there is something I am missing. If it is OK with you I would very simply submit a pull request to do:
query.client_secret = settings.client_secret || settings.clientSecret;
Hi,
I am not sure if this is either totally obvious or not supported, but I want to use bell with a frontend and as an API authentication method.
The procedure would look like that the user is signed in at the frontend and then only sends his own access_token to the backend (e.g. from facebook). The backend then authenticates (with Bell) that access token and would then return its own token from its own authentication strategy.
So I only need bell as a authentication strategy that is taking an access_token from the request and authenticates it against my third party provider (facebook) and also gives me the user information and then I can do in my actual route handler whatever I want.
This seems to be the main purpose, but I could not find documentation about the configuration for this approach. Since most of the use cases seem to be browser based and work with redirect urls.
I have also tried to send send the authentication data to my endpoint via:
server.inject({
method: 'POST',
url: '/auth/facebook',
payload: {
access_token: 'MY_TOKEN'
}
But then I only get a 302 response.
So how would I approach just authenticating a provided access_token with the third party?
I asked this at Stackoverflow
I access the /login route and I get redirected to Twitter, I authorize the app and then I'm redirected back to /login?oauth_token=xxxxxxx&oauth_verifier=xxxxxxx where I can have access to the user profile in the request.auth.credentials.
The problem came when I tried to reject the app. At Twitter, Instead of clicking the "Sign In" button, I clicked the "Cancel" button and then the "Return to site name" button. This last button redirects me to /login?denied=xxxxxx and then I'm redirected (again) to Twitter to approve the app.
I tried to handle this scenario using the example given in https://github.com/hapijs/bell#handling-errors but can't get it to work.
server.route({
method: ['GET', 'POST'],
path: '/login',
config: {
auth: {
strategy: 'twitter',
mode: 'try'
},
handler: function (request, reply) {
if (!request.auth.isAuthenticated) {
return reply('Authentication failed due to: ' + request.auth.error.message);
}
return reply.redirect('/home');
}
}
});
It seems that before checking the request.auth it interprets the /login route and redirects to Twitter. I still don't understand very well the Bell module but it might be that the Twitter strategy is expecting the oauth_token and oauth_verifier in the request.params, but the denied param is not interpreted by the strategy and that's why the redirect happens.
How to handle this scenario?
Just wondering if it's possible to force to redirect_uri
to be https. We're deploying hapi on Heroku and heroku does SSL termination at the edge of their network. This means we run hapi as http. Bell seems to take the protocol the site is running as and make that the protocol for the redirect_uri - this causes an issue when the provider (e.g. facebook) redirect back to our site as it comes back as http instead of https.
I couldn't see in the options a way to tell bell to use https for the redirect_uri protocol. Just wondering if there is a work around for the moment.
It would be useful if there were a wiki that provided reference material associated with the various providers. It can be somewhat difficult to track down the documentation about endpoints, scopes, response bodies, etc.. This information has to be researched when creating a provider for the first time, so it couldn't hurt if it was recorded at that time. This should help in the long run in maintaining the code when the provider updates there service. Here is a sample associated with the Google provider:
Endpoints:
Goggle discovery doc for the plus service:
https://www.googleapis.com/discovery/v1/apis/plus/v1/rest
Auth and Token Details:
Auth and Token based on values found in the OpenIDConnect discovery document:
https://accounts.google.com/.well-known/openid-configuration
Scopes:
Scope discussion can be found here:
https://developers.google.com/+/web/api/rest/oauth#plus.login
Response body:
Documentation of response body:
https://developers.google.com/+/web/api/rest/latest/people#resource
Is it possible to load Bell plugin this way?
server.register([
{
register: require('bell'),
options: {
provider: 'google',
password: 'password',
isSecure: false,
// You'll need to go to https://console.developers.google.com and set up an application to get started
// Once you create your app, fill out "APIs & auth >> Consent screen" and make sure to set the email field
// Next, go to "APIs & auth >> Credentials and Create new Client ID
// Select "web application" and set "AUTHORIZED JAVASCRIPT ORIGINS" and "AUTHORIZED REDIRECT URIS"
// This will net you the clientId and the clientSecret needed.
// Also be sure to pass the redirect_uri as well. It must be in the list of "AUTHORIZED REDIRECT URIS"
clientId: '',
clientSecret: '',
providerParams: {
redirect_uri: server.info.uri + '/auth'
}
}
},
{
register: require("hapi-route-auto-reg"),
options: {
directory: __dirname + '/routes'
}
}
], function (err) {
if (err) throw err;
server.route({
method: '*',
path: '/auth',
config: {
auth: 'google',
handler: function (request, reply) {
reply('<pre>' + JSON.stringify(request.auth, null, 4) + '</pre>');
}
}
});
}
);
I'm getting this
{"statusCode":500,"error":"Internal Server Error","message":"An internal server error occurred"}
when being redirected from facebook back to http://localhost:8080/auth/facebook?code=AQBfow3ErUA7-TB7N...
no stack trace in the console :( will try to investigate tomorrow...
here's my setup
register = (plugin, options, next) ->
plugin.register require('bell'), (err) ->
plugin.auth.strategy 'facebook', 'bell',
provider: 'facebook'
password: '12345'
clientId: settings.get 'facebook.appId'
clientSecret: settings.get 'facebook.appSecret'
plugin.route
method: ['GET', 'POST']
path: '/facebook'
config:
auth: 'facebook'
handler: (request, reply) ->
console.log request
# // Perform any account lookup or registration, setup local session,
# // and redirect to the application. The third-party credentials are
# // stored in request.auth.credentials. Any query parameters from
# // the initial request are passed back via request.auth.credentials.query.
reply.redirect '/admin'
next()
I am using hapijs 7.5.3 with bell 1.3.1.
I'd like to register multiple auth strategies with one provider (i.e. facebook) like this:
plugin.auth.strategy('facebookHost', 'bell', 'try', {
provider: 'facebook',
clientId: options.facebook.clientId,
clientSecret: options.facebook.clientSecret,
password: options.cookie.password,
isSecure: options.cookie.isSecure,
scope: ['email', 'manage_pages', 'create_event', 'publish_stream', 'user_likes', 'user_events', 'rsvp_event', 'user_friends'],
providerParams: {
display: 'touch'
}
});
plugin.auth.strategy('facebookLogin', 'bell', 'try', {
provider: 'facebook',
clientId: options.facebook.clientId,
clientSecret: options.facebook.clientSecret,
password: options.cookie.password,
isSecure: options.cookie.isSecure,
scope: ['email', 'user_likes', 'user_events', 'rsvp_event', 'user_friends'],
providerParams: {
display: 'popup'
}
});
I get the error Error: State already defined: bell-facebook
.
Are multiple auth strategies not possible or am I doing something stupid?
Hi!
I would like to question about this redirection here
When this redirection is done, the client gets notified of two parameters: code and state. However, these parameters should concern just the server, right? Does the client need to know any of these information?
Do my questions make any sense? Could it be a vulnerability?
For example, according to the facebook documentation, I can exchange code for an access token.
First. I would like know if I really should worry about the fact of the client knowing about the code and state parameters.
Second. How could we avoid this redirection in order not to get the user notified about information that should concern just the server?
Finally. Thank you so much for building hapi.js and bell :)
Google now uses the Google Plus services. More information on the service is located here: https://www.googleapis.com/discovery/v1/apis/plus/v1/rest You will need to update the
The profile object has changed in the following ways:
email
is now emails
and is an array of objects with the following keys: type
and value
name
renamed first
and last
to givenName
and familyName
respectivelyThe scope changed so that r_fullprofile
and r_contactinfo
are removed and r_basicprofile
is added instead. This fixes a bug where the contact information wasn't being retrieved. This should only impact your service if you depended on one of the other scopes.
It seems this was supported in travelogue with passport. I still don't know why travelogue was abandoned in favor of bell but it kind of leaves new projects in no mans land that that need SAML support.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.