From c4eafefcd794bcd7e604569bfa1242e353e73db4 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Thu, 3 Aug 2023 16:16:22 +0200 Subject: [PATCH 01/13] docs: fix links and cover missing topics --- docs/api/errors/access-denied-error.rst | 2 +- docs/api/errors/insufficient-scope-error.rst | 2 +- docs/api/errors/invalid-argument-error.rst | 2 +- docs/api/errors/invalid-client-error.rst | 2 +- docs/api/errors/invalid-grant-error.rst | 2 +- docs/api/errors/invalid-request-error.rst | 2 +- docs/api/errors/invalid-scope-error.rst | 2 +- docs/api/errors/invalid-token-error.rst | 2 +- docs/api/errors/oauth-error.rst | 2 +- docs/api/errors/server-error.rst | 2 +- docs/api/errors/unauthorized-client-error.rst | 2 +- .../api/errors/unauthorized-request-error.rst | 2 +- .../errors/unsupported-grant-type-error.rst | 2 +- .../unsupported-response-type-error.rst | 2 +- docs/api/oauth2-server.rst | 10 +- docs/api/request.rst | 4 +- docs/api/response.rst | 4 +- docs/docs/adapters.rst | 4 +- docs/docs/getting-started.rst | 14 +- docs/index.rst | 9 +- docs/misc/extension-grants.rst | 2 +- docs/misc/pkce.rst | 146 ++++++++++++++++++ docs/model/overview.rst | 3 +- docs/model/spec.rst | 81 ++++------ 24 files changed, 217 insertions(+), 88 deletions(-) create mode 100644 docs/misc/pkce.rst diff --git a/docs/api/errors/access-denied-error.rst b/docs/api/errors/access-denied-error.rst index e561c5b..11e61ec 100644 --- a/docs/api/errors/access-denied-error.rst +++ b/docs/api/errors/access-denied-error.rst @@ -6,7 +6,7 @@ The resource owner or authorization server denied the request. See :rfc:`Section :: - const AccessDeniedError = require('oauth2-server/lib/errors/access-denied-error'); + const AccessDeniedError = require('@node-oauth/oauth2-server/lib/errors/access-denied-error'); -------- diff --git a/docs/api/errors/insufficient-scope-error.rst b/docs/api/errors/insufficient-scope-error.rst index be3539d..b19e2ac 100644 --- a/docs/api/errors/insufficient-scope-error.rst +++ b/docs/api/errors/insufficient-scope-error.rst @@ -6,7 +6,7 @@ The request requires higher privileges than provided by the access token. See :r :: - const InsufficientScopeError = require('oauth2-server/lib/errors/insufficient-scope-error'); + const InsufficientScopeError = require('@node-oauth/oauth2-server/lib/errors/insufficient-scope-error'); -------- diff --git a/docs/api/errors/invalid-argument-error.rst b/docs/api/errors/invalid-argument-error.rst index 650e1d9..11b554e 100644 --- a/docs/api/errors/invalid-argument-error.rst +++ b/docs/api/errors/invalid-argument-error.rst @@ -6,7 +6,7 @@ An invalid argument was encountered. :: - const InvalidArgumentError = require('oauth2-server/lib/errors/invalid-argument-error'); + const InvalidArgumentError = require('@node-oauth/oauth2-server/lib/errors/invalid-argument-error'); .. note:: This error indicates that the module is used incorrectly (i.e., there is a programming error) and should never be seen because of external errors (like invalid data sent by a client). diff --git a/docs/api/errors/invalid-client-error.rst b/docs/api/errors/invalid-client-error.rst index d25a493..5ddd0a4 100644 --- a/docs/api/errors/invalid-client-error.rst +++ b/docs/api/errors/invalid-client-error.rst @@ -6,7 +6,7 @@ Client authentication failed (e.g., unknown client, no client authentication inc :: - const InvalidClientError = require('oauth2-server/lib/errors/invalid-client-error'); + const InvalidClientError = require('@node-oauth/oauth2-server/lib/errors/invalid-client-error'); -------- diff --git a/docs/api/errors/invalid-grant-error.rst b/docs/api/errors/invalid-grant-error.rst index 8f2a9ba..7931714 100644 --- a/docs/api/errors/invalid-grant-error.rst +++ b/docs/api/errors/invalid-grant-error.rst @@ -6,7 +6,7 @@ The provided authorization grant (e.g., authorization code, resource owner crede :: - const InvalidGrantError = require('oauth2-server/lib/errors/invalid-grant-error'); + const InvalidGrantError = require('@node-oauth/oauth2-server/lib/errors/invalid-grant-error'); -------- diff --git a/docs/api/errors/invalid-request-error.rst b/docs/api/errors/invalid-request-error.rst index 119ab40..bbb38c4 100644 --- a/docs/api/errors/invalid-request-error.rst +++ b/docs/api/errors/invalid-request-error.rst @@ -6,7 +6,7 @@ The request is missing a required parameter, includes an invalid parameter value :: - const InvalidRequestError = require('oauth2-server/lib/errors/invalid-request-error'); + const InvalidRequestError = require('@node-oauth/oauth2-server/lib/errors/invalid-request-error'); -------- diff --git a/docs/api/errors/invalid-scope-error.rst b/docs/api/errors/invalid-scope-error.rst index 801930f..01c70d2 100644 --- a/docs/api/errors/invalid-scope-error.rst +++ b/docs/api/errors/invalid-scope-error.rst @@ -6,7 +6,7 @@ The requested scope is invalid, unknown, or malformed. See :rfc:`Section 4.1.2.1 :: - const InvalidScopeError = require('oauth2-server/lib/errors/invalid-scope-error'); + const InvalidScopeError = require('@node-oauth/oauth2-server/lib/errors/invalid-scope-error'); -------- diff --git a/docs/api/errors/invalid-token-error.rst b/docs/api/errors/invalid-token-error.rst index 21ffad8..fc0da03 100644 --- a/docs/api/errors/invalid-token-error.rst +++ b/docs/api/errors/invalid-token-error.rst @@ -6,7 +6,7 @@ The access token provided is expired, revoked, malformed, or invalid for other r :: - const InvalidTokenError = require('oauth2-server/lib/errors/invalid-token-error'); + const InvalidTokenError = require('@node-oauth/oauth2-server/lib/errors/invalid-token-error'); -------- diff --git a/docs/api/errors/oauth-error.rst b/docs/api/errors/oauth-error.rst index c7f1d86..83be465 100644 --- a/docs/api/errors/oauth-error.rst +++ b/docs/api/errors/oauth-error.rst @@ -6,7 +6,7 @@ Base class for all errors returned by this module. :: - const OAuthError = require('oauth2-server/lib/errors/oauth-error'); + const OAuthError = require('@node-oauth/oauth2-server/lib/errors/oauth-error'); -------- diff --git a/docs/api/errors/server-error.rst b/docs/api/errors/server-error.rst index 13f436e..7a2dcf9 100644 --- a/docs/api/errors/server-error.rst +++ b/docs/api/errors/server-error.rst @@ -6,7 +6,7 @@ The authorization server encountered an unexpected condition that prevented it f :: - const ServerError = require('oauth2-server/lib/errors/server-error'); + const ServerError = require('@node-oauth/oauth2-server/lib/errors/server-error'); ``ServerError`` is used to wrap unknown exceptions encountered during request processing. diff --git a/docs/api/errors/unauthorized-client-error.rst b/docs/api/errors/unauthorized-client-error.rst index d04cb08..9d104ca 100644 --- a/docs/api/errors/unauthorized-client-error.rst +++ b/docs/api/errors/unauthorized-client-error.rst @@ -6,7 +6,7 @@ The authenticated client is not authorized to use this authorization grant type. :: - const UnauthorizedClientError = require('oauth2-server/lib/errors/unauthorized-client-error'); + const UnauthorizedClientError = require('@node-oauth/oauth2-server/lib/errors/unauthorized-client-error'); -------- diff --git a/docs/api/errors/unauthorized-request-error.rst b/docs/api/errors/unauthorized-request-error.rst index 495f5f8..9ed2467 100644 --- a/docs/api/errors/unauthorized-request-error.rst +++ b/docs/api/errors/unauthorized-request-error.rst @@ -6,7 +6,7 @@ The request lacked any authentication information or the client attempted to use :: - const UnauthorizedRequestError = require('oauth2-server/lib/errors/unauthorized-request-error'); + const UnauthorizedRequestError = require('@node-oauth/oauth2-server/lib/errors/unauthorized-request-error'); According to :rfc:`Section 3.1 of RFC 6750 <6750#section-3.1>` you should just fail the request with ``401 Unauthorized`` and not send any error information in the body if this error occurs: diff --git a/docs/api/errors/unsupported-grant-type-error.rst b/docs/api/errors/unsupported-grant-type-error.rst index d2fe49f..1e812ed 100644 --- a/docs/api/errors/unsupported-grant-type-error.rst +++ b/docs/api/errors/unsupported-grant-type-error.rst @@ -6,7 +6,7 @@ The authorization grant type is not supported by the authorization server. See : :: - const UnsupportedGrantTypeError = require('oauth2-server/lib/errors/unsupported-grant-type-error'); + const UnsupportedGrantTypeError = require('@node-oauth/oauth2-server/lib/errors/unsupported-grant-type-error'); -------- diff --git a/docs/api/errors/unsupported-response-type-error.rst b/docs/api/errors/unsupported-response-type-error.rst index 28974eb..c9ee0fd 100644 --- a/docs/api/errors/unsupported-response-type-error.rst +++ b/docs/api/errors/unsupported-response-type-error.rst @@ -6,7 +6,7 @@ The authorization server does not supported obtaining an authorization code usin :: - const UnsupportedResponseTypeError = require('oauth2-server/lib/errors/unsupported-response-type-error'); + const UnsupportedResponseTypeError = require('@node-oauth/oauth2-server/lib/errors/unsupported-response-type-error'); -------- diff --git a/docs/api/oauth2-server.rst b/docs/api/oauth2-server.rst index 48acf53..38cf6bd 100644 --- a/docs/api/oauth2-server.rst +++ b/docs/api/oauth2-server.rst @@ -6,7 +6,7 @@ Represents an OAuth2 server instance. :: - const OAuth2Server = require('oauth2-server'); + const OAuth2Server = require('@node-oauth/oauth2-server'); -------- @@ -94,7 +94,7 @@ Possible errors include but are not limited to: :doc:`/api/errors/unauthorized-request-error`: The protected resource request failed authentication. -The returned ``Promise`` **must** be ignored if ``callback`` is used. +**Versions <=4.x note:** The returned ``Promise`` **must** be ignored if ``callback`` is used. **Remarks:** @@ -139,7 +139,7 @@ Authorizes a token request. +-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ | [options={}] | Object | Handler options. | +-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ -| [options.authenticateHandler=undefined] | Object | The authenticate handler (see remarks section). | +| [options.authenticateHandler=undefined] | Object | The authenticate handler (see remarks section below). | +-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ | [options.allowEmptyState=false] | Boolean | Allow clients to specify an empty ``state``. | +-----------------------------------------+-----------------+-----------------------------------------------------------------------------+ @@ -158,7 +158,7 @@ Possible errors include but are not limited to: :doc:`/api/errors/access-denied-error` The resource owner denied the access request (i.e. ``request.query.allow`` was ``'false'``). -The returned ``Promise`` **must** be ignored if ``callback`` is used. +**Versions <=4.x note:** The returned ``Promise`` **must** be ignored if ``callback`` is used. **Remarks:** @@ -252,7 +252,7 @@ Possible errors include but are not limited to: :doc:`/api/errors/invalid-grant-error`: The access token request was invalid or not authorized. -The returned ``Promise`` **must** be ignored if ``callback`` is used. +**Versions <=4.x note:** The returned ``Promise`` **must** be ignored if ``callback`` is used. **Remarks:** diff --git a/docs/api/request.rst b/docs/api/request.rst index b8f8963..7d5f4ca 100644 --- a/docs/api/request.rst +++ b/docs/api/request.rst @@ -6,7 +6,7 @@ Represents an incoming HTTP request. :: - const Request = require('oauth2-server').Request; + const Request = require('@node-oauth/oauth2-server').Request; -------- @@ -50,7 +50,7 @@ To convert `Express' request`_ to a ``Request`` simply pass ``req`` as ``options :: function(req, res, next) { - var request = new Request(req); + let request = new Request(req); // ... } diff --git a/docs/api/response.rst b/docs/api/response.rst index 48cc36d..2c5d332 100644 --- a/docs/api/response.rst +++ b/docs/api/response.rst @@ -6,7 +6,7 @@ Represents an outgoing HTTP response. :: - const Response = require('oauth2-server').Response; + const Response = require('@node-oauth/oauth2-server').Response; -------- @@ -46,7 +46,7 @@ To convert `Express' response`_ to a ``Response`` simply pass ``res`` as ``optio :: function(req, res, next) { - var response = new Response(res); + let response = new Response(res); // ... } diff --git a/docs/docs/adapters.rst b/docs/docs/adapters.rst index c302d34..bec9ce6 100644 --- a/docs/docs/adapters.rst +++ b/docs/docs/adapters.rst @@ -7,9 +7,9 @@ The *oauth2-server* module is typically not used directly but through one of the .. framework-agnostic but there are several officially supported adapters available for popular HTTP server frameworks such as Express_ and Koa_. - express-oauth-server_ for Express_ -- koa-oauth-server_ for Koa_ +- koa-oauth-server_ for Koa_ (outdated, maintainer wanted!) -.. _express-oauth-server: https://npmjs.org/package/express-oauth-server +.. _express-oauth-server: https://www.npmjs.com/package/@node-oauth/express-oauth-server .. _Express: https://npmjs.org/package/express .. _koa-oauth-server: https://npmjs.org/package/koa-oauth-server .. _Koa: https://npmjs.org/package/koa diff --git a/docs/docs/getting-started.rst b/docs/docs/getting-started.rst index ff2c115..1e7f076 100644 --- a/docs/docs/getting-started.rst +++ b/docs/docs/getting-started.rst @@ -9,16 +9,16 @@ Installation oauth2-server_ is available via npm_. -.. _oauth2-server: https://npmjs.org/package/oauth2-server +.. _oauth2-server: https://www.npmjs.com/package/@node-oauth/oauth2-server .. _npm: https://npmjs.org .. code-block:: sh $ npm install oauth2-server -.. note:: The *oauth2-server* module is framework-agnostic but there are several officially supported adapters available for popular HTTP server frameworks such as Express_ and Koa_. If you're using one of those frameworks it is strongly recommended to use the respective adapter module instead of rolling your own. +.. note:: The *oauth2-server* module is framework-agnostic but there are several officially supported adapters available for popular HTTP server frameworks such as Express_ and Koa_ (maintainer wanted!). If you're using one of those frameworks it is strongly recommended to use the respective adapter module instead of rolling your own. -.. _Express: https://npmjs.org/package/express-oauth-server +.. _Express: https://www.npmjs.com/package/@node-oauth/express-oauth-server .. _Koa: https://npmjs.org/package/koa-oauth-server @@ -29,12 +29,14 @@ Features - Supports :ref:`authorization code `, :ref:`client credentials `, :ref:`refresh token ` and :ref:`password ` grant, as well as :ref:`extension grants `, with scopes. - Can be used with *promises*, *Node-style callbacks*, *ES6 generators* and *async*/*await* (using Babel_). +- From version 5.0.0 fully native async/await implemented - Fully :rfc:`6749` and :rfc:`6750` compliant. +- Supports PKCE (:rfc:`7636`) - Implicitly supports any form of storage, e.g. *PostgreSQL*, *MySQL*, *MongoDB*, *Redis*, etc. - Complete `test suite`_. .. _Babel: https://babeljs.io -.. _test suite: https://github.com/oauthjs/node-oauth2-server/tree/master/test +.. _test suite: https://github.com/node-oauth/node-oauth2-server/tree/master/test .. _quick-start: @@ -46,7 +48,7 @@ Quick Start :: - const OAuth2Server = require('oauth2-server'); + const OAuth2Server = require('@node-oauth/oauth2-server'); const oauth = new OAuth2Server({ model: require('./model') @@ -78,7 +80,7 @@ Quick Start :: - const AccessDeniedError = require('oauth2-server/lib/errors/access-denied-error'); + const AccessDeniedError = require('@node-oauth/oauth2-server/lib/errors/access-denied-error'); oauth.authorize(request, response) .then((code) => { diff --git a/docs/index.rst b/docs/index.rst index 4a7c341..80f4b6a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,10 +4,10 @@ oauth2-server_ is a complete, compliant and well tested module for implementing an OAuth2 server in Node.js_. The project is `hosted on GitHub`_ and the included test suite is automatically `run on Travis CI`_. -.. _oauth2-server: https://npmjs.org/package/oauth2-server +.. _oauth2-server: https://www.npmjs.com/package/@node-oauth/oauth2-server .. _Node.js: https://nodejs.org -.. _hosted on GitHub: https://github.com/oauthjs/node-oauth2-server -.. _run on Travis CI: https://travis-ci.org/oauthjs/node-oauth2-server +.. _hosted on GitHub: https://github.com/node-oauth/node-oauth2-server +.. _run on GitHub CI: https://github.com/node-oauth/node-oauth2-server/actions :ref:`installation` @@ -17,7 +17,7 @@ Example Usage :: - const OAuth2Server = require('oauth2-server'); + const OAuth2Server = require('@node-oauth/oauth2-server'); const Request = OAuth2Server.Request; const Response = OAuth2Server.Response; @@ -84,5 +84,6 @@ See the :doc:`/model/spec` of what is required from the model passed to :doc:`/a :hidden: misc/extension-grants + misc/pkce misc/migrating-v2-to-v3 diff --git a/docs/misc/extension-grants.rst b/docs/misc/extension-grants.rst index 1fbe55a..4ce22bf 100644 --- a/docs/misc/extension-grants.rst +++ b/docs/misc/extension-grants.rst @@ -6,7 +6,7 @@ Create a subclass of ``AbstractGrantType`` and create methods `handle` and `save .. code-block:: js - const OAuth2Server = require('oauth2-server'); + const OAuth2Server = require('@node-oauth/oauth2-server'); const AbstractGrantType = OAuth2Server.AbstractGrantType; const InvalidArgumentError = OAuth2Server.InvalidArgumentError; const InvalidRequestError = OAuth2Server.InvalidRequestError; diff --git a/docs/misc/pkce.rst b/docs/misc/pkce.rst new file mode 100644 index 0000000..436e000 --- /dev/null +++ b/docs/misc/pkce.rst @@ -0,0 +1,146 @@ +================ + PKCE Support +================ + +Starting with release 4.3.0_ this library supports PKCE (Proof Key for Code Exchange by OAuth Public Clients) as +defined in :rfc:`7636`. + +.. _4.3.0: https://github.com/node-oauth/node-oauth2-server/releases/tag/v4.3.0 + +The PKCE integrates only with the :ref:`authorization code `. The abstract workflow looks like +the following: + +:: + + +-------------------+ + | Authz Server | + +--------+ | +---------------+ | + | |--(A)- Authorization Request ---->| | | + | | + t(code_verifier), t_m | | Authorization | | + | | | | Endpoint | | + | |<-(B)---- Authorization Code -----| | | + | | | +---------------+ | + | Client | | | + | | | +---------------+ | + | |--(C)-- Access Token Request ---->| | | + | | + code_verifier | | Token | | + | | | | Endpoint | | + | |<-(D)------ Access Token ---------| | | + +--------+ | +---------------+ | + +-------------------+ + + Figure 2: Abstract Protocol Flow + +See :rfc:`Section 1 of RFC 7636 <7636#section-1.1>`. + +1. Authorization request +======================== + +.. _PKCE#authorizationRequest: + +| A. The client creates and records a secret named the "code_verifier" +| and derives a transformed version "t(code_verifier)" (referred to as the "code_challenge"), +| which is sent in the OAuth 2.0 Authorization Request along with the transformation method "t_m". + +The following shows an example of how a client could generate a `code_challenge`` and +``code_challenge_method`` for the authorizazion request. + +:: + // helper fn for base64 encoding + const base64URLEncode = str => str.toString('base64') + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=/g, '') + + // This is the code_verifier, which is INITIALLY KEPT SECRET on the client + // and which is later passed as request param to the token endpoint. + // DO NOT SEND this with the authorization request! + const codeVerifier = base64URLEncode(crypto.randomBytes(32)) + + // This is the hashed version of the verifier, which is sent to the authorization endpoint. + // This is named t(code_verifier) in the above workflow + // Send this with the authorization request! + const codeChallenge = base64URLEncode(crypto.createHash('sha256').update(codeVerifier).digest()) + + // This is the name of the code challenge method + // This is named t_m in the above workflow + // Send this with the authorization request! + const codeChallengeMethod = 'S256' + + // add these to the request that is fired from the client + +In this project the authorize endpoint calls OAuth2Server.prototype.authorize which itself uses AuthorizeHandler. +If your Request body contains code_challenge and code_challenge_method then PKCE is active. + +:: + + const server = new OAuth2Server({ model }) + + // this could be added to express or other middleware + const authorizeEndpoint = function (req, res, next) { + const request = new Request(req) + req.query.code_challenge // the codeChallenge value + req.query.code_challenge_method // 'S256' + + server.authorize(request, response, options) + .then(function (code) { + // add code to response, code should not contain + // code_challenge or code_challenge_method + }) + .catch(function (err) { + // handle error condition + }) + } + +2. Authorization response +========================= + +.. _PKCE#authorizationResponse: + +| B. The Authorization Endpoint responds as usual but records +| "t(code_verifier)" and the transformation method. + +The ``AuthorizeHandler.handle`` saves code challenge and code challenge method automatically via ``model.saveAuthorizationCode``. +Note that this calls your model with additional arguments ``codeChallenge`` and ``codeChallengeMethod``. + + +3. Access Token Request +======================= + +.. _PKCE#accessTokenRequest: + +| C. The client then sends the authorization code in the Access Token +| Request as usual but includes the "code_verifier" secret generated +| at (A). + +This is usually done in your token endpoint, that uses ``OAuth2Server.token``. +Note that your client should have kept ``code_verifier`` a secret until this step and now includes it as param for the token endpoint call. + +:: + + const server = new OAuth2Server({ model }) + + // ...authorizeEndpoint + + // this could be added to express or other middleware + const tokenEndpoint = function (req, res, next) { + const request = new Request(req) + request.body.code_verifier // the non-hashed code verifier + server.token(request, response, options) + .then(function (code) { + // add code to response, code should contain + }) + .catch(function (err) { + // handle error condition + }) + } + +| D. The authorization server transforms "code_verifier" and compares +| it to "t(code_verifier)" from (B). Access is denied if they are +| not equal. + +This will call ``model.getAuthorizationCode`` to load the code. +The loaded code has to contain ``codeChallenge`` and ``codeChallengeMethod``. +If ``model.saveAuthorizationCode`` did not cover these values when saving the code then this step will deny the request. + +See :ref:`Model#saveAuthorizationCode` and :ref:`Model#getAuthorizationCode` diff --git a/docs/model/overview.rst b/docs/model/overview.rst index 62c9ffa..76f2c3a 100644 --- a/docs/model/overview.rst +++ b/docs/model/overview.rst @@ -31,10 +31,11 @@ Model functions used by the authorization code grant: - :ref:`Model#generateAccessToken` - :ref:`Model#generateRefreshToken` - :ref:`Model#generateAuthorizationCode` -- :ref:`Model#getAuthorizationCode` +- :ref:`Model#saveAuthorizationCode` - :ref:`Model#getClient` - :ref:`Model#saveToken` - :ref:`Model#saveAuthorizationCode` +- :ref:`Model#getAuthorizationCode` - :ref:`Model#revokeAuthorizationCode` - :ref:`Model#validateScope` - :ref:`Model#validateRedirectUri` diff --git a/docs/model/spec.rst b/docs/model/spec.rst index 953c281..fcce475 100644 --- a/docs/model/spec.rst +++ b/docs/model/spec.rst @@ -2,7 +2,9 @@ Model Specification ===================== -Each model function supports *promises*, *Node-style callbacks*, *ES6 generators* and *async*/*await* (using Babel_). Note that promise support implies support for returning plain values where asynchronism is not required. +**Version >=5.x:** Callback support has been removed! Each model function supports either sync or async (``Promise`` or ``async function``) return values. + +**Version <=4.x:** Each model function supports *promises*, *Node-style callbacks*, *ES6 generators* and *async*/*await* (using Babel_). Note that promise support implies support for returning plain values where asynchronism is not required. .. _Babel: https://babeljs.io @@ -14,9 +16,9 @@ Each model function supports *promises*, *Node-style callbacks*, *ES6 generators return new Promise('works!'); }, - // Or, calling a Node-style callback. - getAuthorizationCode: function(done) { - done(null, 'works!'); + // Or sync-style values + getAuthorizationCode: function() { + return 'works!' }, // Or, using generators. @@ -32,7 +34,7 @@ Each model function supports *promises*, *Node-style callbacks*, *ES6 generators } }; - const OAuth2Server = require('oauth2-server'); + const OAuth2Server = require('@node-oauth/oauth2-server'); let oauth = new OAuth2Server({model: model}); Code examples on this page use *promises*. @@ -41,7 +43,7 @@ Code examples on this page use *promises*. .. _Model#generateAccessToken: -``generateAccessToken(client, user, scope, [callback])`` +``generateAccessToken(client, user, scope)`` ======================================================== Invoked to generate a new access token. @@ -66,8 +68,6 @@ This model function is **optional**. If not implemented, a default handler is us +------------+----------+---------------------------------------------------------------------+ | scope | String | The scopes associated with the access token. Can be ``null``. | +------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -85,7 +85,7 @@ A ``String`` to be used as access token. .. _Model#generateRefreshToken: -``generateRefreshToken(client, user, scope, [callback])`` +``generateRefreshToken(client, user, scope)`` ========================================================= Invoked to generate a new refresh token. @@ -109,8 +109,6 @@ This model function is **optional**. If not implemented, a default handler is us +------------+----------+---------------------------------------------------------------------+ | scope | String | The scopes associated with the refresh token. Can be ``null``. | +------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -128,7 +126,7 @@ A ``String`` to be used as refresh token. .. _Model#generateAuthorizationCode: -``generateAuthorizationCode(client, user, scope, [callback])`` +``generateAuthorizationCode(client, user, scope)`` ========================================= Invoked to generate a new authorization code. @@ -150,8 +148,6 @@ This model function is **optional**. If not implemented, a default handler is us +------------+----------+---------------------------------------------------------------------+ | scope | String | The scopes associated with the authorization code. Can be ``null``. | +------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -163,7 +159,7 @@ A ``String`` to be used as authorization code. .. _Model#getAccessToken: -``getAccessToken(accessToken, [callback])`` +``getAccessToken(accessToken)`` =========================================== Invoked to retrieve an existing access token previously saved through :ref:`Model#saveToken() `. @@ -181,8 +177,6 @@ This model function is **required** if :ref:`OAuth2Server#authenticate() `. @@ -255,8 +249,6 @@ This model function is **required** if the ``refresh_token`` grant is used. +==============+==========+=====================================================================+ | refreshToken | String | The access token to retrieve. | +--------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+--------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -311,7 +303,7 @@ An ``Object`` representing the refresh token and associated data. .. _Model#getAuthorizationCode: -``getAuthorizationCode(authorizationCode, [callback])`` +``getAuthorizationCode(authorizationCode)`` ======================================================= Invoked to retrieve an existing authorization code previously saved through :ref:`Model#saveAuthorizationCode() `. @@ -329,8 +321,6 @@ This model function is **required** if the ``authorization_code`` grant is used. +===================+==========+=====================================================================+ | authorizationCode | String | The authorization code to retrieve. | +-------------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+-------------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -388,7 +378,7 @@ An ``Object`` representing the authorization code and associated data. .. _Model#getClient: -``getClient(clientId, clientSecret, [callback])`` +``getClient(clientId, clientSecret)`` ================================================= Invoked to retrieve a client using a client id or a client id/client secret combination, depending on the grant type. @@ -411,8 +401,6 @@ This model function is **required** for all grant types. +--------------+----------+---------------------------------------------------------------------+ | clientSecret | String | The client secret of the client to retrieve. Can be ``null``. | +--------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+--------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -460,7 +448,7 @@ The return value (``client``) can carry additional properties that will be ignor .. _Model#getUser: -``getUser(username, password, [callback])`` +``getUser(username, password)`` =========================================== Invoked to retrieve a user using a username/password combination. @@ -480,8 +468,6 @@ This model function is **required** if the ``password`` grant is used. +------------+----------+---------------------------------------------------------------------+ | password | String | The user's password. | +------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -500,7 +486,7 @@ An ``Object`` representing the user, or a falsy value if no such user could be f .. _Model#getUserFromClient: -``getUserFromClient(client, [callback])`` +``getUserFromClient(client)`` ========================================= Invoked to retrieve the user associated with the specified client. @@ -520,8 +506,6 @@ This model function is **required** if the ``client_credentials`` grant is used. +------------+----------+---------------------------------------------------------------------+ | client.id | String | A unique string identifying the client. | +------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -542,7 +526,7 @@ An ``Object`` representing the user, or a falsy value if the client does not hav .. _Model#saveToken: -``saveToken(token, client, user, [callback])`` +``saveToken(token, client, user)`` ============================================== Invoked to save an access token and optionally a refresh token, depending on the grant type. @@ -577,8 +561,6 @@ This model function is **required** for all grant types. +-------------------------------+----------+---------------------------------------------------------------------+ | user | Object | The user associated with the token(s). | +-------------------------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+-------------------------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -650,7 +632,7 @@ If the ``allowExtendedTokenAttributes`` server option is enabled (see :ref:`OAut .. _Model#saveAuthorizationCode: -``saveAuthorizationCode(code, client, user, [callback])`` +``saveAuthorizationCode(code, client, user)`` ========================================================= Invoked to save an authorization code. @@ -680,8 +662,12 @@ This model function is **required** if the ``authorization_code`` grant is used. +------------------------+----------+---------------------------------------------------------------------+ | user | Object | The user associated with the authorization code. | +------------------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | +| codeChallenge | String | The code challenge; hash or plain. Only present in PKCE requests. | +------------------------+----------+---------------------------------------------------------------------+ +| codeChallengeMethod | String | One of 'plain' or 'S256'. Only present in PKCE requests. | ++------------------------+----------+---------------------------------------------------------------------+ + +For PKCE requests, see :ref:`PKCE#authorizationRequest` .. todo:: Is ``code.scope`` really optional? @@ -742,7 +728,7 @@ An ``Object`` representing the authorization code and associated data. .. _Model#revokeToken: -``revokeToken(token, [callback])`` +``revokeToken(token)`` ================================== Invoked to revoke a refresh token. @@ -772,8 +758,6 @@ This model function is **required** if the ``refresh_token`` grant is used. +-------------------------------+----------+---------------------------------------------------------------------+ | token.user | Object | The user associated with the refresh token. | +-------------------------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+-------------------------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -797,7 +781,7 @@ Return ``true`` if the revocation was successful or ``false`` if the refresh tok .. _Model#revokeAuthorizationCode: -``revokeAuthorizationCode(code, [callback])`` +``revokeAuthorizationCode(code)`` ============================================= Invoked to revoke an authorization code. @@ -829,8 +813,6 @@ This model function is **required** if the ``authorization_code`` grant is used. +--------------------+----------+---------------------------------------------------------------------+ | code.user | Object | The user associated with the authorization code. | +--------------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+--------------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -854,7 +836,7 @@ Return ``true`` if the revocation was successful or ``false`` if the authorizati .. _Model#validateScope: -``validateScope(user, client, scope, [callback])`` +``validateScope(user, client, scope)`` ================================================== Invoked to check if the requested ``scope`` is valid for a particular ``client``/``user`` combination. @@ -880,8 +862,6 @@ This model function is **optional**. If not implemented, any scope is accepted. +------------+----------+---------------------------------------------------------------------+ | scope | String | The scopes to validate. | +------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -929,12 +909,13 @@ Note that the example above will still reject completely invalid scopes, since ` .. _Model#verifyScope: -``verifyScope(accessToken, scope, [callback])`` +``verifyScope(accessToken, scope)`` =============================================== Invoked during request authentication to check if the provided access token was authorized the requested scopes. -This model function is **required** if scopes are used with :ref:`OAuth2Server#authenticate() `. +This model function is **required** if scopes are used with :ref:`OAuth2Server#authenticate() ` +but it's never called, if you provide your own ``authenticateHandler`` to the options. **Invoked during:** @@ -961,8 +942,6 @@ This model function is **required** if scopes are used with :ref:`OAuth2Server#a +------------------------------+----------+---------------------------------------------------------------------+ | scope | String | The required scopes. | +------------------------------+----------+---------------------------------------------------------------------+ -| [callback] | Function | Node-style callback to be used instead of the returned ``Promise``. | -+------------------------------+----------+---------------------------------------------------------------------+ **Return value:** @@ -989,7 +968,7 @@ Returns ``true`` if the access token passes, ``false`` otherwise. .. _Model#validateRedirectUri: -``validateRedirectUri(redirectUri, client, [callback])`` +``validateRedirectUri(redirectUri, client)`` ================================================================ Invoked to check if the provided ``redirectUri`` is valid for a particular ``client``. From c24352610bada42dd8bfbe00ee30d0024e79e783 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Thu, 3 Aug 2023 16:26:33 +0200 Subject: [PATCH 02/13] docs: fix outdated links/names --- docs/index.rst | 2 +- docs/npm_conf.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 80f4b6a..13b41b7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,7 +2,7 @@ oauth2-server =============== -oauth2-server_ is a complete, compliant and well tested module for implementing an OAuth2 server in Node.js_. The project is `hosted on GitHub`_ and the included test suite is automatically `run on Travis CI`_. +oauth2-server_ is a complete, compliant and well tested module for implementing an OAuth2 server in Node.js_. The project is `hosted on GitHub`_ and the included test suite is automatically `run on GitHub CI`_. .. _oauth2-server: https://www.npmjs.com/package/@node-oauth/oauth2-server .. _Node.js: https://nodejs.org diff --git a/docs/npm_conf.py b/docs/npm_conf.py index f86915f..41b0381 100644 --- a/docs/npm_conf.py +++ b/docs/npm_conf.py @@ -40,10 +40,10 @@ def get_config(): 'name': package['name'], 'version': package['version'], 'short_version': get_short_version(package['version']), - 'organization': 'oauthjs', + 'organization': '@node-oauth', 'copyright_year': get_copyright_year(2016), # TODO: Get authors from package. - 'docs_author': 'Max Truxa', - 'docs_author_email': 'dev@maxtruxa.com' + 'docs_author': 'Node-OAuth Authors', + 'docs_author_email': '' } From ac9e5c43bea5a8d6972902689aafbd706a514849 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Thu, 3 Aug 2023 16:31:47 +0200 Subject: [PATCH 03/13] docs: revert model overview links --- docs/model/overview.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/model/overview.rst b/docs/model/overview.rst index 76f2c3a..62c9ffa 100644 --- a/docs/model/overview.rst +++ b/docs/model/overview.rst @@ -31,11 +31,10 @@ Model functions used by the authorization code grant: - :ref:`Model#generateAccessToken` - :ref:`Model#generateRefreshToken` - :ref:`Model#generateAuthorizationCode` -- :ref:`Model#saveAuthorizationCode` +- :ref:`Model#getAuthorizationCode` - :ref:`Model#getClient` - :ref:`Model#saveToken` - :ref:`Model#saveAuthorizationCode` -- :ref:`Model#getAuthorizationCode` - :ref:`Model#revokeAuthorizationCode` - :ref:`Model#validateScope` - :ref:`Model#validateRedirectUri` From 1ae0877d231e1dc006d319979a94eb93c8482047 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Thu, 3 Aug 2023 16:39:27 +0200 Subject: [PATCH 04/13] docs: add readthedocs config yml --- .readthedocs.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .readthedocs.yml diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..d9ee790 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,22 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +# Set the version of Python and other tools you might need +build: + os: ubuntu-22.04 + tools: + python: "3.11" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/conf.py + +# We recommend specifying your dependencies to enable reproducible builds: +# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html +# python: +# install: +# - requirements: docs/requirements.txt \ No newline at end of file From f13c55f7ef7611bda4695cb6357ac44faa5fbfa0 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Thu, 3 Aug 2023 17:01:21 +0200 Subject: [PATCH 05/13] docs: update sphinx conf --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index d9aae79..2b65064 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -272,5 +272,5 @@ highlight_language = 'js' def setup(app): - app.add_stylesheet('custom.css') + app.add_css_file('custom.css') From dc60b224c9ff7d6401419289a208c86e2d65a9be Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Thu, 3 Aug 2023 17:04:44 +0200 Subject: [PATCH 06/13] docs: fix old oauth2-server references --- docs/conf.py | 2 +- docs/docs/getting-started.rst | 2 +- docs/index.rst | 6 +++--- docs/misc/migrating-v2-to-v3.rst | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 2b65064..a621e90 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# oauth2-server documentation build configuration file, created by +# @node-oauth/oauth2-server documentation build configuration file, created by # sphinx-quickstart on Thu Nov 17 16:47:05 2016. # # This file is execfile()d with the current directory set to its containing dir. diff --git a/docs/docs/getting-started.rst b/docs/docs/getting-started.rst index 1e7f076..1a55f18 100644 --- a/docs/docs/getting-started.rst +++ b/docs/docs/getting-started.rst @@ -14,7 +14,7 @@ oauth2-server_ is available via npm_. .. code-block:: sh - $ npm install oauth2-server + $ npm install @node-oauth/oauth2-server .. note:: The *oauth2-server* module is framework-agnostic but there are several officially supported adapters available for popular HTTP server frameworks such as Express_ and Koa_ (maintainer wanted!). If you're using one of those frameworks it is strongly recommended to use the respective adapter module instead of rolling your own. diff --git a/docs/index.rst b/docs/index.rst index 13b41b7..f88c4b4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,6 +1,6 @@ -=============== - oauth2-server -=============== +========================== + @node-oauth/oauth2-server +========================== oauth2-server_ is a complete, compliant and well tested module for implementing an OAuth2 server in Node.js_. The project is `hosted on GitHub`_ and the included test suite is automatically `run on GitHub CI`_. diff --git a/docs/misc/migrating-v2-to-v3.rst b/docs/misc/migrating-v2-to-v3.rst index 9d03c8f..8d1290c 100644 --- a/docs/misc/migrating-v2-to-v3.rst +++ b/docs/misc/migrating-v2-to-v3.rst @@ -11,7 +11,7 @@ Middlewares The naming of the exposed middlewares has changed to match the OAuth2 _RFC_ more closely. Please refer to the table below: +-------------------+------------------------------------------------+ -| oauth2-server 2.x | oauth2-server 3.x | +| oauth2-server 2.x | @node-oauth/oauth2-server 3.x | +===================+================================================+ | authorise | authenticate | +-------------------+------------------------------------------------+ From 99b3346bfc2d07088263d039363be1ef3a284422 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Thu, 3 Aug 2023 17:14:48 +0200 Subject: [PATCH 07/13] docs: fix pkce code rendering --- docs/misc/pkce.rst | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/misc/pkce.rst b/docs/misc/pkce.rst index 436e000..b6f4447 100644 --- a/docs/misc/pkce.rst +++ b/docs/misc/pkce.rst @@ -38,15 +38,13 @@ See :rfc:`Section 1 of RFC 7636 <7636#section-1.1>`. .. _PKCE#authorizationRequest: -| A. The client creates and records a secret named the "code_verifier" -| and derives a transformed version "t(code_verifier)" (referred to as the "code_challenge"), -| which is sent in the OAuth 2.0 Authorization Request along with the transformation method "t_m". +.. A:: The client creates and records a secret named the "code_verifier" and derives a transformed version "t(code_verifier)" (referred to as the "code_challenge"), which is sent in the OAuth 2.0 Authorization Request along with the transformation method "t_m". The following shows an example of how a client could generate a `code_challenge`` and ``code_challenge_method`` for the authorizazion request. :: - // helper fn for base64 encoding + const base64URLEncode = str => str.toString('base64') .replace(/\+/g, '-') .replace(/\//g, '_') @@ -97,8 +95,7 @@ If your Request body contains code_challenge and code_challenge_method then PKCE .. _PKCE#authorizationResponse: -| B. The Authorization Endpoint responds as usual but records -| "t(code_verifier)" and the transformation method. +.. B:: The Authorization Endpoint responds as usual but records "t(code_verifier)" and the transformation method. The ``AuthorizeHandler.handle`` saves code challenge and code challenge method automatically via ``model.saveAuthorizationCode``. Note that this calls your model with additional arguments ``codeChallenge`` and ``codeChallengeMethod``. @@ -109,9 +106,7 @@ Note that this calls your model with additional arguments ``codeChallenge`` and .. _PKCE#accessTokenRequest: -| C. The client then sends the authorization code in the Access Token -| Request as usual but includes the "code_verifier" secret generated -| at (A). +.. C:: The client then sends the authorization code in the Access Token Request as usual but includes the "code_verifier" secret generated at (A). This is usually done in your token endpoint, that uses ``OAuth2Server.token``. Note that your client should have kept ``code_verifier`` a secret until this step and now includes it as param for the token endpoint call. From 71fa350c2aa7dfaf0db70aba1e8b708c7c405f8d Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Thu, 3 Aug 2023 17:15:44 +0200 Subject: [PATCH 08/13] docs: make section D citation block --- docs/misc/pkce.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/misc/pkce.rst b/docs/misc/pkce.rst index b6f4447..da698c2 100644 --- a/docs/misc/pkce.rst +++ b/docs/misc/pkce.rst @@ -130,9 +130,7 @@ Note that your client should have kept ``code_verifier`` a secret until this ste }) } -| D. The authorization server transforms "code_verifier" and compares -| it to "t(code_verifier)" from (B). Access is denied if they are -| not equal. +.. D:: The authorization server transforms "code_verifier" and compares it to "t(code_verifier)" from (B). Access is denied if they are not equal. This will call ``model.getAuthorizationCode`` to load the code. The loaded code has to contain ``codeChallenge`` and ``codeChallengeMethod``. From 3628d7d519c20aa72081a9d091b050ffc883bd28 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Thu, 3 Aug 2023 17:20:38 +0200 Subject: [PATCH 09/13] docs: use intendation for quote blocks in docs/pkce --- docs/misc/pkce.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/misc/pkce.rst b/docs/misc/pkce.rst index da698c2..c0a847d 100644 --- a/docs/misc/pkce.rst +++ b/docs/misc/pkce.rst @@ -38,7 +38,7 @@ See :rfc:`Section 1 of RFC 7636 <7636#section-1.1>`. .. _PKCE#authorizationRequest: -.. A:: The client creates and records a secret named the "code_verifier" and derives a transformed version "t(code_verifier)" (referred to as the "code_challenge"), which is sent in the OAuth 2.0 Authorization Request along with the transformation method "t_m". + A. The client creates and records a secret named the "code_verifier" and derives a transformed version "t(code_verifier)" (referred to as the "code_challenge"), which is sent in the OAuth 2.0 Authorization Request along with the transformation method "t_m". The following shows an example of how a client could generate a `code_challenge`` and ``code_challenge_method`` for the authorizazion request. @@ -95,7 +95,7 @@ If your Request body contains code_challenge and code_challenge_method then PKCE .. _PKCE#authorizationResponse: -.. B:: The Authorization Endpoint responds as usual but records "t(code_verifier)" and the transformation method. + B. The Authorization Endpoint responds as usual but records "t(code_verifier)" and the transformation method. The ``AuthorizeHandler.handle`` saves code challenge and code challenge method automatically via ``model.saveAuthorizationCode``. Note that this calls your model with additional arguments ``codeChallenge`` and ``codeChallengeMethod``. @@ -106,7 +106,7 @@ Note that this calls your model with additional arguments ``codeChallenge`` and .. _PKCE#accessTokenRequest: -.. C:: The client then sends the authorization code in the Access Token Request as usual but includes the "code_verifier" secret generated at (A). + C. The client then sends the authorization code in the Access Token Request as usual but includes the "code_verifier" secret generated at (A). This is usually done in your token endpoint, that uses ``OAuth2Server.token``. Note that your client should have kept ``code_verifier`` a secret until this step and now includes it as param for the token endpoint call. @@ -130,7 +130,7 @@ Note that your client should have kept ``code_verifier`` a secret until this ste }) } -.. D:: The authorization server transforms "code_verifier" and compares it to "t(code_verifier)" from (B). Access is denied if they are not equal. + D. The authorization server transforms "code_verifier" and compares it to "t(code_verifier)" from (B). Access is denied if they are not equal. This will call ``model.getAuthorizationCode`` to load the code. The loaded code has to contain ``codeChallenge`` and ``codeChallengeMethod``. From 24d9e698ce03e654b6692b8bfc942d4a115d2db3 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Thu, 3 Aug 2023 17:28:02 +0200 Subject: [PATCH 10/13] docs: make pkce section not part of the code block --- docs/misc/pkce.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/misc/pkce.rst b/docs/misc/pkce.rst index c0a847d..ccc0e48 100644 --- a/docs/misc/pkce.rst +++ b/docs/misc/pkce.rst @@ -109,7 +109,6 @@ Note that this calls your model with additional arguments ``codeChallenge`` and C. The client then sends the authorization code in the Access Token Request as usual but includes the "code_verifier" secret generated at (A). This is usually done in your token endpoint, that uses ``OAuth2Server.token``. -Note that your client should have kept ``code_verifier`` a secret until this step and now includes it as param for the token endpoint call. :: @@ -130,6 +129,9 @@ Note that your client should have kept ``code_verifier`` a secret until this ste }) } +Note that your client should have kept ``code_verifier`` a secret until this step and now includes it as param for the token endpoint call. + + D. The authorization server transforms "code_verifier" and compares it to "t(code_verifier)" from (B). Access is denied if they are not equal. This will call ``model.getAuthorizationCode`` to load the code. From 6dc20fc2a53f0fece9b65adb2d12cf44479013f5 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Thu, 3 Aug 2023 17:32:23 +0200 Subject: [PATCH 11/13] docs: add missing pkce params to saveAuthorizationCode --- docs/model/spec.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/model/spec.rst b/docs/model/spec.rst index fcce475..e84140d 100644 --- a/docs/model/spec.rst +++ b/docs/model/spec.rst @@ -632,7 +632,7 @@ If the ``allowExtendedTokenAttributes`` server option is enabled (see :ref:`OAut .. _Model#saveAuthorizationCode: -``saveAuthorizationCode(code, client, user)`` +``saveAuthorizationCode(code, client, user, [codeChallenge], [codeChallengeMethod])`` ========================================================= Invoked to save an authorization code. @@ -667,9 +667,7 @@ This model function is **required** if the ``authorization_code`` grant is used. | codeChallengeMethod | String | One of 'plain' or 'S256'. Only present in PKCE requests. | +------------------------+----------+---------------------------------------------------------------------+ -For PKCE requests, see :ref:`PKCE#authorizationRequest` - -.. todo:: Is ``code.scope`` really optional? +For PKCE requests, see :ref:`PKCE#authorizationRequest`. **Return value:** From 7be88d6546941cad2d592a50e674566611544184 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Fri, 4 Aug 2023 12:56:19 +0200 Subject: [PATCH 12/13] docs: model.saveAuthorizationCode pkce parameters corrected --- docs/model/spec.rst | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/model/spec.rst b/docs/model/spec.rst index e84140d..ffa233c 100644 --- a/docs/model/spec.rst +++ b/docs/model/spec.rst @@ -645,27 +645,27 @@ This model function is **required** if the ``authorization_code`` grant is used. **Arguments:** -+------------------------+----------+---------------------------------------------------------------------+ -| Name | Type | Description | -+========================+==========+=====================================================================+ -| code | Object | The code to be saved. | -+------------------------+----------+---------------------------------------------------------------------+ -| code.authorizationCode | String | The authorization code to be saved. | -+------------------------+----------+---------------------------------------------------------------------+ -| code.expiresAt | Date | The expiry time of the authorization code. | -+------------------------+----------+---------------------------------------------------------------------+ -| code.redirectUri | String | The redirect URI associated with the authorization code. | -+------------------------+----------+---------------------------------------------------------------------+ -| [code.scope] | String | The authorized scope of the authorization code. | -+------------------------+----------+---------------------------------------------------------------------+ -| client | Object | The client associated with the authorization code. | -+------------------------+----------+---------------------------------------------------------------------+ -| user | Object | The user associated with the authorization code. | -+------------------------+----------+---------------------------------------------------------------------+ -| codeChallenge | String | The code challenge; hash or plain. Only present in PKCE requests. | -+------------------------+----------+---------------------------------------------------------------------+ -| codeChallengeMethod | String | One of 'plain' or 'S256'. Only present in PKCE requests. | -+------------------------+----------+---------------------------------------------------------------------+ ++----------------------------+----------+---------------------------------------------------------------------+ +| Name | Type | Description | ++----------------------------+----------+---------------------------------------------------------------------+ +| code | Object | The code to be saved. | ++----------------------------+----------+---------------------------------------------------------------------+ +| code.authorizationCode | String | The authorization code to be saved. | ++----------------------------+----------+---------------------------------------------------------------------+ +| code.expiresAt | Date | The expiry time of the authorization code. | ++----------------------------+----------+---------------------------------------------------------------------+ +| code.redirectUri | String | The redirect URI associated with the authorization code. | ++----------------------------+----------+---------------------------------------------------------------------+ +| [code.scope] | String | The authorized scope of the authorization code. | ++----------------------------+----------+---------------------------------------------------------------------+ +| [code.codeChallenge] | String | The code challenge; hash or plain. Only present in PKCE requests. | ++----------------------------+----------+---------------------------------------------------------------------+ +| [code.codeChallengeMethod] | String | One of 'plain' or 'S256'. Only present in PKCE requests. | ++----------------------------+----------+---------------------------------------------------------------------+ +| client | Object | The client associated with the authorization code. | ++----------------------------+----------+---------------------------------------------------------------------+ +| user | Object | The user associated with the authorization code. | ++----------------------------+----------+---------------------------------------------------------------------+ For PKCE requests, see :ref:`PKCE#authorizationRequest`. From c2731237bf40c61a2357765e7084eff4c29d8eb9 Mon Sep 17 00:00:00 2001 From: jankapunkt Date: Fri, 4 Aug 2023 13:58:50 +0200 Subject: [PATCH 13/13] docs: model.saveAuthorizationCode pkce parameters corrected --- docs/misc/pkce.rst | 2 +- docs/model/spec.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/misc/pkce.rst b/docs/misc/pkce.rst index ccc0e48..cb52f1e 100644 --- a/docs/misc/pkce.rst +++ b/docs/misc/pkce.rst @@ -98,7 +98,7 @@ If your Request body contains code_challenge and code_challenge_method then PKCE B. The Authorization Endpoint responds as usual but records "t(code_verifier)" and the transformation method. The ``AuthorizeHandler.handle`` saves code challenge and code challenge method automatically via ``model.saveAuthorizationCode``. -Note that this calls your model with additional arguments ``codeChallenge`` and ``codeChallengeMethod``. +Note that this calls your model with additional properties ``code.codeChallenge`` and ``code.codeChallengeMethod``. 3. Access Token Request diff --git a/docs/model/spec.rst b/docs/model/spec.rst index ffa233c..b622d9c 100644 --- a/docs/model/spec.rst +++ b/docs/model/spec.rst @@ -632,7 +632,7 @@ If the ``allowExtendedTokenAttributes`` server option is enabled (see :ref:`OAut .. _Model#saveAuthorizationCode: -``saveAuthorizationCode(code, client, user, [codeChallenge], [codeChallengeMethod])`` +``saveAuthorizationCode(code, client, user)`` ========================================================= Invoked to save an authorization code.