# Rfc Compliance

> Verify OAuth protocol implementations stay aligned with relevant RFCs. Use when adding or modifying grant flows, token responses, error formats, redirect behavior, introspection, revocation, PKCE, or metadata endpoints in Doorkeeper.

- Skill: `doorkeeper-gem/rfc-compliance` (Agent Skill)
- Install (CLI): `npx skillmds@latest add doorkeeper-gem/rfc-compliance`
- Raw SKILL.md: https://api.skillmd.com/api/skills/doorkeeper-gem/rfc-compliance/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: doorkeeper-gem (https://skillmd.com/u/doorkeeper-gem)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/doorkeeper-gem/rfc-compliance

---


# RFC Compliance

When implementing or modifying OAuth protocol behavior in Doorkeeper, use this skill to verify the implementation stays aligned with the relevant RFCs.

## Core RFCs

| RFC | Topic | Key Files |
|-----|-------|-----------|
| 6749 | OAuth 2.0 Framework | `lib/doorkeeper/oauth/`, `app/controllers/doorkeeper/` |
| 6750 | Bearer Token Usage | `lib/doorkeeper/oauth/token.rb`, `lib/doorkeeper/rails/helpers.rb` |
| 7009 | Token Revocation | `app/controllers/doorkeeper/tokens_controller.rb` (revoke action) |
| 7636 | PKCE | `lib/doorkeeper/oauth/pre_authorization.rb`, `lib/doorkeeper/oauth/authorization_code_request.rb` |
| 7662 | Token Introspection | `lib/doorkeeper/oauth/token_introspection.rb` |
| 8252 | OAuth for Native Apps | `lib/doorkeeper/oauth/helpers/uri_checker.rb` (loopback) |
| 9207 | Authorization Server Issuer Identification | `lib/doorkeeper/oauth/code_response.rb` (iss param) |
| 8707 | Resource Indicators | `lib/doorkeeper/oauth/resource_indicator_validator.rb` |

## Error Response Format (RFC 6749 §5.2)

Token endpoint errors MUST include:
- `error` — single ASCII error code (required)
- `error_description` — human-readable description (optional)
- HTTP status codes: 400 for most errors, 401 for invalid client auth

Valid error codes for the token endpoint:
`invalid_request`, `invalid_client`, `invalid_grant`, `unauthorized_client`, `unsupported_grant_type`, `invalid_scope`

**Reference:** `lib/doorkeeper/oauth/error_response.rb`

Authorization endpoint errors that are redirectable include `error`, `error_description`, and `state` in the redirect. Non-redirectable errors (invalid redirect_uri, invalid client_id) MUST NOT redirect — render an error page instead.

**Reference:** `lib/doorkeeper/oauth/pre_authorization.rb` — `redirectable?` logic

## Token Response Format (RFC 6749 §5.1)

Successful token responses MUST include:
- `access_token` — the token value
- `token_type` — "Bearer" (case-insensitive per RFC 6750)
- `expires_in` — lifetime in seconds (recommended)

MAY include:
- `refresh_token`
- `scope` — if different from requested

MUST NOT include:
- `refresh_token` in implicit grant responses

**Reference:** `lib/doorkeeper/oauth/token_response.rb`

## Authorization Code Flow (RFC 6749 §4.1)

1. Authorization request → `PreAuthorization` validates, `Code` issues grant
2. Token request → `AuthorizationCodeRequest` validates grant + issues token

Key constraints:
- Code is single-use (§4.1.2) — revoke tokens on replay
- Code must be bound to client_id and redirect_uri
- Code SHOULD expire in max 10 minutes (configurable via `authorization_code_expires_in`)
- redirect_uri in token request must match the one used in authorization request

## PKCE (RFC 7636)

- `code_challenge_method` defaults to "plain" when omitted (§4.2) — but Doorkeeper intentionally requires it when `code_challenge` is present (secure-by-default deviation)
- S256: `BASE64URL(SHA256(code_verifier))` must equal `code_challenge`
- plain: `code_verifier` must equal `code_challenge`
- `code_verifier` is 43-128 characters from `[A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~"`

## Token Introspection (RFC 7662)

- MUST require authentication of the requesting party
- Response for inactive/invalid tokens: `{"active": false}` — no other fields
- Response for active tokens includes: `active`, `scope`, `client_id`, `token_type`, `exp`, `iat`, `sub`, `aud`, `iss`
- Doorkeeper omits `token_type` and `exp` for refresh tokens in introspection responses (these fields are OPTIONAL per §2.2, not prohibited — but they are semantically inapplicable to refresh tokens)

**Reference:** `lib/doorkeeper/oauth/token_introspection.rb`

## Token Revocation (RFC 7009)

- Return 200 OK even for invalid/unknown tokens (§2.1) — prevents token enumeration
- Client authentication is required
- The `token_type_hint` parameter is optional; server must still check both types
- Revoking an access token SHOULD revoke associated refresh token (and vice versa)

**Current known deviation:** Doorkeeper returns 403 when the token belongs to a different client, rather than 200.

## Bearer Token Errors (RFC 6750 §3)

- 401 responses MUST include `WWW-Authenticate: Bearer` header
- Error codes in WWW-Authenticate: `invalid_request`, `invalid_token`, `insufficient_scope`
- 403 for `insufficient_scope`, 401 for `invalid_token`, 400 for `invalid_request`

**Reference:** `lib/doorkeeper/oauth/error_response.rb` — `authenticate_info` method

## Resource Indicators (RFC 8707)

- Resource URIs must be absolute and must not contain a fragment
- Multiple resources use repeated `resource` parameters (Rack limitation: use `resource[]` syntax)
- Tokens are audience-restricted to the declared resources
- Refresh requests enforce subset restriction against original grant

**Reference:** `lib/doorkeeper/oauth/resource_indicator_validator.rb`

## Authorization Server Metadata (RFC 8414)

Served at `/.well-known/oauth-authorization-server`. Must include:
- `issuer` — MUST be identical to the `iss` in authorization responses
- `authorization_endpoint`, `token_endpoint`
- `response_types_supported`, `grant_types_supported`
- `token_endpoint_auth_methods_supported`
- `scopes_supported` (recommended)

**Reference:** `lib/doorkeeper/oauth/metadata_response.rb`

## Implementation Patterns

### Adding a new grant type

1. Create a strategy class in `lib/doorkeeper/request/` extending `Doorkeeper::Request::Strategy`
2. Create a request class in `lib/doorkeeper/oauth/` extending `Doorkeeper::OAuth::BaseRequest`
3. Register with `Doorkeeper::GrantFlow.register` in `lib/doorkeeper/grant_flow.rb`
4. Add to default `grant_flows` if it's a standard flow
5. Add specs in `spec/requests/flows/` and `spec/lib/oauth/`

### Adding a new error code

1. Add to `lib/doorkeeper/errors.rb` as a new class inheriting `BaseResponseError`
2. Add I18n key in `config/locales/en.yml`
3. Map to correct HTTP status in the error class's `#type` method

### Adding a new configuration option

1. Add via `option` DSL in `lib/doorkeeper/config.rb`
2. Add validation in `lib/doorkeeper/config/validations.rb` if needed
3. Document in the initializer template: `lib/generators/doorkeeper/templates/initializer.rb`
4. Add specs in `spec/lib/config_spec.rb`

## Verification

After implementing protocol changes:

1. Run flow specs: `bundle exec rspec spec/requests/flows/`
2. Run endpoint specs: `bundle exec rspec spec/requests/endpoints/`
3. Run OAuth unit specs: `bundle exec rspec spec/lib/oauth/`
4. Verify metadata response: `bundle exec rspec spec/requests/endpoints/metadata_spec.rb`

