oauthjs / express-oauth-server Goto Github PK
View Code? Open in Web Editor NEWComplete, compliant and well tested module for implementing an OAuth2 Server/Provider with express in node.js
License: MIT License
Complete, compliant and well tested module for implementing an OAuth2 Server/Provider with express in node.js
License: MIT License
is this a bug as it didn't return anything
Hey,
Just a head's up that the 'Quick Start' documentation has a minor mistake which could potentially cause a few headaches :)
app.use(app.oauth.authorise());
should be changed to be...
app.use(app.oauth.authorize());
Thanks!
ExpressOAuthServer
should wrap containing functions in a closure to ensure this
is properly scoped. Currently it's making use of module scope, but a closure is more straight forward and portable (I'm currently using the ExpressOAuthServer directly in my server implementation)
https://github.com/oauthjs/express-oauth-server/blob/master/index.js#L17
Is this project still being maintained? It's a very useful package!
https://travis-ci.org/oauthjs/express-oauth-server
The examples in this repo have been very helpful to me in trying to understand exactly what is expected of a Model. However, when I look at the Migrating from 2.x to 3.x guide, it seems like the model specifications have changed. Would it be possible to update the examples here accordingly? Thanks, btw, for sharing this code.
If using this project with latest oauth2-server
, express-oauth-server
will fail if using custom express middleware. For example:
const req = new Request(request);
const res = new Response(response);
expressOAuthServer.server.token(req, res).then(() => {
/* stuff */
})
The above will throw this error.
This occurs if the parent project is using a newer version of oauth2-server
than the one listed in express-oauth-server
package.json
. The instanceof
fails I suppose due to newer class properties; though I haven't looked into it.
A workaround is to import Require
and Response
from node_modules/express-oauth-server/node_modules/oauth2-server
. This will be fixed once the project is updated to use the latest oauth2-server
.
Greetings,
Excellent work on this project! With the lastest oauth2-server
I have a working client
and password
model. I am able to generate and verify user, client, and token credentials.
My last step is creating a login page and redirect flow. I am attempting to use express-oauth-server
. Now, the example given contains a TODO:
:
// Post login.
app.post('/login', function(req, res) {
// @TODO: Insert your own login mechanism.
if (req.body.email !== '[email protected]') {
return render('login', {
redirect: req.body.redirect,
client_id: req.body.client_id,
redirect_uri: req.body.redirect_uri
});
}
// Successful logins should send the user back to /oauth/authorize.
var path = req.body.redirect || '/home';
return res.redirect(util.format('/%s?client_id=%s&redirect_uri=%s', path, req.query.client_id, req.query.redirect_uri));
});
This example seems to expect the express
middleware to verify the credentials? Following other users examples, I am instead verifying user/client credentials in the model (getClient
, getUser
); not express
middleware.
So alternatively I am trying to use the provided token()
method. For example:
import {Express} from 'express';
import settings from '../settings';
import {expressOAuthServer} from './auth';
export default function (app: Express) {
app.post(
'/login',
(request, _response, next) => {
request.body.client_id = '';
request.body.client_secret = '';
request.body.redirect_uri = '';
request.body.grant_type = '';
request.body.scope = '';
next();
},
expressOAuthServer.token()
);
}
Authentication works, and a token is generated. After using token()
, though, I am given token in a response body but without a redirect. How exactly is the client supposed to get the token? Here it seems to redirect if the response contains a 302
; but if I set a 302
in my response, new Response(res)
seems to reset it back to a 200
. .token()
also doesn't redirect back to /login
on a failed attempt.
So instead I am using expressOAuthServer.server.token(req, res).then((val) => {/* handle token */});
, which is more manual. It seems wrong. I feel like I am missing something obvious in how I am using express-oauth-server
and am hoping someone can give me a couple working examples. Thanks!
Hi. I have a simple route:
app.get('/secret_area', oauth.authenticate(), function(req, res) {
res.send('OK');
});
oauth.authenticate() is always calling next and trying to send 'OK'. I am also getting: Error: Can't set headers after they are sent.
when someone sends a invalid bearer token. I believe this is not how it suppose to work.
This middleware is actually very simple. So ported it to typescript.
Install latest oauth2-server as separate package and avoid using this obsolete package.
import { Promise } from "bluebird";
import {
Request,
Response,
AuthenticateOptions,
AuthorizationCode,
AuthorizeOptions,
ServerOptions,
TokenOptions,
Token,
InvalidArgumentError,
OAuthError,
UnauthorizedRequestError,
} from "oauth2-server";
import * as NodeOAuthServer from "oauth2-server";
import {
RequestHandler,
Response as ExpressResponse,
Request as ExpressRequest,
NextFunction,
} from "express";
interface IOAuthServerOptions extends
ServerOptions {
useErrorHandler?: boolean;
continueMiddleware?: boolean;
}
export function OAuthServer(options?: IOAuthServerOptions): void {
options = options || {} as IOAuthServerOptions;
if (!options.model) {
throw new InvalidArgumentError('Missing parameter: `model`');
}
this.useErrorHandler = options.useErrorHandler ? true : false;
delete options.useErrorHandler;
this.continueMiddleware = options.continueMiddleware ? true : false;
delete options.continueMiddleware;
this.server = new NodeOAuthServer(options);
}
/**
* Authentication Middleware.
*
* Returns a middleware that will validate a token.
*
* (See: https://tools.ietf.org/html/rfc6749#section-7)
*/
OAuthServer.prototype.authenticate = function (options: AuthenticateOptions): any {
const that = this;
return function (req: ExpressRequest, res: ExpressResponse, next: NextFunction): any {
const request = new Request(req);
const response = new Response(res);
return Promise.bind(that)
.then(function (): Promise<Token> {
return (this.server as NodeOAuthServer).authenticate(request, response, options);
})
.tap(function (token: Token): void {
(res as any).locals.oauth = { token };
next();
})
.catch(function (e: Error): void {
return handleError.call(this, e, req, res, null, next);
});
};
};
/**
* Authorization Middleware.
*
* Returns a middleware that will authorize a client to request tokens.
*
* (See: https://tools.ietf.org/html/rfc6749#section-3.1)
*/
OAuthServer.prototype.authorize = function (options: AuthorizeOptions): RequestHandler {
const that = this;
return function (req: ExpressRequest, res: ExpressResponse, next: NextFunction): any {
const request = new Request(req);
const response = new Response(res);
return Promise.bind(that)
.then(function (): Promise<AuthorizationCode> {
return (this.server as NodeOAuthServer).authorize(request, response, options);
})
.tap(function (code: AuthorizationCode): void {
(res as any).locals.oauth = { code };
if (this.continueMiddleware) {
next();
}
})
.then(function (): void {
return handleResponse.call(this, req, res, response);
})
.catch(function (e: Error): void {
return handleError.call(this, e, req, res, response, next);
});
};
};
/**
* Grant Middleware.
*
* Returns middleware that will grant tokens to valid requests.
*
* (See: https://tools.ietf.org/html/rfc6749#section-3.2)
*/
OAuthServer.prototype.token = function (options: TokenOptions): RequestHandler {
const that = this;
return function (req: ExpressRequest, res: ExpressResponse, next: NextFunction): Promise<void> {
const request = new Request(req);
const response = new Response(res);
return Promise.bind(that)
.then(function (): Promise<Token> {
return (this.server as NodeOAuthServer).token(request, response, options);
})
.tap(function (token: Token): void {
(res as any).locals.oauth = { token };
if (this.continueMiddleware) {
next();
}
})
.then(function (): void {
return handleResponse.call(this, req, res, response);
})
.catch(function (e: Error): void {
return handleError.call(this, e, req, res, response, next);
});
};
};
const handleResponse = function (req: ExpressRequest, res: ExpressResponse, response: Response): void {
if (response.status === 302) {
const location = response.headers.location;
delete response.headers.location;
res.set(response.headers);
res.redirect(location);
} else {
res.set(response.headers);
res.status(response.status).send(response.body);
}
};
const handleError = function (e: OAuthError, req: ExpressRequest, res: ExpressResponse, response: Response, next: NextFunction): void {
if (this.useErrorHandler === true) {
next(e);
} else {
if (response) {
res.set(response.headers);
}
res.status(e.code);
if (e instanceof UnauthorizedRequestError) {
res.send();
return;
}
res.send({ error: e.name, error_description: e.message });
}
};
export default OAuthServer;
After few hours spend by reading the documentation of the underline library
.
Any ideas why I am getting this error?
Running Node v6.10.2
/Users/elliotlings/api/node_modules/express-oauth-server/index.js:25
this.useErrorHandler = options.useErrorHandler ? true : false;
^
TypeError: Cannot set property 'useErrorHandler' of undefined
at ExpressOAuthServer (/Users/elliotlings/api/node_modules/express-oauth-server/index.js:25:24)
at Object.<anonymous> (/Users/elliotlings/api/src/index.js:9:13)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:393:7)
at startup (bootstrap_node.js:150:9)
at bootstrap_node.js:508:3
Just wondering if anyone had success running this application?
node-oauth2-server-implementation-master/components/oauth/sqldb/OAuthAccessToken.js:8
const OAuthAccessToken = sequelize.define('OAuthAccessToken', {
^^^^^
SyntaxError: Use of const in strict mode.
at exports.runInThisContext (vm.js:73:16)
at Module._compile (module.js:443:25)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
at require (module.js:384:17)
The requirement for my app is the following:
"Log all incoming requests (including the request's response body)".
Even if there is the option continueMiddleware to continue executing a following middleware, it isn't possible to access the response of the token() method in that next middleware. Because of that, I can't easily log the response of the API method to obtain a token.
Maybe it would be feasible to store the response body inside the res object before send it in order to be able to have access it in the following middlewares of the chain.
Alternatively, an option could be added to just obtaining the response body of oauth-node-server but not sending it over automatically.
I've worked on creating a new example that hopefully helps a little in determining what to do.
https://github.com/14gasher/oauth-example
Enjoy.
Hey all,
I just noticed that the requireClientAuthentication option is not available in this module. Am i wrong ? Because they added this option in november 2016 (oauthjs/node-oauth2-server@99a5b02).
It is possible to implement that ?
thanks !
Overview
Versions of lodash before 4.17.5 are vulnerable to prototype pollution.
The vulnerable functions are 'defaultsDeep', 'merge', and 'mergeWith' which allow a malicious user to modify the prototype of Object via {constructor: {prototype: {...}}} causing the addition or modification of an existing property that will exist on all objects.
PFA.
Remediation
Update to version 4.17.11 or later.
The OAuth2 spec suggests 302 redirects as the default but allows for any method of redirecting the user agent. Add support for other redirect codes:
301
302
303
307
308
Node-oauth2-server is now on version 3.0.0-b4. Can express-oauth-server update dependency to match?
Hello,
I'm trying to run the postgres exemple, but this doesn't work.
I have successful create template and correct postgres connection, but i don't understand who it's work.
Can you provide a real and functional sample, with login/authorize/ getToken exemple?
I'm try generate oauth tokens with password grant but the server not responding
my branch: https://github.com/ChicoFigueiredo/receita.digital/tree/001-criando-servidor-oauth2/server
Postman :
Testes.postman_collection.json.zip
I'm using mongodb
Thanks :)
The execution of handleResponse
in the .oauth.authorize
promise chain (https://github.com/oauthjs/express-oauth-server/blob/master/index.js#L78-L80) appears to prematurely terminate the authorization middleware by returning the server response before subsequent operations can take place. When I remove this stage, everything works correctly.
Perhaps this was a duplication error from the oauth.token
chain?
Could you please publish the latest version of the server, which relies on next
rather than a git branch.
Also, would you consider relying on a specific release of oauth2-server
, rather than next
(this worries me a bit, since it breaks semver conventions).
Thanks for the awesome work on this project!
When my model returns nothing for model.getAccessToken
because the token doesn't exist in the db, I get two responses. The offending lines are here: https://github.com/oauthjs/express-oauth-server/blob/master/index.js#L49-L52
.catch(function(e) {
return handleError(e, req, res); // sends an error response
})
.finally(next); // executes after .catch and sends another response
I believe it should be the following, but I am not 100% certain since I'm not very experienced with the flow of promises.
.tap(next)
.catch(function(e) {
return handleError(e, req, res);
});
The latest version published on NPM is broken. The authenticate function will always throw an error because the response object is not passed to the oauth2-server function. It appears this is already fixed in the latest code base here on GitHub.
I have created the server verbatim (I think), but still not able to use it. When I am trying to get the access token using a password grant, I keep getting the subject error.
I am using Postman to POST the request as follows:
Address: localhost:3000/oauth/token
Header: {Content-Type: application/x-www-form-urlencoded, Authorization: __________}
Body: {grant_type: password, username: _____, password: ______}
However the error that I keep getting is:
server_error: Cannot read property '0' of undefined
at new ServerError (/Users/vaibhavgupta/games/pool/server/data/microservices/node_modules/express-oauth-server/node_modules/oauth2-server/lib/errors/server-error.js:25:14)
at TokenHandler.<anonymous> (/Users/vaibhavgupta/games/pool/server/data/microservices/node_modules/express-oauth-server/node_modules/oauth2-server/lib/handlers/token-handler.js:102:13)
From previous event:
at TokenHandler.handle (/Users/vaibhavgupta/games/pool/server/data/microservices/node_modules/express-oauth-server/node_modules/oauth2-server/lib/handlers/token-handler.js:100:13)
at OAuth2Server.token (/Users/vaibhavgupta/games/pool/server/data/microservices/node_modules/express-oauth-server/node_modules/oauth2-server/lib/server.js:75:6)
at ExpressOAuthServer.<anonymous> (/Users/vaibhavgupta/games/pool/server/data/microservices/node_modules/express-oauth-server/index.js:113:28)
at runCallback (timers.js:756:18)
at tryOnImmediate (timers.js:717:5)
at processImmediate [as _immediateCallback] (timers.js:697:5)
Will much much appreciate any help that I can get..
Example in README at https://github.com/oauthjs/express-oauth-server fails to work with error:
{"error":"invalid_argument","error_description":"Invalid argument: model does not implement `getClient()`"}
If this isn't a complete example it would help to mention that and suggest what is needed to get this working. Node version: 6.x
I think it needs to be app.oauth = new oauthserver(...);
If the error encountered is not expected (ie. not an OAuth Library error) it should re throw the error (or at least pass it to next to be dealt with)
https://github.com/oauthjs/express-oauth-server/blob/master/index.js#L142
I propose checking if it's an instance of https://github.com/oauthjs/node-oauth2-server/blob/master/lib/errors/oauth-error.js
If you agree I can prepare a PR
Hi All,
I have implemented a auth server and using SFDC as idp, in sfdc i have created a app and given the entity id =com.xyz.abc also downloaded metadata and integrated with my code .In my auth server properties file i have given -
idp.enity.id= com.xyz.abc
for single Entity id it is working fine.
now i want to create another app in SFDC and want to give entity id =com.xyz.lmno.shas and in my properties file want to do like this-
idp.entity.id = com.xyz.lmno.shas
finally my property file should contain two entity id's so that i can get the response from my selected app , is it possible to give two or more entity id's in property file ?
Thanks
Currently, after calling node-oauth2-server handlers, some results are exposed via req.app.locals
. As stated here, this persists throughout the lifetime of the application. res.locals
only persists throughout the lifetime of the current request. It seems to me the second option should be used, since authentication is request specific. Is this an intentional decision?
node-oauth2-server
offers an options
-parameter to its Response constructor. I think express-oauth-server
should pass (some) of the properties of the express response object via the options
parameter, so that they are available on the node-oauth2-server
response.
The particular reason I am interested in this is because of the problem I mentioned here, but I think the general concept of passing (some) properties could make it possible for express-oauth-server
to more seamlessly proxy the request
and reponse
by implementing some of the principles of express, such as the locals
property on the express reponse.
Current build status says failing? Is this correct?
How can I include the userId or a user object in the token which gets sent back to the client?
Sorry to ask, but i've been having a problem to finish setup, i had to remove de validation of the response instance in the authenticate() middleware, since i haven't been able to set the response before passing to the middleware.
now another question, how can I get the user that is logged in??
A short search in the project revealed, that thenify
is used nowhere. Therefore it should be removed form the dependencies.
The git release 2.0.0-b2 should also be published on NPM.
Thanks!
Attempting to use the mongodb example out of the box, I ran into the following behaviour when debugging /oauth-server/lib/models/token-model.js:
As you can see above, many properties appear to be missing as the example model functions (in this case getClient()
) return a mongoose object rather than the document itself. Instead, we see that the document is buried one level deeper within this object under the _doc
property, and that grants
, etc. are to be found there. Assuming the common use of leading underscore indicates private use here, and noting the mongoose documentation on it is lacking, it would be nice to rely on something more robust.
It turns out that lean()
can be chained to most, perhaps all of the queries in this file, returning just the document. The only special case is saveAccess()
, but using Promise
along with some fairly explicit logic to prepare the return values expected by the oauth server I was able to implement a fix: ancamcheachta@5f98bd1.
Pull request including commit in question is forthcoming, however would be interested in future of support for mongodb example. Did a previous version of mongoose work with the example? If so, which version? If there is a specific version, would it be worth noting in the readme for mongodb and suggesting that version be frozen using package.json
? Or are would ye rather the fix? Sure have a look at the pull request, anyway.
Several issues open and without activity, is this still being maintained?
module.exports.getAccessToken = function(bearerToken) {
return pg.query('SELECT access_token, access_token_expires_on, client_id, refresh_token, refresh_token_expires_on, user_id FROM oauth_tokens WHERE access_token = $1', [bearerToken])
.then(function(result) {
var token = result.rows[0];
return {
accessToken: token.access_token,
clientId: token.client_id,
expires: token.expires, // This position
userId: token.userId //And this position
};
});
};
Please fix it to:
module.exports.getAccessToken = function(bearerToken) {
return pg.query('SELECT access_token, access_token_expires_on, client_id, refresh_token, refresh_token_expires_on, user_id FROM oauth_tokens WHERE access_token = $1', [bearerToken])
.then(function(result) {
var token = result.rows[0];
return {
accessToken: token.access_token,
clientId: token.client_id,
expires: token.access_token_expires_on,
userId: token.user_id
};
});
};
Or:
module.exports.getAccessToken = function(bearerToken) {
return pg.query('SELECT access_token, access_token_expires_on AS expires, client_id, refresh_token, refresh_token_expires_on, user_id AS userId FROM oauth_tokens WHERE access_token = $1', [bearerToken])
.then(function(result) {
var token = result.rows[0];
return {
accessToken: token.access_token,
clientId: token.client_id,
expires: token.expires,
userId: token.userId
};
});
};
authenticate always seems to call next() - even though it sets the response status to 401. Is this on purpose?
After a long debugging session I found following configuration options:
oauth = new OAuthServer({
model: dataModel,
debug: true ,
allowExtendedTokenAttributes: true,
alwaysIssueNewRefreshToken: false,
requireClientAuthentication: {},
accessTokenLifetime:1800,
refreshTokenLifetime: 3600});
For my issue allowExtendedTokenAttributes
seems to be the correct option. But a remaining question is how to specify the custom fields when the allowExtendedTokenAttributes
option is set to true
?
I found that in lib\models\token-model.js
of the underline library oauth2-server
some fields are filtered out and cannot be consider as custom fields.
var modelAttributes = ['accessToken', 'accessTokenExpiresAt', 'refreshToken', 'refreshTokenExpiresAt', 'scope', 'client', 'user'];
if (options && options.allowExtendedTokenAttributes) {
this.customAttributes = {};
console.log("data: ", data)
for (var key in data) {
if (data.hasOwnProperty(key) && (modelAttributes.indexOf(key) < 0)) {
this.customAttributes[key] = data[key];
}
}
}
Now my responses look like this when I hit POST /oauth/token
:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6IjAwMjM3...",
"token_type": "Bearer",
"expires_in": 1799,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6IjA..."
}
How should I proceed if I want to add a new field user_id
in the above response?
Here my source code: https://github.com/nanachimi/oauthserverjs
Thanks
var options = {
useErrorHandler: false,
continueMiddleWare: false,
}
middleWare is spelled with a capital W. instead of the correct w.
TypeError: expecting a function but got [object Object]
on
var db = require('bluebird').promisify(require('redis').createClient());
app.get('/secret', app.oauth.authenticate(), function(req, res) {
// Will require a valid access_token.
res.send('Secret area');
});
I've implemented something similar to the above, it seems that the handler always get called regardless of the validity of the Bearer
token?
This doesn't seem right
I am using Ubuntu 14.04 and this is the output I get when trying to install from npm:
root@9fe82eedfaf2:/# npm install oauth2-server
npm http GET https://registry.npmjs.org/oauth2-server
npm http 304 https://registry.npmjs.org/oauth2-server
npm http GET https://registry.npmjs.org/basic-auth
npm http 304 https://registry.npmjs.org/basic-auth
[email protected] node_modules/oauth2-server
└── [email protected]
root@9fe82eedfaf2:/# npm install express-oauth-server
npm http GET https://registry.npmjs.org/express-oauth-server
npm http 304 https://registry.npmjs.org/express-oauth-server
npm WARN engine [email protected]: wanted: {"node":">=0.11"} (current: {"node":"v0.10.25","npm":"1.3.10"})
npm http GET https://registry.npmjs.org/bluebird
npm http GET https://registry.npmjs.org/express
npm http GET https://registry.npmjs.org/thenify
npm ERR! Error: No compatible version found: oauth2-server@'seegno-forks/node-oauth2-server#enhancement/refactor-project'
npm ERR! Valid install targets:
npm ERR! ["2.2.2","2.3.0","2.4.0","2.4.1","3.0.0-b1","3.0.0-b2"]
npm ERR! at installTargetsError (/usr/share/npm/lib/cache.js:719:10)
npm ERR! at /usr/share/npm/lib/cache.js:638:10
npm ERR! at RegClient.get_ (/usr/share/npm/node_modules/npm-registry-client/lib/get.js:105:14)
npm ERR! at RegClient. (/usr/share/npm/node_modules/npm-registry-client/lib/get.js:41:12)
npm ERR! at fs.js:268:14
npm ERR! at /usr/lib/nodejs/graceful-fs/graceful-fs.js:103:5
npm ERR! at Object.oncomplete (fs.js:107:15)
npm ERR! If you need help, you may report this log at:
npm ERR! http://github.com/isaacs/npm/issues
npm ERR! or email it to:
npm ERR! [email protected]
npm ERR! System Linux 3.13.0-77-generic
npm ERR! command "/usr/bin/nodejs" "/usr/bin/npm" "install" "express-oauth-server"
npm ERR! cwd /
npm ERR! node -v v0.10.25
npm ERR! npm -v 1.3.10
npm http 304 https://registry.npmjs.org/express
npm http 200 https://registry.npmjs.org/bluebird
npm http 200 https://registry.npmjs.org/thenify
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR! /npm-debug.log
npm ERR! not ok code 0
I'm using token() with "password" as grant_type and am providing client, secret, username and password. The GetUser() of my model is able to retrieve and return the user. However, as a response I get "missing parameter 'accessToken'. It doesn't make sense to my why I should be providing accessToken when I'm clearly requesting for one?
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.