From 176b8f868f0394d1b516ef144ed5265d2bf1b801 Mon Sep 17 00:00:00 2001 From: Matt Eby Date: Tue, 15 Apr 2014 10:23:49 -0500 Subject: [PATCH] adding allowPublicClients option to disable strict requirement of an authentication header with client credentials --- README.md | 3 +++ lib/cc/grantToken.js | 2 +- lib/common/makeSetup.js | 3 ++- lib/common/validateGrantTokenRequest.js | 4 ++-- lib/ropc/grantToken.js | 10 +++++++--- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f3c0c10..ced2cd8 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,9 @@ The `hooks` hash is the only required option, but the following are also availab * `tokenExpirationTime`: the value returned for the `expires_in` component of the response from the token endpoint. Note that this is *only* the value reported; you are responsible for keeping track of token expiration yourself and calling back with `false` from `authenticateToken` when the token expires. Defaults to `Infinity`. +* `allowPublicClients`: allow requests to the `tokenEndpoint` that do not have client credentials. This option only + applies to ROPC flows. OAuth2 disallows use of public clients for the CC flow. The `validateClient` hook will still + be called for all requests, but parameters may be `null`. Defaults to `false`. ## What Does That Look Like? diff --git a/lib/cc/grantToken.js b/lib/cc/grantToken.js index c29e21f..96a3897 100644 --- a/lib/cc/grantToken.js +++ b/lib/cc/grantToken.js @@ -5,7 +5,7 @@ var finishGrantingToken = require("../common/finishGrantingToken"); var makeOAuthError = require("../common/makeOAuthError"); module.exports = function grantToken(req, res, next, options) { - if (!validateGrantTokenRequest("client_credentials", req, next)) { + if (!validateGrantTokenRequest("client_credentials", false, req, next)) { return; } diff --git a/lib/common/makeSetup.js b/lib/common/makeSetup.js index 3348683..4c1a6a7 100644 --- a/lib/common/makeSetup.js +++ b/lib/common/makeSetup.js @@ -26,7 +26,8 @@ module.exports = function makeSetup(grantTypes, requiredHooks, grantToken) { options = _.defaults(options, { tokenEndpoint: "/token", wwwAuthenticateRealm: "Who goes there?", - tokenExpirationTime: Infinity + tokenExpirationTime: Infinity, + allowPublicClients: false }); // Allow `tokenExpirationTime: Infinity` (like above), but translate it into `undefined` so that diff --git a/lib/common/validateGrantTokenRequest.js b/lib/common/validateGrantTokenRequest.js index 339e6e3..9e9dbcf 100644 --- a/lib/common/validateGrantTokenRequest.js +++ b/lib/common/validateGrantTokenRequest.js @@ -3,7 +3,7 @@ var _ = require("underscore"); var makeOAuthError = require("./makeOAuthError"); -module.exports = function validateGrantTokenRequest(grantType, req, next) { +module.exports = function validateGrantTokenRequest(grantType, allowPublicClients, req, next) { function sendBadRequestError(type, description) { next(makeOAuthError("BadRequest", type, description)); } @@ -24,7 +24,7 @@ module.exports = function validateGrantTokenRequest(grantType, req, next) { return false; } - if (!req.authorization || !req.authorization.basic) { + if (!allowPublicClients && (!req.authorization || !req.authorization.basic)) { sendBadRequestError("invalid_request", "Must include a basic access authentication header."); return false; } diff --git a/lib/ropc/grantToken.js b/lib/ropc/grantToken.js index a26d2fa..f47a7df 100644 --- a/lib/ropc/grantToken.js +++ b/lib/ropc/grantToken.js @@ -11,7 +11,7 @@ module.exports = function grantToken(req, res, next, options) { } - if (!validateGrantTokenRequest("password", req, next)) { + if (!validateGrantTokenRequest("password", options.allowPublicClients, req, next)) { return; } @@ -26,8 +26,12 @@ module.exports = function grantToken(req, res, next, options) { return next(makeOAuthError("BadRequest", "invalid_request", "Must specify password field.")); } - var clientId = req.authorization.basic.username; - var clientSecret = req.authorization.basic.password; + var clientId = null; + var clientSecret = null; + if (req.authorization && req.authorization.basic) { + clientId = req.authorization.basic.username; + clientSecret = req.authorization.basic.password; + } var clientCredentials = { clientId: clientId, clientSecret: clientSecret }; options.hooks.validateClient(clientCredentials, req, function (error, result) {