Skip to content

Return RFC 6749 error fields from the token endpoint - #89

Open
roborourke wants to merge 2 commits into
WP-API:mainfrom
humanmade:roborourke/oauth-token-errors
Open

roborourke wants to merge 2 commits into
WP-API:mainfrom
humanmade:roborourke/oauth-token-errors

Conversation

@roborourke

Copy link
Copy Markdown
Collaborator

Token endpoint errors now include the error and error_description fields from RFC 6749 section 5.2.

Before this change, errors used the WordPress shape only: code, message and data. A standard OAuth client looks for a top-level error like invalid_grant, so it could not tell why a request failed. The WordPress fields stay, so clients that read code keep working.

Each known error maps to an OAuth code. For example, an unknown client gives invalid_client, an expired code gives invalid_grant, and an unknown grant_type gives unsupported_grant_type. An error can also set its own code with an error key in its data. The PKCE errors in #85 already do this, so they will be covered once both PRs merge. Unknown errors become server_error.

Errors now use status 400, as the RFC asks. The exceptions are server_error, which stays 500, and a failed client login, which stays 401. That 401 now sends a WWW-Authenticate: Basic header.

Copilot flagged this on #85. It predates that PR, so the fix is here.

🤖 Generated with Claude Code

RFC 6749 section 5.2 says a token endpoint error is a JSON object with a top-level "error" code such as invalid_grant, plus an optional "error_description". The endpoint returned the WordPress error shape instead ({"code","message","data"}), so a standard OAuth client could not tell why a request failed.

A rest_request_after_callbacks filter on the token route now adds "error" and "error_description" to every error. That filter also sees argument validation errors, such as an unknown grant_type, which happen before the endpoint callback runs. rest_post_dispatch would work in production too, but WP_REST_Server::dispatch() does not run it, so it would be untested.

The WordPress fields are kept alongside the new ones, so existing clients that read "code" keep working. Replacing the body outright would be closer to the RFC but would break them.

Error codes come from a map of the endpoint's known WP_Error codes. An "error" key in the WP_Error data takes precedence, so new errors can set their OAuth code where they are created. The PKCE errors in WP-API#85 already do this. Unknown errors become server_error with a 500 status. Every other error is sent as a 400, except invalid_client, which keeps its 401 when the client failed to authenticate. A 401 now carries a WWW-Authenticate: Basic challenge, as section 5.2 requires. The resource server's Bearer challenge still stays off this route, so the WWW-Authenticate test now checks for the Basic challenge instead of no header.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Dispatched token errors are not formatted, and server_error can retain an incorrect status.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 High severity · 1 Medium severity

Open (2)
What changed in this PR

Updates token endpoint errors with RFC 6749 OAuth fields while preserving WordPress fields, status handling, and authentication challenges.

Changes:

  • Maps token errors to OAuth error codes.
  • Adds RFC-aligned statuses and Basic authentication challenges.
  • Expands token endpoint and header tests.
File Summary
tests/​test-www-authenticate.php Tests Basic authentication challenge behavior.
tests/​test-token-endpoint.php Tests OAuth error responses.
inc/​endpoints/​namespace.php Registers token endpoint hooks.
inc/​endpoints/​class-token.php Formats OAuth errors and statuses; contains unresolved response-hook and server_error status issues.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread inc/endpoints/class-token.php
Comment thread inc/endpoints/class-token.php
An unknown error that carried a 4xx status became server_error but kept its 4xx status, so the response said "server error" with a client-error status. Unknown errors now pick their OAuth code from the status: a 4xx becomes invalid_request with a 400, and anything else becomes server_error. server_error is always sent as a 500, including when an error sets it through its data.

Forcing every unknown error to 500 was the other option, but an error that already says it is the client's fault should not be reported as a server failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

Three moderate findings remain in inc/endpoints/class-token.php.

Review effort: Lite
Findings: None

Resolved since last review (2)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants