add_auth 0.2.1

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 (122) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +125 -0
  3. data/CODE_OF_CONDUCT.md +4 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +545 -0
  6. data/ROADMAP.md +244 -0
  7. data/SECURITY.md +75 -0
  8. data/app/controllers/add_auth/assets_controller.rb +54 -0
  9. data/app/controllers/add_auth/passkeys_controller.rb +144 -0
  10. data/app/controllers/add_auth/reauthentications_controller.rb +81 -0
  11. data/app/controllers/add_auth/recoveries_controller.rb +50 -0
  12. data/app/controllers/add_auth/sessions_controller.rb +62 -0
  13. data/app/controllers/add_auth/sign_ins_controller.rb +65 -0
  14. data/app/helpers/add_auth/sign_ins_helper.rb +42 -0
  15. data/app/javascript/controllers/.keep +0 -0
  16. data/app/jobs/add_auth/delivery_job.rb +31 -0
  17. data/app/jobs/add_auth/email_delivery_job.rb +15 -0
  18. data/app/jobs/add_auth/email_request_job.rb +21 -0
  19. data/app/jobs/add_auth/security_notification_job.rb +13 -0
  20. data/app/mailers/add_auth/security_mailer.rb +16 -0
  21. data/app/mailers/add_auth/sign_in_mailer.rb +36 -0
  22. data/app/models/concerns/.keep +0 -0
  23. data/app/views/.keep +0 -0
  24. data/app/views/add_auth/passkeys/_controls.html.erb +17 -0
  25. data/app/views/add_auth/passkeys/_list.html.erb +32 -0
  26. data/app/views/add_auth/reauthentications/_check_email.html.erb +3 -0
  27. data/app/views/add_auth/reauthentications/_confirmation.html.erb +7 -0
  28. data/app/views/add_auth/reauthentications/_different_browser.html.erb +3 -0
  29. data/app/views/add_auth/reauthentications/_form.html.erb +27 -0
  30. data/app/views/add_auth/reauthentications/_invalid_link.html.erb +3 -0
  31. data/app/views/add_auth/recoveries/_check_email.html.erb +3 -0
  32. data/app/views/add_auth/recoveries/_confirmation.html.erb +9 -0
  33. data/app/views/add_auth/recoveries/_form.html.erb +11 -0
  34. data/app/views/add_auth/recoveries/_invalid_link.html.erb +3 -0
  35. data/app/views/add_auth/security_mailer/notice.text.erb +3 -0
  36. data/app/views/add_auth/sessions/_list.html.erb +25 -0
  37. data/app/views/add_auth/sessions/_revoke_all.html.erb +18 -0
  38. data/app/views/add_auth/sessions/index.html.erb +12 -0
  39. data/app/views/add_auth/sign_in_mailer/link.text.erb +5 -0
  40. data/app/views/add_auth/sign_ins/_check_email.html.erb +5 -0
  41. data/app/views/add_auth/sign_ins/_confirmation.html.erb +9 -0
  42. data/app/views/add_auth/sign_ins/_different_browser.html.erb +3 -0
  43. data/app/views/add_auth/sign_ins/_form.html.erb +34 -0
  44. data/app/views/add_auth/sign_ins/_invalid_link.html.erb +3 -0
  45. data/app/views/add_auth/sign_ins/show.html.erb +1 -0
  46. data/app/views/layouts/add_auth/authentication.html.erb +19 -0
  47. data/lib/add_auth/configuration.rb +61 -0
  48. data/lib/add_auth/core/access_policy.rb +55 -0
  49. data/lib/add_auth/core/browser_binding.rb +28 -0
  50. data/lib/add_auth/core/challenge/base.rb +100 -0
  51. data/lib/add_auth/core/challenge/http.rb +130 -0
  52. data/lib/add_auth/core/challenge/null.rb +21 -0
  53. data/lib/add_auth/core/challenge/recaptcha.rb +76 -0
  54. data/lib/add_auth/core/challenge/test.rb +32 -0
  55. data/lib/add_auth/core/challenge/turnstile.rb +46 -0
  56. data/lib/add_auth/core/delivery.rb +55 -0
  57. data/lib/add_auth/core/digest/base.rb +34 -0
  58. data/lib/add_auth/core/digest/hmac.rb +41 -0
  59. data/lib/add_auth/core/intake.rb +59 -0
  60. data/lib/add_auth/core/maintenance.rb +45 -0
  61. data/lib/add_auth/core/rate_limit.rb +30 -0
  62. data/lib/add_auth/core/security_events.rb +48 -0
  63. data/lib/add_auth/core/sessions.rb +287 -0
  64. data/lib/add_auth/core/step_up.rb +129 -0
  65. data/lib/add_auth/core/strategies/email_link.rb +201 -0
  66. data/lib/add_auth/core/strategies/passkey.rb +286 -0
  67. data/lib/add_auth/rails/authentication.rb +67 -0
  68. data/lib/add_auth/rails/authentication_pages.rb +66 -0
  69. data/lib/add_auth/rails/delivery_cipher.rb +33 -0
  70. data/lib/add_auth/rails/doctor.rb +154 -0
  71. data/lib/add_auth/rails/ejection.rb +138 -0
  72. data/lib/add_auth/rails/elevation.rb +35 -0
  73. data/lib/add_auth/rails/engine.rb +34 -0
  74. data/lib/add_auth/rails/password_entry.rb +34 -0
  75. data/lib/add_auth/rails/runtime.rb +216 -0
  76. data/lib/add_auth/rails/stores/account_lock.rb +40 -0
  77. data/lib/add_auth/rails/stores/delivery_state.rb +21 -0
  78. data/lib/add_auth/rails/stores/email_tokens.rb +92 -0
  79. data/lib/add_auth/rails/stores/maintenance.rb +46 -0
  80. data/lib/add_auth/rails/stores/passkeys.rb +63 -0
  81. data/lib/add_auth/rails/stores/security_events.rb +40 -0
  82. data/lib/add_auth/rails/stores/sessions.rb +62 -0
  83. data/lib/add_auth/rails/user_lifecycle.rb +35 -0
  84. data/lib/add_auth/result.rb +55 -0
  85. data/lib/add_auth/testing.rb +30 -0
  86. data/lib/add_auth/version.rb +5 -0
  87. data/lib/add_auth.rb +52 -0
  88. data/lib/generators/add_auth/challenge/challenge_generator.rb +48 -0
  89. data/lib/generators/add_auth/challenge/templates/recaptcha.rb.tt +28 -0
  90. data/lib/generators/add_auth/challenge/templates/turnstile.rb.tt +24 -0
  91. data/lib/generators/add_auth/controllers/controllers_generator.rb +14 -0
  92. data/lib/generators/add_auth/ejection.rb +18 -0
  93. data/lib/generators/add_auth/email_link/email_link_generator.rb +56 -0
  94. data/lib/generators/add_auth/email_link/templates/add_add_auth_email_binding.rb.tt +5 -0
  95. data/lib/generators/add_auth/email_link/templates/add_add_auth_email_delivery.rb.tt +10 -0
  96. data/lib/generators/add_auth/email_link/templates/add_auth.css +28 -0
  97. data/lib/generators/add_auth/email_link/templates/add_auth_challenge.js +129 -0
  98. data/lib/generators/add_auth/email_tokens/email_tokens_generator.rb +35 -0
  99. data/lib/generators/add_auth/email_tokens/templates/add_auth_sign_in_token.rb +4 -0
  100. data/lib/generators/add_auth/email_tokens/templates/create_add_auth_sign_in_tokens.rb.tt +18 -0
  101. data/lib/generators/add_auth/install/install_generator.rb +27 -0
  102. data/lib/generators/add_auth/install/templates/initializer.rb +46 -0
  103. data/lib/generators/add_auth/javascript/javascript_generator.rb +14 -0
  104. data/lib/generators/add_auth/javascript/templates/application.js +2 -0
  105. data/lib/generators/add_auth/javascript/templates/codec.js +28 -0
  106. data/lib/generators/add_auth/javascript/templates/passkey.js +81 -0
  107. data/lib/generators/add_auth/mailer_views/mailer_views_generator.rb +14 -0
  108. data/lib/generators/add_auth/notifications/notifications_generator.rb +32 -0
  109. data/lib/generators/add_auth/notifications/templates/add_auth_security_event.rb +4 -0
  110. data/lib/generators/add_auth/notifications/templates/create_add_auth_security_events.rb.tt +18 -0
  111. data/lib/generators/add_auth/passkeys/passkeys_generator.rb +75 -0
  112. data/lib/generators/add_auth/passkeys/templates/add_add_auth_passkeys.rb.tt +45 -0
  113. data/lib/generators/add_auth/passkeys/templates/add_auth_ceremony.rb +4 -0
  114. data/lib/generators/add_auth/passkeys/templates/add_auth_credential.rb +4 -0
  115. data/lib/generators/add_auth/session_upgrade/session_upgrade_generator.rb +79 -0
  116. data/lib/generators/add_auth/session_upgrade/templates/add_add_auth_elevation.rb.tt +12 -0
  117. data/lib/generators/add_auth/session_upgrade/templates/extend_sessions_for_add_auth.rb.tt +14 -0
  118. data/lib/generators/add_auth/step_up/step_up_generator.rb +44 -0
  119. data/lib/generators/add_auth/step_up/templates/add_add_auth_reauthentication.rb.tt +9 -0
  120. data/lib/generators/add_auth/views/views_generator.rb +16 -0
  121. data/lib/tasks/add_auth.rake +38 -0
  122. metadata +361 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 33de30a9b51e6aff4236af059703155e8eeed6692497df9657c2958d37d21536
4
+ data.tar.gz: a3dd63d2b854c69f4f17af73d067f7dc5b9c5fd3105ce9b45cd2d1aec8eb943f
5
+ SHA512:
6
+ metadata.gz: ac89ed45158b07a68a94fba2c832781b1f5a38f732217f29992865dc0b0f532ae6e0e70f79c746b1a962f07cad4f7ec0cadff71485d79d1c569af07ef2c3887c
7
+ data.tar.gz: 99459566fa90408261c16d2cd3453c168e3800a913cdbe48b44ebc4b64dd13a2cddda3661097b01d12f39cc89415b395158fb0c50b6fa335412fa5544a91f022
data/CHANGELOG.md ADDED
@@ -0,0 +1,125 @@
1
+ # Changelog
2
+
3
+ ## 0.2.1 — 2026-09-07
4
+
5
+ - Install release dependencies into RubyGems' normal gem path so the attestation
6
+ preload and Bundler resolve the same OpenSSL version. Check that loading order
7
+ before requesting publishing credentials. Retain OIDC and attestations.
8
+ - The immutable `v0.2.0` tag passed all acceptance checks but did not publish a
9
+ package because its release action hit an OpenSSL activation conflict.
10
+ Authentication runtime and feature behavior are unchanged from that candidate.
11
+
12
+ ## 0.2.0 — 2026-09-07
13
+
14
+ First integrated 0.2 release for Rails 8.0 and 8.1 hosts on Ruby 3.3, 3.4 and
15
+ 4.0. Local integration acceptance covers real stores, generated hosts, browser
16
+ journeys and SMTP/queue/cache recovery. Hosts own verification of their production
17
+ providers and physical devices. Review generated changes when upgrading this
18
+ pre-1.0 API. The earlier `v0.1.0` tag did not publish a gem.
19
+
20
+ ### AddAuth name
21
+
22
+ - Rename the development gem from Latchkey to `add_auth`, with Ruby namespace
23
+ `AddAuth` and `add_auth:*` generators/tasks. Standard Rails/Thor naming handles engine loading, models, controllers and
24
+ generator discovery without an inflection override.
25
+ - Fresh installations use AddAuth tables, configuration, cookies, cryptographic
26
+ contexts, jobs and ejection manifests. This release does not migrate an
27
+ existing Latchkey installation or provide a legacy namespace alias.
28
+
29
+ ### Operations and documentation
30
+
31
+ - Bound session pages to 50 candidates plus the current browser and one lookahead,
32
+ using account-scoped creation-order cursors. Add session lookup/retention indexes.
33
+ - Bound each maintenance operation to 100 rows by default (configurable 1–1000).
34
+ Add opt-in session and email/notification receipt retention. Recheck eligibility
35
+ during cleanup, protect active delivery leases and report completed-pass counts.
36
+ - Check standalone notification queue/mail configuration and successful cleanup
37
+ in doctor; fail the sweep if the queue declines a handoff.
38
+ - Add local Redis/Sidekiq/SMTP restart and retry acceptance without runtime
39
+ dependencies on those services.
40
+ - Expand the RubyGems-first manual with passkeys, reauthentication, recovery,
41
+ notifications, testing and operations guides, highlighted code and accessible
42
+ Mermaid diagrams. Email themes remain an optional host presentation choice.
43
+
44
+ ### Security and lifecycle hardening
45
+
46
+ - Prevent fixed-window rate-limit bursts and cap anonymous passkey ceremonies;
47
+ require production doctor to observe a recent successful cleanup run.
48
+ - Return an unavailable response for invalid passkey configuration and safely
49
+ redirect when a step-up purpose is removed during a request.
50
+ - Keep generated-host Gemfiles and lockfiles isolated under Bundler 4, and serve
51
+ public assets through a stateless controller restricted to GET/HEAD.
52
+ - Atomically retire the browser's previous session on password/email sign-in,
53
+ including account switches; retain it on failed proof or database rollback.
54
+ - Invalidate installed email tokens on password/address changes even while email
55
+ sign-in is disabled, preserving hosts without email persistence.
56
+ - Recheck current account, initiating session and bearer generation under lock
57
+ for revoke-one. Its Core API now requires the initiating `session:`.
58
+ - Treat mail callback/interceptor suppression as cancellation: revoke the link,
59
+ emit `delivery_cancelled.add_auth` with only the issuance ID, and never mark it
60
+ delivered or resend it. Actual delivery errors retain the same-intent retry.
61
+ - Apply shared abuse/CSRF/challenge policy to legacy and new password entry
62
+ points; throttle and lock password reauthentication for revoke-all.
63
+ - Bind step-up to proof time, current credentials and bearer generation, and
64
+ recheck authority under the transaction lock. Require transaction-owned email
65
+ session creation, including connection/thread provenance.
66
+ - Redact provider tokens/secrets; classify outages accurately and bound provider
67
+ payloads, scores, network deadlines and response sizes.
68
+ - Use scoped Stimulus widgets with Turbo retry/cache cleanup, shared session-only
69
+ assets, HTML/stream reauthentication errors and correct frame/redirect behavior.
70
+ - Fail closed on missing production captcha configuration; expand doctor and
71
+ packaged-host/README tests. Pin release actions, require tested tag provenance
72
+ and add PostgreSQL CI plus the Ruby 4.0/PostgreSQL branch checks.
73
+ ### Authentication features and host integration
74
+
75
+ - Add explicit email/passkey-only mode, rejecting password proof while keeping
76
+ installed Rails password aliases guarded. Support a User without password
77
+ methods during email-address invalidation. Default password behavior is unchanged.
78
+ - Require authenticated sessions on account-management endpoints even in hosts
79
+ whose general page guard permits anonymous readers; retain public proof routes.
80
+ - Add optional browser-bound ordinary email links and public password/email/passkey
81
+ reauthentication, always binding email elevation to its browser/session/purpose.
82
+ - Add discoverable passkey enrollment, explicit/conditional sign-in, management,
83
+ UV and exact RP/origin enforcement, atomic counters and last-credential checks.
84
+ - Add trusted-address recovery with replacement grants and opt-in strict policy
85
+ enforced across sign-in, reset, fallback, feature toggles and policy changes.
86
+ - Add encrypted security-notification intents sharing email delivery leases,
87
+ retries, cancellation and the pending-delivery/expired-ceremony sweep.
88
+ - Add complete view/controller/JavaScript/mailer-view ejection, preserved source
89
+ fingerprints, doctor upstream diffs and framework-neutral browser/mail helpers.
90
+ - Require WebAuthn 3.4.3 or newer in the 3.x line and Public Suffix 7.x for the
91
+ verified ceremony API and RP public-suffix validation; Ruby/Rails floors stay.
92
+
93
+ - Add the signed-ID session bridge, random bearer cookies, absolute/idle expiry,
94
+ revocation, safe return paths and host password/address invalidation hooks.
95
+ - Add authenticated session visibility and revoke-one management at `/sessions`;
96
+ metadata excludes bearer material and ownership is checked under the account lock.
97
+ - Add password-reauthenticated `/sessions/revoke-all`, which revokes every active
98
+ bearer under the account lock and clears the initiating browser.
99
+ - Add the Rails-independent step-up policy foundation: purpose-bound grants,
100
+ separate freshness/strength windows, session/account binding and passkey UV
101
+ enforcement, persisted evidence, atomic bearer rotation and host mutation guards.
102
+ - Complete the default email sign-in path with encrypted request jobs, idempotent
103
+ issuance, leased delivery retries, recovery sweep, inert link confirmation and
104
+ deliberate account switching. Keep public request responses generic.
105
+ - Add shared HTML/Turbo login pages, no-JS password/email flows, scoped CSS and
106
+ semantic class/stylesheet overrides for host Bootstrap and Tailwind builds.
107
+ - Add server-backed Turnstile and reCAPTCHA v2/v3 challenge adapters with
108
+ hostname/action/score checks, bounded HTTPS verification, explicit closed/open
109
+ outage policy, provider markup and a Turbo-safe reCAPTCHA v3 submit bridge.
110
+ - Add `add_auth:challenge turnstile|recaptcha` scaffolding with environment-keyed
111
+ secrets and an idempotent fixed challenge asset route.
112
+ - Extend `add_auth:doctor` to verify session elevation columns, challenge policy
113
+ and the reCAPTCHA v3 asset route alongside origin/mail/cache checks.
114
+ - Add view ejection, fresh-host installation tests, CSRF-enabled Chrome journeys,
115
+ real cookie/worker failure tests and permanent default-color contrast checks.
116
+
117
+ - Add the Rails-backed email-token persistence slice: atomic replacement and
118
+ consumption/session persistence, encrypted expiring delivery intent, replay,
119
+ address/eligibility checks, rollback and query-cache protection.
120
+ - Add `add_auth:email_tokens` with additive schema and custom-model preservation;
121
+ add inert configuration install and per-feature session/email generators.
122
+ - Require explicit strong HMAC key material in Core; derive Rails defaults through
123
+ the engine and make challenge verification outcomes immutable.
124
+ - Add shared fake/SQLite contracts, host request specs, fresh Rails generator tests
125
+ and a Ruby/Rails CI matrix. Replace generated Minitest stubs with RSpec coverage.
@@ -0,0 +1,4 @@
1
+ # Code of Conduct
2
+
3
+ Be respectful, be constructive, assume good faith. Reports go to
4
+ taimoorq@gmail.com.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Taimoor Qureshi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.