Semantic diff: User API key auth becomes a device authorization flow.

Start from the semantically split full diff, not from alphabetic files. Each section explains what changed, why that slice matters, and then shows the Pierre-rendered diff with notes attached to the relevant files.

Feature: device authorization Persistence: expires_at Redis-backed grants ERB → Ember authorization screens Rake smoke client
6
new device routes

Creation, polling, activation, approve, deny, and activation POST.

12
new backend service files

Grant, store, validator, crypto, code registry, user activation, and flow commands.

10m
pending grant TTL

Device requests live briefly in Redis; authorized payloads are retained for at most one minute.

365d
default max requested key expiry

New hidden site setting gates expires_in_seconds.

Behavioral contract

Before

  • Client opens browser or redirect-capable auth flow.
  • Server-rendered ERB pages own new, otp, and show.
  • User API keys have no first-class requested expiry field.
  • No code-entry flow for CLIs/headless clients.

After

  • Headless client calls POST /user-api-key/device.json.
  • User approves in Ember activation UI with code/request-token safeguards.
  • Client polls /device/poll.json and receives encrypted payload once.
  • Keys can carry expires_at, exposed in payload and preferences.

Changed system surfaces

HTTP API6 device endpoints
Auth UIEmber routes/templates
Postgresuser_api_keys.expires_at
Redisgrants, codes, locks
CryptoRSA OAEP/PKCS1 helper
Admin/opsrake device_auth client
Preferencesexpiry displayed
Securityrate limits, no-store, CSRF skip on JSON endpoints