add_auth 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/README.md +57 -18
  4. data/ROADMAP.md +260 -242
  5. data/SECURITY.md +6 -0
  6. data/app/controllers/add_auth/accounts_controller.rb +138 -0
  7. data/app/controllers/add_auth/assets_controller.rb +2 -1
  8. data/app/controllers/add_auth/external_identities_controller.rb +56 -0
  9. data/app/controllers/add_auth/mobile_sessions_controller.rb +120 -0
  10. data/app/controllers/add_auth/provider_sign_ins_controller.rb +248 -0
  11. data/app/helpers/add_auth/sign_ins_helper.rb +2 -1
  12. data/app/jobs/add_auth/account_delivery_job.rb +14 -0
  13. data/app/jobs/add_auth/account_request_job.rb +17 -0
  14. data/app/mailers/add_auth/account_mailer.rb +12 -0
  15. data/app/views/add_auth/account_mailer/link.text.erb +7 -0
  16. data/app/views/add_auth/accounts/_check_email.html.erb +5 -0
  17. data/app/views/add_auth/accounts/_delete.html.erb +6 -0
  18. data/app/views/add_auth/accounts/_email.html.erb +12 -0
  19. data/app/views/add_auth/accounts/_invalid_proof.html.erb +5 -0
  20. data/app/views/add_auth/accounts/_password.html.erb +12 -0
  21. data/app/views/add_auth/accounts/_proof.html.erb +16 -0
  22. data/app/views/add_auth/accounts/_register.html.erb +17 -0
  23. data/app/views/add_auth/accounts/_request.html.erb +14 -0
  24. data/app/views/add_auth/accounts/_unavailable.html.erb +3 -0
  25. data/app/views/add_auth/external_identities/_index.html.erb +22 -0
  26. data/app/views/add_auth/external_identities/_unavailable.html.erb +3 -0
  27. data/app/views/add_auth/passkeys/_controls.html.erb +3 -1
  28. data/app/views/add_auth/provider_sign_ins/_enrollment.html.erb +12 -0
  29. data/app/views/add_auth/provider_sign_ins/_failure.html.erb +3 -0
  30. data/app/views/add_auth/provider_sign_ins/_prepare.html.erb +7 -0
  31. data/app/views/add_auth/reauthentications/_form.html.erb +9 -0
  32. data/app/views/add_auth/sessions/_list.html.erb +1 -1
  33. data/app/views/add_auth/sessions/index.html.erb +7 -0
  34. data/app/views/add_auth/sign_ins/_confirmation.html.erb +1 -0
  35. data/app/views/add_auth/sign_ins/_form.html.erb +17 -0
  36. data/app/views/add_auth/sign_ins/_remember.html.erb +6 -0
  37. data/app/views/layouts/add_auth/authentication.html.erb +4 -3
  38. data/exe/add_auth-preflight +26 -0
  39. data/lib/add_auth/configuration.rb +78 -4
  40. data/lib/add_auth/core/access_policy.rb +11 -1
  41. data/lib/add_auth/core/account_lifecycle.rb +251 -0
  42. data/lib/add_auth/core/account_policy.rb +50 -0
  43. data/lib/add_auth/core/external_identities/evidence.rb +98 -0
  44. data/lib/add_auth/core/external_identities.rb +278 -0
  45. data/lib/add_auth/core/intake.rb +6 -1
  46. data/lib/add_auth/core/maintenance.rb +5 -3
  47. data/lib/add_auth/core/migration/account_adoption.rb +79 -0
  48. data/lib/add_auth/core/migration/readiness.rb +41 -0
  49. data/lib/add_auth/core/mobile_authentication.rb +35 -0
  50. data/lib/add_auth/core/mobile_handoffs.rb +83 -0
  51. data/lib/add_auth/core/mobile_profile.rb +46 -0
  52. data/lib/add_auth/core/mobile_response.rb +12 -0
  53. data/lib/add_auth/core/native_authentication.rb +77 -0
  54. data/lib/add_auth/core/passwords/bcrypt_support.rb +28 -0
  55. data/lib/add_auth/core/passwords/credential.rb +49 -0
  56. data/lib/add_auth/core/passwords/legacy_bcrypt.rb +43 -0
  57. data/lib/add_auth/core/passwords/lifecycle.rb +60 -0
  58. data/lib/add_auth/core/remaining_factors.rb +24 -0
  59. data/lib/add_auth/core/sessions.rb +102 -17
  60. data/lib/add_auth/core/step_up.rb +13 -1
  61. data/lib/add_auth/migration/static_inventory.rb +116 -0
  62. data/lib/add_auth/rails/account_password_entry.rb +24 -0
  63. data/lib/add_auth/rails/authentication.rb +1 -1
  64. data/lib/add_auth/rails/authentication_pages.rb +5 -0
  65. data/lib/add_auth/rails/doctor.rb +73 -3
  66. data/lib/add_auth/rails/ejection.rb +1 -1
  67. data/lib/add_auth/rails/engine.rb +6 -1
  68. data/lib/add_auth/rails/migration/account_store.rb +41 -0
  69. data/lib/add_auth/rails/migration/effective_inventory.rb +162 -0
  70. data/lib/add_auth/rails/migration/key_type.rb +23 -0
  71. data/lib/add_auth/rails/migration/source_bridge.rb +53 -0
  72. data/lib/add_auth/rails/password_adoption.rb +37 -0
  73. data/lib/add_auth/rails/provider_enrollment.rb +61 -0
  74. data/lib/add_auth/rails/provider_libraries/apple_form_post_correlation.rb +127 -0
  75. data/lib/add_auth/rails/provider_libraries/apple_jwks.rb +68 -0
  76. data/lib/add_auth/rails/provider_libraries/apple_native.rb +55 -0
  77. data/lib/add_auth/rails/provider_libraries/callback_route.rb +16 -0
  78. data/lib/add_auth/rails/provider_libraries/omniauth.rb +136 -0
  79. data/lib/add_auth/rails/provider_libraries/omniauth_correlation.rb +107 -0
  80. data/lib/add_auth/rails/provider_libraries/openid_connect.rb +62 -0
  81. data/lib/add_auth/rails/provider_libraries/request_protection.rb +43 -0
  82. data/lib/add_auth/rails/rate_limit_cache.rb +17 -0
  83. data/lib/add_auth/rails/runtime.rb +173 -9
  84. data/lib/add_auth/rails/stores/account_credentials.rb +44 -0
  85. data/lib/add_auth/rails/stores/account_lock.rb +16 -7
  86. data/lib/add_auth/rails/stores/account_tokens.rb +96 -0
  87. data/lib/add_auth/rails/stores/authority.rb +28 -0
  88. data/lib/add_auth/rails/stores/commit_dispatch.rb +32 -0
  89. data/lib/add_auth/rails/stores/external_identities.rb +91 -0
  90. data/lib/add_auth/rails/stores/maintenance.rb +1 -1
  91. data/lib/add_auth/rails/stores/mobile_handoffs.rb +53 -0
  92. data/lib/add_auth/rails/stores/security_events.rb +3 -6
  93. data/lib/add_auth/rails/user_lifecycle.rb +8 -10
  94. data/lib/add_auth/result.rb +1 -0
  95. data/lib/add_auth/version.rb +1 -1
  96. data/lib/add_auth.rb +4 -0
  97. data/lib/generators/add_auth/accounts/accounts_generator.rb +52 -0
  98. data/lib/generators/add_auth/accounts/templates/add_add_auth_accounts.rb.tt +49 -0
  99. data/lib/generators/add_auth/accounts/templates/add_auth_account_token.rb +6 -0
  100. data/lib/generators/add_auth/accounts/templates/add_auth_address_claim.rb +6 -0
  101. data/lib/generators/add_auth/devise_accounts/devise_accounts_generator.rb +23 -0
  102. data/lib/generators/add_auth/devise_accounts/templates/prepare_add_auth_devise_accounts.rb.tt +17 -0
  103. data/lib/generators/add_auth/email_link/templates/add_auth_challenge.js +1 -0
  104. data/lib/generators/add_auth/email_tokens/templates/create_add_auth_sign_in_tokens.rb.tt +3 -1
  105. data/lib/generators/add_auth/external_identities/external_identities_generator.rb +52 -0
  106. data/lib/generators/add_auth/external_identities/templates/add_add_auth_external_enrollment.rb.tt +5 -0
  107. data/lib/generators/add_auth/external_identities/templates/add_add_auth_external_identity_validity.rb.tt +5 -0
  108. data/lib/generators/add_auth/external_identities/templates/add_auth_external_identity.rb +4 -0
  109. data/lib/generators/add_auth/external_identities/templates/add_auth_external_transaction.rb +6 -0
  110. data/lib/generators/add_auth/external_identities/templates/create_add_auth_external_identities.rb.tt +50 -0
  111. data/lib/generators/add_auth/external_identities/templates/providers.rb +51 -0
  112. data/lib/generators/add_auth/install/templates/initializer.rb +7 -1
  113. data/lib/generators/add_auth/javascript/templates/passkey.js +8 -5
  114. data/lib/generators/add_auth/mobile_sessions/mobile_sessions_generator.rb +48 -0
  115. data/lib/generators/add_auth/mobile_sessions/templates/add_add_auth_mobile_sessions.rb.tt +9 -0
  116. data/lib/generators/add_auth/mobile_sessions/templates/add_auth_mobile_handoff.rb +5 -0
  117. data/lib/generators/add_auth/mobile_sessions/templates/create_add_auth_mobile_handoffs.rb.tt +27 -0
  118. data/lib/generators/add_auth/mobile_sessions/templates/mobile.rb +8 -0
  119. data/lib/generators/add_auth/notifications/templates/create_add_auth_security_events.rb.tt +3 -1
  120. data/lib/generators/add_auth/passkeys/templates/add_add_auth_passkeys.rb.tt +7 -3
  121. data/lib/generators/add_auth/step_up/templates/add_add_auth_reauthentication.rb.tt +3 -1
  122. data/lib/tasks/add_auth.rake +18 -1
  123. metadata +86 -2
data/ROADMAP.md CHANGED
@@ -1,244 +1,262 @@
1
1
  # Roadmap
2
2
 
3
- AddAuth extends Rails 8's `bin/rails generate authentication` with email-link
4
- sign-in, passkeys, purpose-bound reauthentication, session hardening and pluggable
5
- captcha. It reuses the host's accounts and Session model.
6
-
7
- The canonical design lives in the companion **private** planning workspace:
8
- [scope](https://github.com/taimoorq/add_auth-workspace/blob/main/docs/authentication-gem-plan.md#14-scope-decision-and-roadmap)
9
- and [user journeys, contracts and test plan](https://github.com/taimoorq/add_auth-workspace/blob/main/docs/authentication-gem-plan.md#16-integrated-user-journeys-and-implementation-plan).
10
- Those links require workspace access. This public checklist stands on its own as
11
- progress tracking; it does not duplicate the private design. Engineering guidance
12
- stays only in that workspace's `AGENTS.md`.
13
-
14
- Reviewed 2026-09-07. The 0.2.1 source implements the v1
15
- strategy features: password/email/passkey sign-in, hardened sessions, reauthentication,
16
- credential management, default recovery and strict policy, security notifications,
17
- challenge adapters and fingerprinted ejection. Core policy, session finalization
18
- and leased mail delivery are shared by engine and ejected flows.
19
-
20
- The 0.2 release gate uses local real-database, generated-host, browser and
21
- SMTP/queue/cache acceptance. The final supported matrix is recorded in the
22
- [canonical evidence ledger](https://github.com/taimoorq/add_auth-workspace/blob/main/docs/authentication-gem-plan.md#20-release-020-execution--2026-09-07).
23
- Checked feature items mean passing relevant local specs. GitHub's required
24
- merge/release controls still apply. Hosts verify their own live providers,
25
- physical authenticators and deployment operations; those checks do not block
26
- the gem's 0.2 release. Email themes and branding are optional host presentation.
27
-
28
- Generated pages use shared HTML/Turbo partials. Password/email paths support
29
- ordinary no-JS navigation when permitted by policy; passkeys require browser
30
- JavaScript, and a configured captcha may also require it. Strict policy must never
31
- be weakened to simulate no-JS parity.
32
-
33
- ## 0. Project foundations
34
-
35
- - [x] Gemspec with a capability-derived Rails floor (`>= 8.0`, the release
36
- that shipped the authentication generator) and a security-patch-derived
37
- Ruby floor (`>= 3.3.0`), not just whatever the newest Rails tolerates.
38
- - [x] MIT license, Code of Conduct, Security policy (`SECURITY.md`).
39
- - [x] RSpec test setup (`.rspec`, `spec/spec_helper.rb`).
40
- - [x] `standard` for formatting/linting.
41
- - [x] CI (GitHub Actions): RSpec + Standard across the Ruby support matrix,
42
- plus a `bundler-audit` job.
43
- - [x] Dependabot, grouped by ecosystem, with the Rails family grouped
44
- together — the concrete mechanism behind the "stay current" mandate in
45
- the workspace's `AGENTS.md`.
46
- - [x] RubyGems release workflow configured for [Trusted
47
- Publishing](https://guides.rubygems.org/trusted-publishing/) (OIDC from
48
- GitHub Actions) instead of a long-lived API key, gated behind
49
- `rubygems_mfa_required` and `allowed_push_host`.
50
- - [x] `bin/setup` / `bin/console` dev scripts.
51
- - [ ] First successful tagged release published via the Trusted Publishing
52
- workflow, to lock in the gem name on RubyGems.
53
-
54
- ## 1. Core primitives
55
-
56
- - [x] `AddAuth::Result` — closed success/failure type for auth outcomes.
57
- - [x] `AddAuth::Configuration` / `AddAuth.configure`.
58
- - [x] Challenge adapter contract (`AddAuth::Core::Challenge::Base`) with the
59
- three-state result (success / rejected / unavailable).
60
- - [x] `Challenge::Null` (default, always succeeds) and `Challenge::Test`
61
- (configurable, for specs) adapters.
62
- - [x] Purpose-separated HMAC digests with explicit strong key material,
63
- real Rails key derivation, override tests and a framework-free Core check.
64
-
65
- ## 2. Shared contracts and a real host harness — slices A1/A2
66
-
67
- - [x] One Core policy for eligibility, purpose, proof strength and freshness;
68
- one session finalizer and public result presenter across all methods.
69
- - [x] Ordinary email-token store and encrypted delivery-intent contracts,
70
- shared examples against fake and real SQLite/PostgreSQL adapters, with clock/digest
71
- injection, replay/race/rollback/address-binding coverage.
72
- - [x] Passkey/recovery proof and host lifecycle contracts, with actual WebAuthn
73
- cryptography, rollback and concurrency on SQLite and PostgreSQL.
74
- - [x] Boot `spec/dummy` through RSpec; replace generated test stubs with
75
- password sign-in/reset/sign-out requests and real database coverage.
76
- - [x] Generate and boot Rails 8.0/8.1 hosts; exercise the persistence
77
- generator and preserve host customizations. CI covers both Rails lines
78
- on Ruby 3.3, 3.4 and 4.0. Commands are in CONTRIBUTING.md.
79
- - [x] Browser/virtual-authenticator harness with the passkey slice.
80
-
81
- ## 3. Adopt the host's sessions and password flow — slice B, U1/U8
82
-
83
- - [x] Inert `add_auth:install` configuration plus additive `session_upgrade`
84
- migration and shared lifecycle hooks; repeat generation preserves edits.
85
- - [x] Bounded signed-ID cookie transition to random digested bearers, with
86
- real signature/tamper, race, cutoff and revocation tests.
87
- - [x] Password/reset normalization and routes preserved; password/address
88
- invalidation and account deletion integrated. Hosts supply eligibility.
89
- - [x] Absolute/idle expiry, protected cookies, fresh session IDs and safe local
90
- return destinations for implemented password/email flows.
91
- - [x] Current-session sign-out revokes its bearer and clears browser state.
92
- - [x] Session list and revoke-one, including next-request rejection in another
93
- browser and cache/back-safe authenticated-page handling.
94
- - [x] Sign-out-everywhere, guarded by fresh allowed proof and covering every
95
- active browser, with old bearers rejected on their next request.
96
- - [x] Account-scoped cursor pages and bounded maintenance, with optional history
97
- retention, active-lease protection and completed-pass counts.
98
- - [x] Explicit passwordless mode, guarded stock entry routes and authenticated
99
- account-management pages in hosts that also serve public pages.
100
-
101
- ## 4. Complete email-link sign-in — slice C, U2
102
-
103
- - [x] Internal `EmailLink#issue`/`#consume` lifecycle: atomic replacement and
104
- session persistence, one-use proof, account/address eligibility rechecks,
105
- expiring encrypted delivery handoff and tested concurrent use.
106
- - [x] Wire the lifecycle to the hardened session finalizer and uniform
107
- asynchronous/rate-limited public intake.
108
- - [x] Additive token model/store generator and protected pending-delivery
109
- payload, cleared on consumption/revocation; no Session schema changes.
110
- - [x] Encrypted request jobs, idempotent issuance, leased mail delivery,
111
- retry/cleanup sweep and delivered-link-to-browser integration.
112
- - [x] Durable security notifications share the delivery lease/retry/cancellation
113
- contract and recover interrupted queue handoffs.
114
- - [x] Local SMTP, durable queue restart/retry and cross-process shared-cache
115
- acceptance. Live transport and monitoring validation belongs to each host.
116
- - [x] Shared IP + keyed identifier rate policy, normalization and generic
117
- request/resend responses for unknown, disabled and throttled accounts.
118
- - [x] Request → check-email → inert GET confirmation → explicit POST consume
119
- → session; masked account confirmation and deliberate account switching.
120
- - [x] Resend limits, newest-link guidance, expired/used-link recovery and
121
- cross-device sign-in by default.
122
- - [x] Optional same-browser binding, including delivered links, wrong-browser denial,
123
- Turbo/no-JS browsers and generated/ejected hosts.
124
- - [x] Real DB concurrency and delivered-mail-to-session specs, plus HTML,
125
- Turbo and no-JS request/system coverage for the complete flow.
126
-
127
- - [x] Basic scoped CSS, semantic class overrides for host Bootstrap/Tailwind
128
- builds, stylesheet opt-out and view ejection with custom-file preservation.
129
-
130
- ## 5. Reauthentication and recovery policy — slice D, U6/U7
131
-
132
- - [x] Core purpose/freshness evaluator with account/session binding, generic
133
- elevation failures and passkey UV requirements.
134
- - [x] Additive session elevation metadata and bearer-rotation finalizer for a
135
- previously authorized grant, now wired to public reauthentication routes.
136
- - [x] Host reauthentication adapters persist purpose-bound grants and rotate the
137
- existing session's bearer after password/email/passkey verification.
138
- - [x] Password/email reauthentication adapters share policy and presentation;
139
- email step-up is bound to the initiating browser/session/purpose.
140
- - [x] Sensitive-action return goes to a safe confirmation page; final mutation
141
- rechecks authorization/grant/target and never automatically replays a POST.
142
- - [x] Default email recovery with explicit recovery purpose, replacement grant,
143
- security notifications and post-recovery session/proof invalidation.
144
- - [x] Stricter opt-in policy enforced across sign-in, fallback, credential
145
- management, password reset and policy changes; no hidden weaker route.
146
- - [x] Tests for fresh-but-insufficient proof, wrong account/session/purpose,
147
- expiry, lost response, cancellation and attempted policy bypass.
148
-
149
- ## 6. Complete passkeys and credential management — slice E, U3–U7
150
-
151
- - [x] Registration with discoverable credentials, server-enforced user
152
- verification and transaction binding to an existing account.
153
- - [x] Discoverable sign-in with credential/userHandle ownership checks;
154
- explicit and conditional-autofill UI share the same verification path.
155
- - [x] Native browser support for another device/security key, neutral cancel,
156
- understandable retry/fallback and strict-policy unavailable states.
157
- - [x] First-passkey bootstrap and additional-passkey enrollment require
158
- appropriate fresh proof. The optional post-login invitation is a host product
159
- choice; v1 supplies the authenticated `/passkeys` entry point.
160
- - [x] Credential list, rename, remove, notifications and atomic last-usable-method
161
- checks; default/strict recovery works with enrollment and lost-device flows.
162
- - [x] Correct sign-counter anomaly/backup-flag handling, with atomic counter
163
- updates and tests for zero, equal, increasing and decreasing counters.
164
- - [x] Exact origin/RP policy, single-use server transactions, one shared codec,
165
- payload bounds and cleanup of pending browser ceremonies.
166
- - [x] Virtual-authenticator and real-store coverage of success, UV/signature/
167
- origin/ownership failures, replay, races, management and recovery.
168
-
169
- ## 7. Challenge adapters and accessible failure paths — slice F, U9
170
-
171
- - [x] Turnstile adapter with hostname/action checks, provider-owned lifetime,
172
- bounded HTTPS timeouts and safe no-retry handling for single-use tokens.
173
- - [x] reCAPTCHA v2/v3 adapters respecting their different verification fields
174
- and configured score/action requirements where applicable.
175
- - [x] Shared success/rejected/unavailable behavior, fail-closed default and
176
- observable explicit fail-open policy; no implicit bypass without JS.
177
- - [x] Retry/outage messages, preserved input, provider protocol fixtures and no
178
- live-provider dependency in routine specs.
179
- - [x] Local keyboard/focus/status, virtual-authenticator and provider-contract
180
- browser coverage in bundled and ejected UI. Broader browser/device and
181
- assistive-technology verification remains a host deployment responsibility.
182
-
183
- ## 8. Generators, ejection and integrated acceptance — slice G
184
-
185
- - [x] `add_auth:install` writes inert configuration; session/email feature
186
- generators add reviewable wiring and preserve edits on repeat runs.
187
- - [x] `add_auth:views`, `add_auth:controllers`, `add_auth:javascript` and
188
- `add_auth:mailer_views` reuse the same Core policy, presenter and templates.
189
- - [x] `add_auth:challenge` writes environment-keyed Turnstile/reCAPTCHA config,
190
- adds the fixed challenge route and preserves an existing initializer.
191
- - [x] `add_auth:doctor` checks deployment origins, cookies/session metadata,
192
- delivery, migrations and challenge policy/routes.
193
- - [x] `add_auth:doctor` checks recovery policy and generated-file drift.
194
- - [x] Every generated flow exercised before and after ejection, with Turbo
195
- Drive/Frames/Streams, ordinary HTML, no-JS alternatives and strict denial.
196
- - [x] Auth-page cache/referrer protections, redacted app/job telemetry,
197
- CSRF, safe redirects and correct success/failure HTTP contracts.
198
- - [x] RSpec strategy/store shared examples and host-facing test helpers,
199
- including virtual authenticator lifecycle and delivered-link extraction.
200
- - [x] Full RSpec, Standard and dependency audit pass on supported local matrices;
201
- README/roadmap distinguish working development APIs from release gates.
202
- - [ ] Exact-commit remote CI/CodeQL and required repository security checks;
203
- refresh deployed public documentation when the gem is released.
204
-
205
- ## 9. Release readiness
206
-
207
- - [x] README rewritten from skeleton status to verified usage and migration
208
- instructions, linking to maintained public API docs as they ship.
209
- - [x] Security policy updated for shipped strategies, recovery limits and
210
- supported versions; redacted events and incident/rollback guidance documented.
211
- - [ ] CHANGELOG entries and successful Trusted Publishing release; a tag or
212
- configured workflow alone does not prove the gem was published.
213
- - [x] Local enabled-journey, delivery-retry/restart, expiry and transaction rollback
214
- evidence. Record 0.2 operational defaults and host deployment responsibilities.
215
- - [x] Audit adopter-requested changes against stock Rails behavior; keep app roles,
216
- invitations, authorization and email themes in the host.
217
- - [ ] `v1.0.0` only after the integrated acceptance gates pass.
218
-
219
- ## v2 — reassess after v1 usage
220
-
221
- - [ ] AddAuth-owned password registration/reset, confirmation, lockout and
222
- password policy. Existing host password integration is part of v1.
223
- - [ ] Password-hashing adapter seam, following the canonical cryptography
224
- policy and Rails support available at implementation time.
225
- - [ ] Recovery codes; they are not an implied fallback for v1 strict policy.
226
- - [ ] Multiple realms/routing scopes.
227
-
228
- ## Decisions before they become dependencies
229
-
230
- Owner and deadline details remain in the canonical plan's section 16.
231
-
232
- - [x] Review the 0.2 configuration and public integration contract. The runtime
233
- uses Rails-generator User/Session conventions; authentication models must
234
- share one database connection pool and cross-pool writes are rejected.
235
- - [x] Review lifetime/resend/legacy-bridge defaults and local failure evidence;
236
- retention is opt-in, and key changes require a host deployment plan.
237
- - [x] Framework-neutral mail and virtual-authenticator helpers; no
238
- Minitest-specific integration DSL. AddAuth's own suite stays RSpec.
239
- - [ ] Revisit API/token authentication after v1; outside current scope.
240
-
241
- ## Potential standalone libraries
242
-
243
- - [ ] Virtual-authenticator test helpers.
244
- - [ ] Challenge adapter contract and its three-state result.
3
+ AddAuth extends Rails 8's authentication generator with email-link sign-in,
4
+ passkeys, purpose-bound reauthentication, hardened sessions and pluggable captcha.
5
+ It reuses the host's accounts and Session model.
6
+
7
+ **Reviewed 2026-09-09: 0.2.2 is published, and the planned v1 strategy features
8
+ have shipped.** The bounded Devise migration and native additions below are locally verified
9
+ and selected for 0.3.0. The future 1.0 support commitment remains separate. Milestones below describe priorities, not promised dates or
10
+ versions. See [release status](https://addauthgem.com/release-status/),
11
+ [the changelog](CHANGELOG.md) and [the manual](https://addauthgem.com/).
12
+
13
+ **[0.2.2 is published and verified](https://github.com/taimoorq/add_auth/releases/tag/v0.2.2).**
14
+ It contains the counter-store correction and upgrade/operations coverage below.
15
+ The registry package passes fresh-host installation and the matching manual is
16
+ live. The owner selected this patch before accepting the proposed 1.0 commitment.
17
+
18
+ An unchecked item is remaining work; deferred candidates need a scope decision
19
+ before implementation. Checked features have passing relevant acceptance specs.
20
+ Other completed work requires its applicable verification evidence. Checkmarks
21
+ can describe tested local work; release/publication remains a separate gate. Detailed
22
+ design and decision records remain in the companion private planning workspace;
23
+ this public checklist is derived from its section 14 and stands on its own.
24
+
25
+ ## Now — maintain 0.2 and learn from adoption
26
+
27
+ - [x] **R1 · Resolve the outstanding dependency update.**
28
+ [PR #9](https://github.com/taimoorq/add_auth/pull/9) updates the immutable
29
+ checkout pin to 7.0.1 with current required checks passing. Old Dependabot
30
+ PR #1 is closed as superseded. All merge/release protections remain in force.
31
+ - [x] **R1 · Complete the 2026-09-07 currency review.** Review Rails/Ruby support,
32
+ authentication APIs, WebAuthn, advisories and the competitive landscape
33
+ before the next version bump; repeat the standing review at least quarterly.
34
+ Floors remain Ruby 3.3 / Rails 8.0; current audits are clear. Follow Rails-
35
+ native password hashing when the supported API permits it. Future reviews
36
+ remain an ongoing maintenance responsibility.
37
+ - [x] **R2 · Complete a bounded first-adopter feedback review.** Official-package
38
+ local integration already passes. Collect installation, sign-in/recovery,
39
+ customization and operational friction; give each finding a gem fix,
40
+ documentation improvement, host-owned resolution or explicit deferral.
41
+ The review dispositions existing passwordless/management fixes, host-owned
42
+ onboarding/roles/mail branding and the new upgrade/operations guidance.
43
+ Stock and synthetic host regressions remain required for reusable changes.
44
+ - [x] **R2 · Improve onboarding from observed friction.** Update existing
45
+ quickstart, doctor and troubleshooting guidance with exact prerequisites,
46
+ observable success and recovery steps. Keep the public manual tied to the
47
+ published package. Upgrade, compatibility, cache and ejection guidance is
48
+ published for 0.2.2; build, browser and live deployment checks pass.
49
+
50
+ The exact 0.2.2 release commit passed the full CI matrix and CodeQL. The post-publication
51
+ passwordless-fixture isolation failure is fixed in
52
+ [PR #8](https://github.com/taimoorq/add_auth/pull/8); it is not an open runtime
53
+ defect or a reason by itself to republish 0.2.1.
54
+
55
+ ## Next — prove upgrades, plan migrations and define the 1.0 contract
56
+
57
+ - [x] **R3 · Rehearse an upgrade from published 0.2.1.** Start with a populated
58
+ host, active sessions, passkeys, strict accounts, pending mail and customized
59
+ ejected files. Upgrade to the candidate and verify data/policy preservation,
60
+ migration repeatability, doctor diffs, reviewed baseline acceptance,
61
+ worker compatibility and safe rollback or explicit revocation. Keep
62
+ fresh-install and before/after-ejection coverage. The checksum-pinned
63
+ baseline/candidate/rollback test passes on all six Ruby/Rails combinations;
64
+ CI now includes the same rehearsal.
65
+ - [x] **R4 · Validate the Rails-default operations path.** Exercise Solid Queue
66
+ restart/enqueue failure and same-intent mail retry locally. Determine
67
+ whether Solid Cache meets atomic rate-limit increment/TTL requirements;
68
+ document a tested separate store if needed. Publish only verified adapter
69
+ support. Solid Queue 1.7.0 passes with a separate queue database. Solid
70
+ Cache 1.0.10 loses concurrent first increments on PostgreSQL; 0.2.2
71
+ rejects it for abuse counters and documents a separate Redis store.
72
+ - [x] **R4 · Measure bounded maintenance and recovery.** Record workload,
73
+ query counts, backlog drain and latency for session pages, outbox retries
74
+ and cleanup. Use those measurements to explain batch sizing, retention,
75
+ alerts and recovery procedures. SQLite/PostgreSQL rehearsals retain 5,000
76
+ live sessions while draining 1,200 expired rows in twelve batches of 100;
77
+ session listing uses two SELECTs and at most 52 loaded Session records.
78
+ - [x] **R5 · Inventory the proposed stable public surface.** Name supported configuration,
79
+ Core/host hooks and Results, routes, generators/ejection metadata, testing
80
+ helpers and redacted events. Distinguish internal APIs and document
81
+ compatibility, deprecation and migration rules. The current integration
82
+ reference is published; the proposed 1.0 contract remains for owner
83
+ review under the separate item below.
84
+ - [ ] **R5 · Set the 1.0 support policy.** Specify supported runtime/database
85
+ combinations and security-supported release lines. Publish an upgrade
86
+ guide and evidence-backed troubleshooting updates before the candidate
87
+ freezes. The current latest-0.x policy remains in
88
+ [SECURITY.md](SECURITY.md).
89
+ - [x] **R8 · Define Devise migration readiness.** Inventory source versions,
90
+ modules, extensions and customizations; provide a read-only preflight with
91
+ supported mappings, prerequisites and actionable blockers. Running Rails 8
92
+ alone does not establish the authentication contracts AddAuth needs.
93
+ - [x] **R8 · Provide a path for Rails-aligned Devise apps.** Reuse verified
94
+ account/session contracts and preserve host customizations while replacing
95
+ remaining Devise authentication wiring. Prove password compatibility,
96
+ account restrictions, session/token revocation and safe cutover/rollback.
97
+ - [x] **R8 · Provide a path for standard or customized Devise apps.** Guide an
98
+ additive conversion from existing models, identifiers, password storage
99
+ and controllers to the supported Rails contracts. Preserve account IDs and
100
+ associations; resolve incompatible hashes, identifier collisions and
101
+ unsupported module policies before cutover. Include older-runtime
102
+ prerequisites and host-owned lifecycle replacements where needed.
103
+ - [x] **R8 · Add optional account lifecycle support.** Registration,
104
+ confirmation/reconfirmation, password reset, lock/unlock and account
105
+ changes must preserve ownership, account policy and session revocation.
106
+ - [x] **R8 · Preserve provider sign-in through maintained libraries.** Add
107
+ optional OmniAuth integration with verified identity binding, explicit
108
+ linking/unlinking and usable recovery for provider-only accounts.
109
+ Preserve host-owned OAuth configuration, routes and other provider flows;
110
+ delegate protocol work to the selected libraries.
111
+ - [x] **R8 · Rehearse both migration paths and draft the guides.** Test populated Devise
112
+ hosts before and after migration, including custom schema, peppered
113
+ passwords, denied accounts, interrupted conversion and rollback. Verify
114
+ supported database/runtime, ordinary HTML with JavaScript and Turbo absent,
115
+ Turbo enhancement and permitted no-JS journeys. Draft step-by-step guides
116
+ and prove the destination works with Devise removed.
117
+ - [ ] **R8 · Publish migration and native guides with the feature release.**
118
+ Verify the released package, installation commands, HTTPS and deep links;
119
+ keep development guides explicitly unpublished until then.
120
+
121
+ Local development has verified preflight, optional account lifecycle and
122
+ provider-library integration across the supported Ruby/Rails matrix, including
123
+ ordinary HTML, Turbo and permitted no-JS journeys. These additions are
124
+ unpublished. Migration/checkpoint/compatible-rollback tests and native client
125
+ acceptance are complete locally. The full adopter suite passes 1,330 examples
126
+ with zero failures and three existing empty scaffold examples pending. Six
127
+ development guides pass build, browser, keyboard and no-JS checks. Publication
128
+ and the proposed 1.0 commitment remain separate gates.
129
+
130
+ ## Locally verified — Android and iOS login
131
+
132
+ Mobile support is now part of the active migration implementation. It is not available in the published gem. These capabilities extend the
133
+ same account and session policies. The verified finite profile uses explicit
134
+ 30-day absolute and 14-day idle limits, with fresh sign-in after expiry. Renewable
135
+ refresh-token families remain a distinct optional capability, currently disabled.
136
+ The owner selected 0.3.0; publication and package verification remain pending.
137
+
138
+ - [x] **R8 · Password and provider login for native clients.** Return credentials
139
+ over authenticated HTTPS responses; preserve supported client contracts.
140
+ - [x] **R8 · Secure browser-to-app sign-in handoffs.** Short-lived, single-use
141
+ codes bound to state and a verifier, exact callback validation, and native
142
+ Apple nonce verification; no reusable bearer tokens in callback URLs.
143
+ - [x] **R8 · Device sessions and revocation.** Expiring, digested API credentials,
144
+ cookie/bearer separation, device listing, current-device and all-device
145
+ logout, and invalidation on password/account changes. Evaluate optional
146
+ renewal with rotation and replay detection as a distinct profile.
147
+ - [x] **R8 · Android/iOS migration acceptance.** Test secure client storage,
148
+ cancellation/restarts, account switching, expiry and concurrent handoffs,
149
+ plus supported old/new client combinations. Android/iOS consumers also
150
+ pass against an installed gem in an isolated Rails adopter over local HTTPS.
151
+
152
+ Each change owns its tests and keeps intermediate releases usable. R3/R4 findings
153
+ feed R5. A patch may address compatible corrections; another 0.x minor is possible
154
+ if integration contracts change. A 0.3 release is not a prerequisite for 1.0.
155
+ R8 follows the published 0.2.2 correction; its supported source profiles
156
+ are bounded to the verified Devise 5.0.4 fixtures. The selected delivery version is 0.3.0. Its pre-1.0 integration contracts
157
+ remain subject to review before R5 freezes. Devise migration support is not available yet.
158
+
159
+ ## Delivery — 0.3.0 feature release, then the proposed 1.0 gate
160
+
161
+ - [x] Select 0.3.0 for the locally verified migration, lifecycle, provider and native scope.
162
+ - [ ] Pass required PR and exact default-branch CI/CodeQL for 0.3.0.
163
+ - [ ] Publish 0.3.0 through protected OIDC and verify the downloaded package and manual.
164
+
165
+ - [x] **R6 · Deliver the 0.2.2 correction.**
166
+ [PR #10](https://github.com/taimoorq/add_auth/pull/10) passed all required
167
+ checks, followed by exact default-branch CI and protected OIDC publication.
168
+ The downloaded package checksum and all 121 files match the reviewed
169
+ candidate; fresh-host installation and the matching public manual pass.
170
+ The existing latest-0.x support policy remains in effect.
171
+
172
+ - [ ] **R6 · Finish the adoption and compatibility review.** R1–R5 findings are
173
+ completed or explicitly dispositioned, the supported API is accepted, and
174
+ the published-package upgrade and documented operations profile pass.
175
+ - [ ] **R6 · Verify the exact candidate.** Preserve the complete local
176
+ Ruby/Rails, SQLite/PostgreSQL, generated/ejected browser and operations
177
+ acceptance; resolve release-blocking security and upgrade findings.
178
+ Recheck dependency currency and pass required GitHub CI/CodeQL controls.
179
+ - [ ] **R6 · Publish and verify 1.0.** Release notes, migration/support guidance,
180
+ protected OIDC publication, registry checksum/package verification, fresh
181
+ installation and the public manual all identify the same accepted release.
182
+
183
+ The owner accepted local testing as the gem release gate. Production migration,
184
+ a fixed number of adopters, live captcha accounts, physical devices and branded
185
+ emails are not additional gem release requirements. Hosts remain responsible for
186
+ their actual providers, proxy/TLS, trusted recovery addresses and support process.
187
+
188
+ ## Ongoing — broader compatibility evidence
189
+
190
+ - [ ] **R7 · Record browser, device and accessibility results as available.**
191
+ Track exact Safari/Firefox/mobile/hybrid authenticator and
192
+ assistive-technology environments. Add local regressions for reproducible
193
+ defects and document limits.
194
+ - [ ] **R7 · Record deployment-provider results as available.** Capture actual
195
+ provider and failure/recovery evidence without treating local protocol
196
+ fixtures as live-service certification.
197
+
198
+ These broaden host deployment confidence; they do not reopen completed 0.2
199
+ acceptance or silently add hardware/service gates to 1.0.
200
+
201
+ ## Later — evaluate demand before adding scope
202
+
203
+ These are candidates, not promised features or a committed “v2” release. A
204
+ compatible extension could ship in 1.x after an explicit scope decision.
205
+
206
+ - [ ] **F1 · Recovery codes.** First expansion candidate to assess when adopters
207
+ need recovery beyond trusted email or strict host support. Design single
208
+ use, regeneration/revocation, abuse controls and the recovery-policy boundary
209
+ before implementation; codes must not silently satisfy passkey-only purposes.
210
+ - [ ] **F2 · Rails-native password hashing integration.** Recheck available Rails
211
+ support and real adopter needs before adding an adapter or changing a default.
212
+ - [ ] **F3 · Account lifecycle helpers.** The bounded migration requirements
213
+ are promoted to R8 above; broader module parity remains outside this scope.
214
+ - [ ] **F4 · Multiple realms.** Require a concrete identity/session-isolation need
215
+ and migration design before adding models, cookies or routing APIs.
216
+ - [ ] **F4 · API/token authentication.** Android/iOS login is the active R8
217
+ work above; multiple realms and general API-key management remain separate.
218
+ - [ ] **F5 · Standalone test helpers or challenge adapters.** Extract only if
219
+ independent demand and maintenance capacity justify another package;
220
+ retain one implementation per concern.
221
+
222
+ Optional provider-library integration is locally verified under R8. SMS/TOTP and enterprise
223
+ or cross-origin WebAuthn remain outside the current roadmap. Account roles,
224
+ invitations, authorization and email branding
225
+ stay with the host.
226
+
227
+ ## Shipped — 0.2.1 baseline
228
+
229
+ - [x] Host password integration and explicit passwordless mode; one Core policy,
230
+ result presenter and atomic session finalizer.
231
+ - [x] Random digested session bearers, bounded Rails signed-ID session adoption,
232
+ expiry, device listing/pagination, revoke-one/all and host lifecycle invalidation.
233
+ - [x] Email links with inert GET/explicit POST confirmation, generic intake,
234
+ resend/replay protection and optional same-browser binding.
235
+ - [x] Discoverable passkeys, conditional sign-in, UV/origin enforcement,
236
+ credential management, counter checks and atomic last-method protection.
237
+ - [x] Purpose-bound password/email/passkey reauthentication, trusted-address
238
+ recovery, strict opt-in policy and protected host mutations.
239
+ - [x] Durable encrypted mail/notification intents, leases, retries,
240
+ cancellation and bounded maintenance with optional retention.
241
+ - [x] Turnstile and reCAPTCHA v2/v3 with distinct rejected/unavailable outcomes,
242
+ bounded verification and explicit outage policy.
243
+ - [x] Additive generators, fingerprinted view/controller/JavaScript/mail ejection,
244
+ drift diagnostics, doctor and framework-neutral testing helpers.
245
+ - [x] Shared HTML/Turbo pages, permitted no-JS alternatives, browser
246
+ capability detection and cache/CSRF/privacy protections.
247
+ - [x] Local supported Ruby 3.3/3.4/4.0 × Rails 8.0/8.1 matrix, SQLite/PostgreSQL
248
+ concurrency, generated/ejected browser and SMTP/queue/cache acceptance.
249
+ - [x] RSpec, Standard, dependency audit, CodeQL, protected repository controls
250
+ and pinned-action Trusted Publishing.
251
+ - [x] [Published 0.2.1](https://rubygems.org/gems/add_auth/versions/0.2.1),
252
+ verified registry installation and the maintained public manual.
253
+
254
+ Passkeys require JavaScript and a capable browser. Configured captcha may also
255
+ require JavaScript; strict policy is never weakened to imitate no-JS parity.
256
+ The immutable 0.1.0/0.2.0 tags did not publish packages; 0.2.1 is the first
257
+ successful package release. Historical details remain in the changelog and
258
+ release records.
259
+
260
+ For application setup, start with the [quickstart](https://addauthgem.com/quickstart/).
261
+ Report bugs or adoption feedback through [public issues](https://github.com/taimoorq/add_auth/issues);
262
+ use [private vulnerability reporting](SECURITY.md) for security concerns.
data/SECURITY.md CHANGED
@@ -34,6 +34,12 @@ mailing list, or social media) until a fix has been released.
34
34
  replacement handling.
35
35
  - Bounded session listing and authentication-history cleanup, including account
36
36
  scoping, eligibility rechecks and active-delivery-lease protection.
37
+ - Optional account lifecycle and migration boundaries: credential
38
+ profile selection, source-write fencing, address ownership, account proofs,
39
+ policy and revocation. These capabilities are introduced in 0.3.0.
40
+ - Optional provider identity binding and mobile sessions/handoffs, including
41
+ nonce/client/purpose binding, exact callbacks, single use and bearer/cookie
42
+ separation. Provider protocol cryptography remains library-owned.
37
43
  - The generated controllers and views this gem ships,
38
44
  including their CSRF, enumeration-safety, and Turbo-Stream behavior.
39
45
  - The GitHub Actions release pipeline (`.github/workflows/push_gem.yml`) and