{"action":"created","comment":{"url":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/comments/41711922","id":41711922,"diff_hunk":"@@ -0,0 +1,255 @@\n+\n+/**\n+ * Module dependencies.\n+ */\n+\n+var InvalidArgumentError = require('../errors/invalid-argument-error');\n+var InvalidRequestError = require('../errors/invalid-request-error');\n+var InvalidScopeError = require('../errors/invalid-scope-error');\n+var InvalidTokenError = require('../errors/invalid-token-error');\n+var OAuthError = require('../errors/oauth-error');\n+var Promise = require('bluebird');\n+var Request = require('../request');\n+var Response = require('../response');\n+var ServerError = require('../errors/server-error');\n+var UnauthorizedRequestError = require('../errors/unauthorized-request-error');\n+\n+/**\n+ * Constructor.\n+ */\n+\n+function AuthenticateHandler(options) {\n+  options = options || {};\n+\n+  if (!options.model) {\n+    throw new InvalidArgumentError('Missing parameter: `model`');\n+  }\n+\n+  if (!options.model.getAccessToken) {\n+    throw new InvalidArgumentError('Invalid argument: model does not implement `getAccessToken()`');\n+  }\n+\n+  if (options.scope && undefined === options.addAcceptedScopesHeader) {\n+    throw new InvalidArgumentError('Missing parameter: `addAcceptedScopesHeader`');\n+  }\n+\n+  if (options.scope && undefined === options.addAuthorizedScopesHeader) {\n+    throw new InvalidArgumentError('Missing parameter: `addAuthorizedScopesHeader`');\n+  }\n+\n+  if (options.scope && !options.model.validateScope) {\n+    throw new InvalidArgumentError('Invalid argument: model does not implement `validateScope()`');\n+  }\n+\n+  this.addAcceptedScopesHeader = options.addAcceptedScopesHeader;\n+  this.addAuthorizedScopesHeader = options.addAuthorizedScopesHeader;\n+  this.model = options.model;\n+  this.scope = options.scope;\n+}\n+\n+/**\n+ * Authenticate Handler.\n+ */\n+\n+AuthenticateHandler.prototype.handle = function(request, response) {\n+  if (!(request instanceof Request)) {\n+    throw new InvalidArgumentError('Invalid argument: `request` must be an instance of Request');\n+  }\n+\n+  if (!(response instanceof Response)) {\n+    throw new InvalidArgumentError('Invalid argument: `response` must be an instance of Request');\n+  }\n+\n+  return Promise.bind(this)\n+    .then(function() {\n+      return this.getToken(request);\n+    })\n+    .then(function(token) {\n+      return this.getAccessToken(token);\n+    })\n+    .tap(function(token) {\n+      return this.validateAccessToken(token);\n+    })\n+    .tap(function(token) {\n+      if (!this.scope) {\n+        return;\n+      }\n+\n+      return this.validateScope(token);\n+    })\n+    .tap(function(token) {\n+      return this.updateResponse(response, token);\n+    })\n+    .catch(function(e) {\n+      // Include the \"WWW-Authenticate\" response header field if the client\n+      // lacks any authentication information.\n+      //\n+      // @see https://tools.ietf.org/html/rfc6750#section-3.1\n+      if (e instanceof UnauthorizedRequestError) {\n+        response.set('WWW-Authenticate', 'Bearer realm=\"Service\"');\n+      }\n+\n+      if (!(e instanceof OAuthError)) {\n+        throw new ServerError(e);\n+      }\n+\n+      throw e;\n+    });\n+};\n+\n+/**\n+ * Get the token from the header or body, depending on the request.\n+ *\n+ * \"Clients MUST NOT use more than one method to transmit the token in each request.\"\n+ *\n+ * @see https://tools.ietf.org/html/rfc6750#section-2\n+ */\n+\n+AuthenticateHandler.prototype.getToken = function(request) {\n+  var headerToken = request.get('Authorization');\n+  var queryToken = request.query.access_token;\n+  var bodyToken = request.body.access_token;\n+\n+  if (!!headerToken + !!queryToken + !!bodyToken > 1) {\n+    throw new InvalidRequestError('Invalid request: only one authentication method is allowed');\n+  }\n+\n+  if (headerToken) {\n+    return this.getTokenFromRequestHeader(request);\n+  }\n+\n+  if (queryToken) {\n+    return this.getTokenFromRequestQuery(request);\n+  }\n+\n+  if (bodyToken) {\n+    return this.getTokenFromRequestBody(request);\n+  }\n+\n+  throw new UnauthorizedRequestError('Unauthorized request: no authentication given');\n+};\n+\n+/**\n+ * Get the token from the request header.\n+ *\n+ * @see http://tools.ietf.org/html/rfc6750#section-2.1\n+ */\n+\n+AuthenticateHandler.prototype.getTokenFromRequestHeader = function(request) {\n+  var token = request.get('Authorization');\n+  var matches = token.match(/Bearer\\s(\\S+)/);\n+\n+  if (!matches) {\n+    throw new InvalidRequestError('Invalid request: malformed authorization header');\n+  }\n+\n+  return matches[1];\n+};\n+\n+/**\n+ * Get the token from the request query.\n+ *\n+ * \"Don't pass bearer tokens in page URLs:  Bearer tokens SHOULD NOT be passed in page\n+ * URLs (for example, as query string parameters). Instead, bearer tokens SHOULD be\n+ * passed in HTTP message headers or message bodies for which confidentiality measures\n+ * are taken. Browsers, web servers, and other software may not adequately secure URLs\n+ * in the browser history, web server logs, and other data structures. If bearer tokens\n+ * are passed in page URLs, attackers might be able to steal them from the history data,\n+ * logs, or other unsecured locations.\"\n+ *\n+ * @see http://tools.ietf.org/html/rfc6750#section-2.3\n+ */\n+\n+AuthenticateHandler.prototype.getTokenFromRequestQuery = function() {\n+  throw new InvalidRequestError('Invalid request: do not send bearer tokens in query URLs');\n+};\n+\n+/**\n+ * Get the token from the request body.\n+ *\n+ * \"The HTTP request method is one for which the request-body has defined semantics.\n+ * In particular, this means that the \"GET\" method MUST NOT be used.\"\n+ *\n+ * @see http://tools.ietf.org/html/rfc6750#section-2.2\n+ */\n+\n+AuthenticateHandler.prototype.getTokenFromRequestBody = function(request) {\n+  if (request.method === 'GET') {\n+    throw new InvalidRequestError('Invalid request: token may not be passed in the body when using the GET verb');\n+  }\n+\n+  if (!request.is('application/x-www-form-urlencoded')) {","path":"lib/handlers/authenticate-handler.js","position":181,"original_position":181,"commit_id":"bcec6d266aca58d4098b8278540aae5af0c8015e","original_commit_id":"bcec6d266aca58d4098b8278540aae5af0c8015e","user":{"login":"sunnycmf","id":31832,"avatar_url":"https://avatars.githubusercontent.com/u/31832?v=3","gravatar_id":"","url":"https://api.github.com/users/sunnycmf","html_url":"https://github.com/sunnycmf","followers_url":"https://api.github.com/users/sunnycmf/followers","following_url":"https://api.github.com/users/sunnycmf/following{/other_user}","gists_url":"https://api.github.com/users/sunnycmf/gists{/gist_id}","starred_url":"https://api.github.com/users/sunnycmf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sunnycmf/subscriptions","organizations_url":"https://api.github.com/users/sunnycmf/orgs","repos_url":"https://api.github.com/users/sunnycmf/repos","events_url":"https://api.github.com/users/sunnycmf/events{/privacy}","received_events_url":"https://api.github.com/users/sunnycmf/received_events","type":"User","site_admin":false},"body":"@mjsalinger according to [RFC-6750](http://tools.ietf.org/html/rfc6750#section-2.2), the `x-www-form-urlencoded` is needed.\r\n> The client MUST NOT use this method unless\r\n   *all* of the following conditions are met:\r\n   -  The HTTP request entity-header includes the \"Content-Type\" header\r\n      field set to \"application/x-www-form-urlencoded\".","created_at":"2015-10-11T15:37:23Z","updated_at":"2015-10-11T15:37:23Z","html_url":"https://github.com/thomseddon/node-oauth2-server/pull/203#discussion_r41711922","pull_request_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/203","_links":{"self":{"href":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/comments/41711922"},"html":{"href":"https://github.com/thomseddon/node-oauth2-server/pull/203#discussion_r41711922"},"pull_request":{"href":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/203"}}},"pull_request":{"url":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/203","id":40515432,"html_url":"https://github.com/thomseddon/node-oauth2-server/pull/203","diff_url":"https://github.com/thomseddon/node-oauth2-server/pull/203.diff","patch_url":"https://github.com/thomseddon/node-oauth2-server/pull/203.patch","issue_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/issues/203","number":203,"state":"open","locked":false,"title":"Refactor project","user":{"login":"nunofgs","id":92085,"avatar_url":"https://avatars.githubusercontent.com/u/92085?v=3","gravatar_id":"","url":"https://api.github.com/users/nunofgs","html_url":"https://github.com/nunofgs","followers_url":"https://api.github.com/users/nunofgs/followers","following_url":"https://api.github.com/users/nunofgs/following{/other_user}","gists_url":"https://api.github.com/users/nunofgs/gists{/gist_id}","starred_url":"https://api.github.com/users/nunofgs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nunofgs/subscriptions","organizations_url":"https://api.github.com/users/nunofgs/orgs","repos_url":"https://api.github.com/users/nunofgs/repos","events_url":"https://api.github.com/users/nunofgs/events{/privacy}","received_events_url":"https://api.github.com/users/nunofgs/received_events","type":"User","site_admin":false},"body":"This PR completely restructures the project into a more modern Promise-based approach. Among many many fixes, it also adds support for scopes, changes the license to MIT, validates user input according to the OAuth spec, removes express-specific middlewares, improves error handling and is fully tested.\r\n\r\nI know this is a monumental PR and is quite a big shift in style and approach, it is my opinion that it greatly enhances this library and further establishes it as the de-facto OAuth server library for node.\r\n\r\nI'd love to know what you think.\r\n\r\n# OAuth2-Server\r\n\r\nIntroduces a new OAuth server implementation with the following changes:\r\n\r\n  * Added a promise-based API which supports both promises and *node-style* callbacks.\r\n  * Added support for scopes for all grant types.\r\n  * Added syntax-checking to all user input as defined in the [spec](https://tools.ietf.org/html/rfc6749#appendix-A).\r\n  * Added OAuth client validation to authorization requests which fixes an edge-case where an auth code would be generated even if the OAuth client did not support *authorization codes*.\r\n  * Fixed authorization requests now defer to the authentication middleware in order to verify that the request is authenticated (in the process, multiple bugs were fixed since the original library was doing this in place and consequently skipping many important checks).\r\n  * Fixed incorrect (non-spec compliant) validation of the *redirectUri* in the *authorization_code* grant.\r\n  * Fixed incorrect handling of custom grant types (the spec requires that extended grants be specified in the form of a *uri*).\r\n  * Fixed non-spec compliant behavior when validating unsupported grant types.\r\n  * Fixed non-[spec](https://tools.ietf.org/html/rfc6749) compliant errors being returned to the response.\r\n  * Fixed objects retrieved from the model are no longer injected into the current execution context and are instead returned in the original promise.\r\n  * Fixed parameters given to model calls are now objects previously fetched from the model which reduces the number of database queries per OAuth request.\r\n  * Fixed tokens are no longer allowed to be passed by GET parameter as recommended by the OAuth spec, for security reasons.\r\n  * Improved *authorization_code* grant by allowing the *redirect_uri* parameter to be omitted (as required by the spec).\r\n  * Improved *authorization_code* grant type by revoking the authorization code immediately upon issuing an access token (as required by the spec).\r\n  * Improved *refresh_token* grant type by revoking the previous *refresh_token* immediately upon issuing an access token (as required by the spec).\r\n  * Improved architecture by separating the *grant-types*, *response-types* and *token-types* into strongly typed classes.\r\n  * Improved error handling by throwing strongly-typed errors so they can be caught in our backend.\r\n  * Improved error handling by wrapping model errors in a *server_error*, as required by the [spec](https://tools.ietf.org/html/rfc6749).\r\n  * Improved validation of all objects retrieved from the model (no validation was being done on expiry dates, for example).\r\n  * Removed dependency on the *express* framework.\r\n  * Removed injection of response body and headers in favor of strongly-typed *Request* and *Response* classes.\r\n  * Renamed *authorise*, *grant* and *authCodeGrant* middlewares to more OAuth spec-friendly *authenticate*, *token* and *authorize*, respectively.","created_at":"2015-07-21T23:14:51Z","updated_at":"2015-10-11T15:37:23Z","closed_at":null,"merged_at":null,"merge_commit_sha":"040ee397794352ce7aaf0f3912136e3b8d1e54e6","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/203/commits","review_comments_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/203/comments","review_comment_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/comments{/number}","comments_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/issues/203/comments","statuses_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/statuses/bcec6d266aca58d4098b8278540aae5af0c8015e","head":{"label":"seegno-forks:enhancement/refactor-project","ref":"enhancement/refactor-project","sha":"bcec6d266aca58d4098b8278540aae5af0c8015e","user":{"login":"seegno-forks","id":10717345,"avatar_url":"https://avatars.githubusercontent.com/u/10717345?v=3","gravatar_id":"","url":"https://api.github.com/users/seegno-forks","html_url":"https://github.com/seegno-forks","followers_url":"https://api.github.com/users/seegno-forks/followers","following_url":"https://api.github.com/users/seegno-forks/following{/other_user}","gists_url":"https://api.github.com/users/seegno-forks/gists{/gist_id}","starred_url":"https://api.github.com/users/seegno-forks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/seegno-forks/subscriptions","organizations_url":"https://api.github.com/users/seegno-forks/orgs","repos_url":"https://api.github.com/users/seegno-forks/repos","events_url":"https://api.github.com/users/seegno-forks/events{/privacy}","received_events_url":"https://api.github.com/users/seegno-forks/received_events","type":"Organization","site_admin":false},"repo":{"id":16441877,"name":"node-oauth2-server","full_name":"seegno-forks/node-oauth2-server","owner":{"login":"seegno-forks","id":10717345,"avatar_url":"https://avatars.githubusercontent.com/u/10717345?v=3","gravatar_id":"","url":"https://api.github.com/users/seegno-forks","html_url":"https://github.com/seegno-forks","followers_url":"https://api.github.com/users/seegno-forks/followers","following_url":"https://api.github.com/users/seegno-forks/following{/other_user}","gists_url":"https://api.github.com/users/seegno-forks/gists{/gist_id}","starred_url":"https://api.github.com/users/seegno-forks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/seegno-forks/subscriptions","organizations_url":"https://api.github.com/users/seegno-forks/orgs","repos_url":"https://api.github.com/users/seegno-forks/repos","events_url":"https://api.github.com/users/seegno-forks/events{/privacy}","received_events_url":"https://api.github.com/users/seegno-forks/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/seegno-forks/node-oauth2-server","description":"Complete, compliant and well tested module for implementing an OAuth2 Server/Provider with express in node.js","fork":true,"url":"https://api.github.com/repos/seegno-forks/node-oauth2-server","forks_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/forks","keys_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/keys{/key_id}","collaborators_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/teams","hooks_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/hooks","issue_events_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/issues/events{/number}","events_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/events","assignees_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/assignees{/user}","branches_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/branches{/branch}","tags_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/tags","blobs_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/git/refs{/sha}","trees_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/git/trees{/sha}","statuses_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/statuses/{sha}","languages_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/languages","stargazers_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/stargazers","contributors_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/contributors","subscribers_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/subscribers","subscription_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/subscription","commits_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/commits{/sha}","git_commits_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/git/commits{/sha}","comments_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/comments{/number}","issue_comment_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/issues/comments{/number}","contents_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/contents/{+path}","compare_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/compare/{base}...{head}","merges_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/merges","archive_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/downloads","issues_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/issues{/number}","pulls_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/pulls{/number}","milestones_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/milestones{/number}","notifications_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/labels{/name}","releases_url":"https://api.github.com/repos/seegno-forks/node-oauth2-server/releases{/id}","created_at":"2014-02-01T20:24:13Z","updated_at":"2015-08-16T17:10:34Z","pushed_at":"2015-09-24T16:15:45Z","git_url":"git://github.com/seegno-forks/node-oauth2-server.git","ssh_url":"git@github.com:seegno-forks/node-oauth2-server.git","clone_url":"https://github.com/seegno-forks/node-oauth2-server.git","svn_url":"https://github.com/seegno-forks/node-oauth2-server","homepage":"https://npmjs.org/package/node-oauth2-server","size":775,"stargazers_count":2,"watchers_count":2,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":2,"forks":2,"open_issues":2,"watchers":2,"default_branch":"master"}},"base":{"label":"thomseddon:master","ref":"master","sha":"b36a06b445ad0a676e6175d68a8bd0b2f3353dbf","user":{"login":"thomseddon","id":747138,"avatar_url":"https://avatars.githubusercontent.com/u/747138?v=3","gravatar_id":"","url":"https://api.github.com/users/thomseddon","html_url":"https://github.com/thomseddon","followers_url":"https://api.github.com/users/thomseddon/followers","following_url":"https://api.github.com/users/thomseddon/following{/other_user}","gists_url":"https://api.github.com/users/thomseddon/gists{/gist_id}","starred_url":"https://api.github.com/users/thomseddon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thomseddon/subscriptions","organizations_url":"https://api.github.com/users/thomseddon/orgs","repos_url":"https://api.github.com/users/thomseddon/repos","events_url":"https://api.github.com/users/thomseddon/events{/privacy}","received_events_url":"https://api.github.com/users/thomseddon/received_events","type":"User","site_admin":false},"repo":{"id":9367940,"name":"node-oauth2-server","full_name":"thomseddon/node-oauth2-server","owner":{"login":"thomseddon","id":747138,"avatar_url":"https://avatars.githubusercontent.com/u/747138?v=3","gravatar_id":"","url":"https://api.github.com/users/thomseddon","html_url":"https://github.com/thomseddon","followers_url":"https://api.github.com/users/thomseddon/followers","following_url":"https://api.github.com/users/thomseddon/following{/other_user}","gists_url":"https://api.github.com/users/thomseddon/gists{/gist_id}","starred_url":"https://api.github.com/users/thomseddon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thomseddon/subscriptions","organizations_url":"https://api.github.com/users/thomseddon/orgs","repos_url":"https://api.github.com/users/thomseddon/repos","events_url":"https://api.github.com/users/thomseddon/events{/privacy}","received_events_url":"https://api.github.com/users/thomseddon/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/thomseddon/node-oauth2-server","description":"Complete, compliant and well tested module for implementing an OAuth2 Server/Provider with express in node.js","fork":false,"url":"https://api.github.com/repos/thomseddon/node-oauth2-server","forks_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/forks","keys_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/keys{/key_id}","collaborators_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/teams","hooks_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/hooks","issue_events_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/issues/events{/number}","events_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/events","assignees_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/assignees{/user}","branches_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/branches{/branch}","tags_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/tags","blobs_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/git/refs{/sha}","trees_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/git/trees{/sha}","statuses_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/statuses/{sha}","languages_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/languages","stargazers_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/stargazers","contributors_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/contributors","subscribers_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/subscribers","subscription_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/subscription","commits_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/commits{/sha}","git_commits_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/git/commits{/sha}","comments_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/comments{/number}","issue_comment_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/issues/comments{/number}","contents_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/contents/{+path}","compare_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/compare/{base}...{head}","merges_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/merges","archive_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/downloads","issues_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/issues{/number}","pulls_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls{/number}","milestones_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/milestones{/number}","notifications_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/labels{/name}","releases_url":"https://api.github.com/repos/thomseddon/node-oauth2-server/releases{/id}","created_at":"2013-04-11T10:39:52Z","updated_at":"2015-10-11T14:51:29Z","pushed_at":"2015-09-26T04:45:57Z","git_url":"git://github.com/thomseddon/node-oauth2-server.git","ssh_url":"git@github.com:thomseddon/node-oauth2-server.git","clone_url":"https://github.com/thomseddon/node-oauth2-server.git","svn_url":"https://github.com/thomseddon/node-oauth2-server","homepage":"https://npmjs.org/package/node-oauth2-server","size":1993,"stargazers_count":793,"watchers_count":793,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":279,"mirror_url":null,"open_issues_count":65,"forks":279,"open_issues":65,"watchers":793,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/203"},"html":{"href":"https://github.com/thomseddon/node-oauth2-server/pull/203"},"issue":{"href":"https://api.github.com/repos/thomseddon/node-oauth2-server/issues/203"},"comments":{"href":"https://api.github.com/repos/thomseddon/node-oauth2-server/issues/203/comments"},"review_comments":{"href":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/203/comments"},"review_comment":{"href":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/thomseddon/node-oauth2-server/pulls/203/commits"},"statuses":{"href":"https://api.github.com/repos/thomseddon/node-oauth2-server/statuses/bcec6d266aca58d4098b8278540aae5af0c8015e"}}}}