WIP: Add PKCE support to remoteStorage OAuth #256

Draft
raucao wants to merge 1 commits from feature/rs_auth_pkce into master
pull from: feature/rs_auth_pkce
Owner

Implements the optional OAuth 2.0 Authorization Code grant with PKCE (RFC 7636) for remoteStorage, per the remoteStorage spec §10.1. First of three PRs for #254.

What

  • Discovery: WebFinger now advertises rfc6749#section-3.1 (authorization endpoint), rfc6749#section-3.2 (token endpoint) and rfc7636 = S256, and the advertised spec version is bumped to draft-dejong-remotestorage-27. The implicit endpoint (#section-4.2) is kept so non-PKCE clients keep working.
  • Code storage: new rs_authorization_codes table storing only a SHA256 digest of the code, with a 5-minute expiry and single-use consumption.
  • Flow: for response_type=code, the consent dialog redirects back with ?code=… (query), and a new cross-origin POST /rs/oauth/token exchanges the code + code_verifier for a JSON access token after verifying the S256 challenge.
  • Per-device: the existing-token reuse shortcut is removed, so every authorization creates a distinct authorization (and token).

The access token itself is still written to Redis exactly as before; Liquor Cabinet needs no change.

Interop

Verified against the current remoteStorage.js PKCE implementation, which reads exactly these WebFinger properties and sends grant_type=authorization_code with code/client_id/redirect_uri/code_verifier as application/x-www-form-urlencoded, expecting access_token in the JSON response.

Notes

  • PKCE does not refresh access tokens (tracked separately in #255); when a token expires the app re-authorizes via the dialog.
  • CSRF is disabled for the token endpoint (cross-origin, no session). The test environment disables forgery protection, so this needs a manual check in a production-like setup.
  • POST /rs/oauth remains the consent action; GET /rs/oauth/:username remains the dialog.

Tests

bundle exec rspec — 335 examples, 0 failures (model, service, controller, request, feature and WebFinger specs added/updated).

Follow-ups

  • PR 2: per-device token metadata (user_agent).
  • PR 3: storage dashboard card + per-app details modal.
  • #255: refresh tokens.

Part of #254.

Implements the optional OAuth 2.0 Authorization Code grant with PKCE (RFC 7636) for remoteStorage, per the remoteStorage spec §10.1. First of three PRs for #254. ## What - **Discovery:** WebFinger now advertises `rfc6749#section-3.1` (authorization endpoint), `rfc6749#section-3.2` (token endpoint) and `rfc7636` = `S256`, and the advertised spec version is bumped to `draft-dejong-remotestorage-27`. The implicit endpoint (`#section-4.2`) is kept so non-PKCE clients keep working. - **Code storage:** new `rs_authorization_codes` table storing only a SHA256 digest of the code, with a 5-minute expiry and single-use consumption. - **Flow:** for `response_type=code`, the consent dialog redirects back with `?code=…` (query), and a new cross-origin `POST /rs/oauth/token` exchanges the code + `code_verifier` for a JSON access token after verifying the S256 challenge. - **Per-device:** the existing-token reuse shortcut is removed, so every authorization creates a distinct authorization (and token). The access token itself is still written to Redis exactly as before; Liquor Cabinet needs no change. ## Interop Verified against the current `remoteStorage.js` PKCE implementation, which reads exactly these WebFinger properties and sends `grant_type=authorization_code` with `code`/`client_id`/`redirect_uri`/`code_verifier` as `application/x-www-form-urlencoded`, expecting `access_token` in the JSON response. ## Notes - PKCE does not refresh access tokens (tracked separately in #255); when a token expires the app re-authorizes via the dialog. - CSRF is disabled for the token endpoint (cross-origin, no session). The test environment disables forgery protection, so this needs a manual check in a production-like setup. - `POST /rs/oauth` remains the consent action; `GET /rs/oauth/:username` remains the dialog. ## Tests `bundle exec rspec` — 335 examples, 0 failures (model, service, controller, request, feature and WebFinger specs added/updated). ## Follow-ups - PR 2: per-device token metadata (`user_agent`). - PR 3: storage dashboard card + per-app details modal. - #255: refresh tokens. Part of #254.
raucao added the security
integration
remotestorage
labels 2026-11-02 09:00:17 +00:00
raucao added 1 commit 2026-11-02 12:41:26 +00:00
Add PKCE support to remoteStorage OAuth
CI / Test (pull_request) Successful in 41s
8fc7ffdd1d
Implements the optional OAuth 2.0 Authorization Code grant with PKCE
(RFC 7636) for remoteStorage, as described in the remoteStorage spec
(section 10.1).

- Advertise the authorization and token endpoints plus the supported
  code_challenge method (S256) in WebFinger, and bump the advertised
  spec version to draft-dejong-remotestorage-27
- Add RsAuthorizationCode: a short-lived (5 min), single-use authorization
  code stored only as a SHA256 digest
- Add RsOauthManager services for issuing and exchanging codes, including
  S256 verification
- Add a cross-origin POST /rs/oauth/token endpoint that exchanges a code
  (and code_verifier) for an access token, with CORS and no CSRF token
- Consent dialog now carries response_type / code_challenge through the
  form and redirects with the code in the query string for the code flow
- Remove the existing-token reuse shortcut so every authorization results
  in a distinct authorization (and token)

Part of #254
raucao force-pushed feature/rs_auth_pkce from 0ab0412bb3 to 8fc7ffdd1d 2026-11-02 12:41:26 +00:00 Compare
raucao added the feature label 2026-11-02 13:26:23 +00:00
raucao marked the pull request as work in progress 2026-11-02 19:00:03 +00:00
All checks were successful
CI / Test (pull_request) Successful in 41s
Required
Details
The branch requires signed commits but this merge will not be signed
You are not authorized to merge this pull request.
This pull request is marked as a work in progress.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feature/rs_auth_pkce:feature/rs_auth_pkce
git checkout feature/rs_auth_pkce
Sign in to join this conversation.