feat: add requirePKCE option to enforce PKCE on the authorization code grant#449
feat: add requirePKCE option to enforce PKCE on the authorization code grant#449dhensby wants to merge 1 commit into
requirePKCE option to enforce PKCE on the authorization code grant#449Conversation
34c8162 to
ea917ab
Compare
There was a problem hiding this comment.
Pull request overview
Adds a new server option, requirePKCE, to enforce PKCE for the authorization_code grant across both the authorization and token endpoints, aligning the library with OAuth 2.1 / OAuth 2.0 Security BCP guidance.
Changes:
- Introduces
requirePKCEplumbing fromOAuth2Serveroptions into authorize + token handling paths. - Enforces PKCE at
/authorize(reject missingcode_challenge) and at/token(reject codes issued without a stored challenge). - Documents the new option and adds compliance tests covering the new behavior.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| test/compliance/pkce_test.js | Adds compliance tests validating requirePKCE behavior on authorize + token flows. |
| lib/server.js | Documents the new requirePKCE constructor option in JSDoc. |
| lib/handlers/token-handler.js | Threads requirePKCE into grant type instantiation options. |
| lib/handlers/authorize-handler.js | Rejects authorize requests missing code_challenge when requirePKCE is enabled. |
| lib/grant-types/authorization-code-grant-type.js | Rejects token exchanges for codes lacking a stored PKCE challenge when requirePKCE is enabled. |
| index.d.ts | Exposes requirePKCE in TypeScript option types. |
| docs/api/server.md | Documents requirePKCE in the server API docs table. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
I would add this paragraph to the documentation, unless this is already covered by #448 |
ea917ab to
0837585
Compare
|
Good shout. It isn't covered by #448 — that PR only adds the "PKCE vs client authentication & refresh tokens" section, nothing about requiring PKCE. So I've added a Also addressed Copilot's three notes in the same fixup: |
…ode grant OAuth 2.1 and RFC 9700 (Security BCP) §2.1.1 require/recommend PKCE for all authorization code flows; previously PKCE was opt-in per request. When `requirePKCE` is enabled (default `false`): - the authorize endpoint rejects requests without a `code_challenge` (InvalidRequestError), so no PKCE-less authorization codes are issued; and - the token endpoint rejects authorization codes issued without a `code_challenge` (InvalidGrantError), closing the gap for pre-existing codes. Plumbed through the server to the authorize and token handlers (mirroring `enablePlainPKCE`), documented in JSDoc/typings, and covered by compliance tests. Existing behaviour is unchanged when the option is off. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
96af831 to
b08d51c
Compare
What
Adds a
requirePKCEserver option that enforces PKCE on theauthorization_codegrant.Closes #179.
Why
OAuth 2.1 makes PKCE mandatory for the authorization code grant (all clients), and RFC 9700 (OAuth 2.0 Security BCP) §2.1.1 / §4.8 recommend authorization servers require it (PKCE downgrade attack). Previously this library only enforced PKCE if a
code_challengewas present — a client could skip PKCE entirely, and the only way to force it was a workaround that throws inmodel.saveAuthorizationCode.Behaviour
requirePKCEdefaults tofalse(no change to existing behaviour). Whentrue:code_challengeare rejected withInvalidRequestError— so no PKCE-less codes are ever issued.code_challengeare rejected withInvalidGrantError— covering codes issued before the option was enabled or via other paths.The library already implemented the RFC 7636 §4.6 downgrade mitigation (challenge ⇒ verifier required; a verifier with no challenge is rejected);
requirePKCElayers the "PKCE is mandatory" enforcement on top.Implementation
requirePKCEthroughserver.js→authorize-handler+token-handler→authorization-code-grant-type, mirroring the existingenablePlainPKCEoption.index.d.ts(AuthorizeOptions+TokenOptions).test/compliance/pkce_test.js: authorize rejects without a challenge, allows with one, and token rejects a no-challenge code.Full suite green (461 passing), lint clean. Strong candidate to become the default in v6 to align with OAuth 2.1.
🤖 Generated with Claude Code