rodauth 2.36.0 → 2.37.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 (159) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rodauth/features/base.rb +15 -1
  3. data/lib/rodauth/features/change_login.rb +2 -2
  4. data/lib/rodauth/features/create_account.rb +2 -2
  5. data/lib/rodauth/features/email_auth.rb +1 -1
  6. data/lib/rodauth/features/internal_request.rb +4 -4
  7. data/lib/rodauth/features/json.rb +5 -0
  8. data/lib/rodauth/features/jwt.rb +5 -9
  9. data/lib/rodauth/features/lockout.rb +1 -1
  10. data/lib/rodauth/features/login.rb +1 -1
  11. data/lib/rodauth/features/login_password_requirements_base.rb +13 -0
  12. data/lib/rodauth/features/reset_password.rb +1 -1
  13. data/lib/rodauth/features/two_factor_base.rb +6 -13
  14. data/lib/rodauth/features/verify_account.rb +2 -2
  15. data/lib/rodauth/features/webauthn_autofill.rb +2 -1
  16. data/lib/rodauth/features/webauthn_login.rb +1 -1
  17. data/lib/rodauth/version.rb +1 -1
  18. data/lib/rodauth.rb +6 -2
  19. metadata +3 -258
  20. data/CHANGELOG +0 -521
  21. data/README.rdoc +0 -1555
  22. data/doc/account_expiration.rdoc +0 -41
  23. data/doc/active_sessions.rdoc +0 -56
  24. data/doc/argon2.rdoc +0 -54
  25. data/doc/audit_logging.rdoc +0 -44
  26. data/doc/base.rdoc +0 -123
  27. data/doc/change_login.rdoc +0 -25
  28. data/doc/change_password.rdoc +0 -26
  29. data/doc/change_password_notify.rdoc +0 -14
  30. data/doc/close_account.rdoc +0 -26
  31. data/doc/confirm_password.rdoc +0 -32
  32. data/doc/create_account.rdoc +0 -27
  33. data/doc/disallow_common_passwords.rdoc +0 -17
  34. data/doc/disallow_password_reuse.rdoc +0 -30
  35. data/doc/email_auth.rdoc +0 -55
  36. data/doc/email_base.rdoc +0 -18
  37. data/doc/error_reasons.rdoc +0 -77
  38. data/doc/guides/admin_activation.rdoc +0 -46
  39. data/doc/guides/already_authenticated.rdoc +0 -10
  40. data/doc/guides/alternative_login.rdoc +0 -46
  41. data/doc/guides/change_table_and_column_names.rdoc +0 -19
  42. data/doc/guides/create_account_programmatically.rdoc +0 -38
  43. data/doc/guides/delay_password.rdoc +0 -25
  44. data/doc/guides/email_only.rdoc +0 -16
  45. data/doc/guides/i18n.rdoc +0 -29
  46. data/doc/guides/internals.rdoc +0 -233
  47. data/doc/guides/links.rdoc +0 -12
  48. data/doc/guides/login_return.rdoc +0 -37
  49. data/doc/guides/migrate_password_hash_algorithm.rdoc +0 -15
  50. data/doc/guides/password_column.rdoc +0 -25
  51. data/doc/guides/password_confirmation.rdoc +0 -37
  52. data/doc/guides/password_requirements.rdoc +0 -43
  53. data/doc/guides/paths.rdoc +0 -51
  54. data/doc/guides/query_params.rdoc +0 -9
  55. data/doc/guides/redirects.rdoc +0 -17
  56. data/doc/guides/registration_field.rdoc +0 -68
  57. data/doc/guides/render_confirmation.rdoc +0 -17
  58. data/doc/guides/require_mfa.rdoc +0 -30
  59. data/doc/guides/reset_password_autologin.rdoc +0 -21
  60. data/doc/guides/share_configuration.rdoc +0 -34
  61. data/doc/guides/status_column.rdoc +0 -28
  62. data/doc/guides/totp_or_recovery.rdoc +0 -16
  63. data/doc/http_basic_auth.rdoc +0 -18
  64. data/doc/internal_request.rdoc +0 -539
  65. data/doc/json.rdoc +0 -56
  66. data/doc/jwt.rdoc +0 -52
  67. data/doc/jwt_cors.rdoc +0 -22
  68. data/doc/jwt_refresh.rdoc +0 -58
  69. data/doc/lockout.rdoc +0 -73
  70. data/doc/login.rdoc +0 -39
  71. data/doc/login_password_requirements_base.rdoc +0 -44
  72. data/doc/logout.rdoc +0 -22
  73. data/doc/otp.rdoc +0 -93
  74. data/doc/otp_lockout_email.rdoc +0 -30
  75. data/doc/otp_modify_email.rdoc +0 -19
  76. data/doc/otp_unlock.rdoc +0 -58
  77. data/doc/password_complexity.rdoc +0 -34
  78. data/doc/password_expiration.rdoc +0 -38
  79. data/doc/password_grace_period.rdoc +0 -24
  80. data/doc/password_pepper.rdoc +0 -52
  81. data/doc/path_class_methods.rdoc +0 -10
  82. data/doc/recovery_codes.rdoc +0 -61
  83. data/doc/release_notes/1.0.0.txt +0 -443
  84. data/doc/release_notes/1.1.0.txt +0 -8
  85. data/doc/release_notes/1.10.0.txt +0 -80
  86. data/doc/release_notes/1.11.0.txt +0 -32
  87. data/doc/release_notes/1.12.0.txt +0 -61
  88. data/doc/release_notes/1.13.0.txt +0 -34
  89. data/doc/release_notes/1.14.0.txt +0 -19
  90. data/doc/release_notes/1.15.0.txt +0 -21
  91. data/doc/release_notes/1.16.0.txt +0 -31
  92. data/doc/release_notes/1.17.0.txt +0 -23
  93. data/doc/release_notes/1.18.0.txt +0 -26
  94. data/doc/release_notes/1.19.0.txt +0 -116
  95. data/doc/release_notes/1.2.0.txt +0 -18
  96. data/doc/release_notes/1.20.0.txt +0 -175
  97. data/doc/release_notes/1.21.0.txt +0 -12
  98. data/doc/release_notes/1.22.0.txt +0 -11
  99. data/doc/release_notes/1.23.0.txt +0 -32
  100. data/doc/release_notes/1.3.0.txt +0 -21
  101. data/doc/release_notes/1.4.0.txt +0 -11
  102. data/doc/release_notes/1.5.0.txt +0 -74
  103. data/doc/release_notes/1.6.0.txt +0 -37
  104. data/doc/release_notes/1.7.0.txt +0 -6
  105. data/doc/release_notes/1.8.0.txt +0 -14
  106. data/doc/release_notes/1.9.0.txt +0 -15
  107. data/doc/release_notes/2.0.0.txt +0 -361
  108. data/doc/release_notes/2.1.0.txt +0 -31
  109. data/doc/release_notes/2.10.0.txt +0 -47
  110. data/doc/release_notes/2.11.0.txt +0 -31
  111. data/doc/release_notes/2.12.0.txt +0 -17
  112. data/doc/release_notes/2.13.0.txt +0 -19
  113. data/doc/release_notes/2.14.0.txt +0 -17
  114. data/doc/release_notes/2.15.0.txt +0 -48
  115. data/doc/release_notes/2.16.0.txt +0 -20
  116. data/doc/release_notes/2.17.0.txt +0 -10
  117. data/doc/release_notes/2.18.0.txt +0 -27
  118. data/doc/release_notes/2.19.0.txt +0 -61
  119. data/doc/release_notes/2.2.0.txt +0 -39
  120. data/doc/release_notes/2.20.0.txt +0 -10
  121. data/doc/release_notes/2.21.0.txt +0 -28
  122. data/doc/release_notes/2.22.0.txt +0 -43
  123. data/doc/release_notes/2.23.0.txt +0 -15
  124. data/doc/release_notes/2.24.0.txt +0 -15
  125. data/doc/release_notes/2.25.0.txt +0 -8
  126. data/doc/release_notes/2.26.0.txt +0 -45
  127. data/doc/release_notes/2.27.0.txt +0 -35
  128. data/doc/release_notes/2.28.0.txt +0 -16
  129. data/doc/release_notes/2.29.0.txt +0 -27
  130. data/doc/release_notes/2.3.0.txt +0 -37
  131. data/doc/release_notes/2.30.0.txt +0 -15
  132. data/doc/release_notes/2.31.0.txt +0 -47
  133. data/doc/release_notes/2.32.0.txt +0 -65
  134. data/doc/release_notes/2.33.0.txt +0 -18
  135. data/doc/release_notes/2.34.0.txt +0 -36
  136. data/doc/release_notes/2.35.0.txt +0 -22
  137. data/doc/release_notes/2.36.0.txt +0 -35
  138. data/doc/release_notes/2.4.0.txt +0 -22
  139. data/doc/release_notes/2.5.0.txt +0 -20
  140. data/doc/release_notes/2.6.0.txt +0 -37
  141. data/doc/release_notes/2.7.0.txt +0 -33
  142. data/doc/release_notes/2.8.0.txt +0 -20
  143. data/doc/release_notes/2.9.0.txt +0 -21
  144. data/doc/remember.rdoc +0 -79
  145. data/doc/reset_password.rdoc +0 -66
  146. data/doc/reset_password_notify.rdoc +0 -17
  147. data/doc/session_expiration.rdoc +0 -28
  148. data/doc/single_session.rdoc +0 -37
  149. data/doc/sms_codes.rdoc +0 -138
  150. data/doc/two_factor_base.rdoc +0 -70
  151. data/doc/update_password_hash.rdoc +0 -7
  152. data/doc/verify_account.rdoc +0 -67
  153. data/doc/verify_account_grace_period.rdoc +0 -19
  154. data/doc/verify_login_change.rdoc +0 -59
  155. data/doc/webauthn.rdoc +0 -118
  156. data/doc/webauthn_autofill.rdoc +0 -19
  157. data/doc/webauthn_login.rdoc +0 -16
  158. data/doc/webauthn_modify_email.rdoc +0 -19
  159. data/doc/webauthn_verify_account.rdoc +0 -9
data/README.rdoc DELETED
@@ -1,1555 +0,0 @@
1
- = Rodauth
2
-
3
- Rodauth is Ruby's most advanced authentication framework, designed
4
- to work in any rack application. It's built using Roda and Sequel,
5
- but it can be used with other web frameworks, database libraries,
6
- and databases.
7
-
8
- When used with PostgreSQL, MySQL, and Microsoft SQL Server in the
9
- default configuration, it offers additional security for password
10
- hashes by protecting access via database functions.
11
-
12
- Rodauth supports multiple multifactor authentication methods,
13
- multiple passwordless authentication methods, and offers both an
14
- HTML and JSON API for all supported features.
15
-
16
- == Design Goals
17
-
18
- * Security: Ship in a maximum security by default configuration
19
- * Simplicity: Allow for easy configuration via a DSL
20
- * Flexibility: Allow for easy overriding of any part of the framework
21
-
22
- == Features
23
-
24
- * Login
25
- * Logout
26
- * Change Password
27
- * Change Login
28
- * Reset Password
29
- * Create Account
30
- * Close Account
31
- * Verify Account
32
- * Confirm Password
33
- * Remember (Autologin via token)
34
- * Lockout (Bruteforce protection)
35
- * Audit Logging
36
- * Email Authentication (Passwordless login via email link)
37
- * WebAuthn (Multifactor authentication via WebAuthn)
38
- * WebAuthn Login (Passwordless login via WebAuthn)
39
- * WebAuthn Verify Account (Passwordless WebAuthn Setup)
40
- * WebAuthn Autofill (Autofill WebAuthn credentials on login)
41
- * WebAuthn Modify Email (Email when WebAuthn authenticator aded or removed)
42
- * OTP (Multifactor authentication via TOTP)
43
- * OTP Modify Email (Email when TOTP authentication setup or disabled)
44
- * OTP Unlock (Unlock TOTP authentication after lockout)
45
- * OTP Lockout Email (Email when TOTP authentication locked out or unlocked)
46
- * Recovery Codes (Multifactor authentication via backup codes)
47
- * SMS Codes (Multifactor authentication via SMS)
48
- * Verify Login Change (Verify new login before changing login)
49
- * Verify Account Grace Period (Don't require verification before login)
50
- * Password Grace Period (Don't require password entry if recently entered)
51
- * Password Complexity (More sophisticated checks)
52
- * Password Pepper
53
- * Disallow Password Reuse
54
- * Disallow Common Passwords
55
- * Password Expiration
56
- * Account Expiration
57
- * Session Expiration
58
- * Active Sessions (Prevent session reuse after logout, allow logout of all sessions)
59
- * Single Session (Only one active session per account)
60
- * JSON (JSON API support for all other features)
61
- * JWT (JSON Web Token support for all other features)
62
- * JWT Refresh (Access & Refresh Token)
63
- * JWT CORS (Cross-Origin Resource Sharing)
64
- * Update Password Hash (when hash cost changes)
65
- * Argon2
66
- * HTTP Basic Auth
67
- * Change Password Notify
68
- * Reset Password Notify
69
- * Internal Request
70
- * Path Class Methods
71
-
72
- == Resources
73
-
74
- Website :: http://rodauth.jeremyevans.net
75
- Demo Site :: http://rodauth-demo.jeremyevans.net
76
- Source :: http://github.com/jeremyevans/rodauth
77
- Bugs :: http://github.com/jeremyevans/rodauth/issues
78
- Discussion Forum (GitHub Discussions) :: https://github.com/jeremyevans/rodauth/discussions
79
- Alternate Discussion Forum (Google Groups) :: https://groups.google.com/forum/#!forum/rodauth
80
-
81
- == Dependencies
82
-
83
- There are some dependencies that Rodauth uses depending on the
84
- features in use. These are development dependencies instead of
85
- runtime dependencies in the gem as it is possible to run without them:
86
-
87
- tilt :: Used by all features unless in JSON API only mode or using
88
- :render=>false plugin option.
89
- rack_csrf :: Used for CSRF support if the <tt>csrf: :rack_csrf</tt> plugin
90
- option is given (the default is to use Roda's route_csrf
91
- plugin, as that allows for more secure request-specific
92
- tokens).
93
- bcrypt :: Used by default for password hashing, can be skipped
94
- if password_match? is overridden for custom authentication.
95
- argon2 :: Used by the argon2 feature as alternative to bcrypt for
96
- password hashing.
97
- mail :: Used by default for mailing in the reset_password, verify_account,
98
- verify_login_change, change_password_notify, lockout, and
99
- email_auth features.
100
- rotp :: Used by the otp feature
101
- rqrcode :: Used by the otp feature
102
- jwt :: Used by the jwt feature
103
- webauthn :: Used by the webauthn feature
104
-
105
- You can use <tt>gem install --development rodauth</tt> to install
106
- the development dependencies in order to run tests.
107
-
108
- == Security
109
-
110
- === Password Hash Access Via Database Functions
111
-
112
- By default on PostgreSQL, MySQL, and Microsoft SQL Server, Rodauth
113
- uses database functions to access password hashes, with the user
114
- running the application unable to get direct access to password
115
- hashes. This reduces the risk of an attacker being able to access
116
- password hashes and use them to attack other sites.
117
-
118
- The rest of this section describes this feature in more detail, but
119
- note that Rodauth does not require this feature be used and works
120
- correctly without it. There may be cases where you cannot use
121
- this feature, such as when using a different database or when you
122
- do not have full control over the database you are using.
123
-
124
- Passwords are hashed using bcrypt by default, and the password hashes are
125
- kept in a separate table from the accounts table, with a foreign key
126
- referencing the accounts table. Two database functions are added,
127
- one to retrieve the salt for a password, and the other to check
128
- if a given password hash matches the password hash for the user.
129
-
130
- Two database accounts are used. The first is the account that the
131
- application uses, which is referred to as the +app+ account. The +app+
132
- account does not have access to read the password hashes. The other
133
- account handles password hashes and is referred to as the +ph+
134
- account. The +ph+ account sets up the database functions that can
135
- retrieve the salt for a given account's password, and check if a
136
- password hash matches for a given account. The +ph+ account
137
- sets these functions up so that the +app+ account can execute the
138
- functions using the +ph+ account's permissions. This allows the
139
- +app+ account to check passwords without having access to read
140
- password hashes.
141
-
142
- While the +app+ account is not be able to read password hashes, it
143
- is still be able to insert password hashes, update passwords hashes,
144
- and delete password hashes, so the additional security is not that
145
- painful.
146
-
147
- By disallowing the +app+ account access to the password hashes,
148
- it is much more difficult for an attacker to access the password
149
- hashes, even if they are able to exploit an SQL injection or remote
150
- code execution vulnerability in the application.
151
-
152
- The reason for extra security in regards to password hashes stems from
153
- the fact that people tend to choose poor passwords and reuse passwords,
154
- so a compromise of one database containing password hashes can result
155
- in account access on other sites, making password hash storage of
156
- critical importance even if the other data stored is not that important.
157
-
158
- If you are storing other sensitive information in your database, you
159
- should consider using a similar approach in other areas (or all areas)
160
- of your application.
161
-
162
- === Tokens
163
-
164
- Account verification, password resets, email auth, verify login change,
165
- remember, and lockout tokens all use a similar approach. They all
166
- provide a token, in the format "account-id_long-random-string". By
167
- including the id of the account in the token, an attacker can only
168
- attempt to bruteforce the token for a single account, instead of being
169
- able to bruteforce tokens for all accounts at once (which would be
170
- possible if the token was just a random string).
171
-
172
- Additionally, all comparisons of tokens use a timing-safe comparison
173
- function to reduce the risk of timing attacks.
174
-
175
- == HMAC
176
-
177
- By default, for backwards compatibility, Rodauth does not use HMACs,
178
- but you are strongly encouraged to use the +hmac_secret+ configuration
179
- method to set an HMAC secret. Setting an HMAC secret will enable HMACs
180
- for additional security, as described below.
181
-
182
- === email_base feature
183
-
184
- All features that send email use this feature. Setting +hmac_secret+
185
- will make the tokens sent via email use an HMAC, while the raw token
186
- stored in the database will not use an HMAC. This will make it so
187
- if the tokens in the database are leaked (e.g. via an SQL injection
188
- vulnerability), they will not be usable without also having access
189
- to the +hmac_secret+. Without an HMAC, the raw token is sent in the
190
- email, and if the tokens in the database are leaked, they will be
191
- usable.
192
-
193
- To allow for an graceful transition, you can set +allow_raw_email_token?+
194
- to true temporarily. This will allow the raw tokens in previous sent
195
- emails to still work. This should only be set temporarily as it
196
- removes the security that +hmac_secret+ adds. Most features that
197
- send email have tokens that expire by default in 1 day. The
198
- exception is the verify_account feature, which has tokens that do
199
- not expire. For the verify_account feature, if the user requested
200
- an email before +hmac_secret+ was set, after +allow_raw_email_token+
201
- is no longer set, they will need to request the verification email
202
- be resent, in which case they will receive an email with a token
203
- that uses an HMAC.
204
-
205
- === remember feature
206
-
207
- Similar to the email_base feature, this uses HMACs for remember
208
- tokens, while storing the raw tokens in the database. This makes
209
- it so if the raw tokens in the database are leaked, the remember
210
- tokens are not usable without knowledge of the +hmac_secret+.
211
-
212
- The +raw_remember_token_deadline+ configuration method can
213
- be set to allow a previously set raw remember token to be used
214
- if the deadline for the remember token is before the given time.
215
- This allows for graceful transition to using HMACs for remember tokens.
216
- By default, the deadline is 14 days after the token is created, so this
217
- should be set to 14 days after the time you enable the HMAC for the
218
- remember feature if you are using the defaults.
219
-
220
- === otp feature
221
-
222
- Setting +hmac_secret+ will provide HMACed OTP keys to users, and
223
- would store the raw OTP keys in the database. This will make so
224
- if the raw OTP keys in the database are leaked, they will not be
225
- usable for two factor authentication without knowledge of the +hmac_secret+.
226
-
227
- Unfortunately, there can be no simple graceful transition for existing users.
228
- When introducing +hmac_secret+ to a Rodauth installation that already uses
229
- the otp feature, you will have to either revoke and replace all OTP keys,
230
- set +otp_keys_use_hmac?+ to false and continue to use raw OTP keys, or override
231
- +otp_keys_use_hmac?+ to return false if the user was issued an OTP key before
232
- +hmac_secret+ was added to the configuration, and true otherwise.
233
- +otp_keys_use_hmac?+ defaults to true if +hmac_secret+ is set, and false
234
- otherwise.
235
-
236
- If +otp_keys_use_hmac?+ is true, Rodauth will also ensure during OTP setup
237
- that the OTP key was generated by the server. If +otp_keys_use_hmac?+ is false,
238
- any OTP key in a valid format will be accepted during setup.
239
-
240
- If +otp_keys_use_hmac?+ is true, the jwt and otp features are in use and you
241
- are setting up OTP via JSON requests, you need to first send a POST request
242
- to the OTP setup route. This will return an error with the +otp_secret+ and
243
- +otp_raw_secret+ parameters in the JSON. These parameters should be submitted
244
- in the POST request to setup OTP, along with a valid OTP auth code for the
245
- +otp_secret+.
246
-
247
- === webauthn feature
248
-
249
- Setting +hmac_secret+ is required to use the webauthn feature, as it is
250
- used for checking that the provided authentication challenges have not
251
- been modified.
252
-
253
- === active_sessions feature
254
-
255
- Setting +hmac_secret+ is required to use the active_sessions feature,
256
- as the database stores an HMAC of the active session ID.
257
-
258
- === single_session feature
259
-
260
- Setting +hmac_secret+ will ensure the single session secret set in the
261
- session will be an HMACed. This does not affect security, as the session
262
- itself should at the least by protected by an HMAC (if not encrypted).
263
- This is only done for consistency, so that the raw tokens in the database
264
- are distinct from the tokens provided to the users. To allow for a
265
- graceful transition, +allow_raw_single_session_key?+ can be set to true.
266
-
267
- == PostgreSQL Database Setup
268
-
269
- In order to get full advantages of Rodauth's security design on PostgreSQL,
270
- multiple database accounts are involved:
271
-
272
- 1. database superuser account (usually postgres)
273
- 2. +app+ account (same name as application)
274
- 3. +ph+ account (application name with +_password+ appended)
275
-
276
- The database superuser account is used to load extensions related to the
277
- database. The application should never be run using the database
278
- superuser account.
279
-
280
- === Create database accounts
281
-
282
- If you are currently running your application using the database superuser
283
- account, the first thing you need to do is to create the +app+ database
284
- account. It's often best to name this account the same as the
285
- database name.
286
-
287
- You should also create the +ph+ database account which will handle access
288
- to the password hashes.
289
-
290
- Example for PostgreSQL:
291
-
292
- createuser -U postgres ${DATABASE_NAME}
293
- createuser -U postgres ${DATABASE_NAME}_password
294
-
295
- Note that if the database superuser account owns all of the items in the
296
- database, you'll need to change the ownership to the database account you
297
- just created. See https://gist.github.com/jeremyevans/8483320
298
- for a way to do that.
299
-
300
- === Create database
301
-
302
- In general, the +app+ account is the owner of the database, since it will
303
- own most of the tables:
304
-
305
- createdb -U postgres -O ${DATABASE_NAME} ${DATABASE_NAME}
306
-
307
- Note that this is not the most secure way to develop applications. For
308
- maximum security, you would want to use a separate database account as
309
- the owner of the tables, have the +app+ account not be the
310
- owner of any tables, and specifically grant the +app+ account only the
311
- minimum access it needs to work correctly. Doing that is beyond the
312
- scope of Rodauth, though.
313
-
314
- === Load extensions
315
-
316
- If you want to use the login features for Rodauth, you need to load the
317
- citext extension if you want to support case insensitive logins.
318
-
319
- Example:
320
-
321
- psql -U postgres -c "CREATE EXTENSION citext" ${DATABASE_NAME}
322
-
323
- Note that on Heroku, this extension can be loaded using a standard database
324
- account. If you want logins to be case sensitive (generally considered a
325
- bad idea), you don't need to use the PostgreSQL citext extension. Just
326
- remember to modify the migration below to use +String+ instead of +citext+
327
- for the email in that case.
328
-
329
- === Grant schema rights (PostgreSQL 15+)
330
-
331
- PostgreSQL 15 changed default database security so that only the database
332
- owner has writable access to the public schema. Rodauth expects the
333
- +ph+ account to have writable access to the public schema when setting
334
- things up. Temporarily grant that access (it will be revoked after the
335
- migration has run)
336
-
337
- psql -U postgres -c "GRANT CREATE ON SCHEMA public TO ${DATABASE_NAME}_password" ${DATABASE_NAME}
338
-
339
- === Using non-default schema
340
-
341
- PostgreSQL sets up new tables in the public schema by default.
342
- If you would like to use separate schemas per user, you can do:
343
-
344
- psql -U postgres -c "DROP SCHEMA public;" ${DATABASE_NAME}
345
- psql -U postgres -c "CREATE SCHEMA AUTHORIZATION ${DATABASE_NAME};" ${DATABASE_NAME}
346
- psql -U postgres -c "CREATE SCHEMA AUTHORIZATION ${DATABASE_NAME}_password;" ${DATABASE_NAME}
347
- psql -U postgres -c "GRANT USAGE ON SCHEMA ${DATABASE_NAME} TO ${DATABASE_NAME}_password;" ${DATABASE_NAME}
348
- psql -U postgres -c "GRANT USAGE ON SCHEMA ${DATABASE_NAME}_password TO ${DATABASE_NAME};" ${DATABASE_NAME}
349
-
350
- You'll need to modify the code to load the extension to specify the schema:
351
-
352
- psql -U postgres -c "CREATE EXTENSION citext SCHEMA ${DATABASE_NAME}" ${DATABASE_NAME}
353
-
354
- When running the migration for the +ph+ user you'll need to modify a couple
355
- things for the schema changes:
356
-
357
- create_table(:account_password_hashes) do
358
- foreign_key :id, Sequel[:${DATABASE_NAME}][:accounts], primary_key: true, type: :Bignum
359
- String :password_hash, null: false
360
- end
361
- Rodauth.create_database_authentication_functions(self, table_name: Sequel[:${DATABASE_NAME}_password][:account_password_hashes])
362
-
363
- # if using the disallow_password_reuse feature:
364
- create_table(:account_previous_password_hashes) do
365
- primary_key :id, type: :Bignum
366
- foreign_key :account_id, Sequel[:${DATABASE_NAME}][:accounts], type: :Bignum
367
- String :password_hash, null: false
368
- end
369
- Rodauth.create_database_previous_password_check_functions(self, table_name: Sequel[:${DATABASE_NAME}_password][:account_previous_password_hashes])
370
-
371
- You'll also need to use the following Rodauth configuration methods so that the
372
- app account calls functions in a separate schema:
373
-
374
- function_name do |name|
375
- "${DATABASE_NAME}_password.#{name}"
376
- end
377
- password_hash_table Sequel[:${DATABASE_NAME}_password][:account_password_hashes]
378
-
379
- # if using the disallow_password_reuse feature:
380
- previous_password_hash_table Sequel[:${DATABASE_NAME}_password][:account_previous_password_hashes]
381
-
382
- == MySQL Database Setup
383
-
384
- MySQL does not have the concept of object owners, and MySQL's GRANT/REVOKE
385
- support is much more limited than PostgreSQL's. When using MySQL, it is
386
- recommended to GRANT the +ph+ account ALL privileges on the database,
387
- including the ability to GRANT permissions to the +app+ account:
388
-
389
- CREATE USER '${DATABASE_NAME}'@'localhost' IDENTIFIED BY '${PASSWORD}';
390
- CREATE USER '${DATABASE_NAME}_password'@'localhost' IDENTIFIED BY '${OTHER_PASSWORD}';
391
- GRANT ALL ON ${DATABASE_NAME}.* TO '${DATABASE_NAME}_password'@'localhost' WITH GRANT OPTION;
392
-
393
- You should run all migrations as the +ph+ account, and GRANT specific access
394
- to the +app+ account as needed.
395
-
396
- Adding the database functions on MySQL may require setting the
397
- <tt>log_bin_trust_function_creators=1</tt> setting in the MySQL configuration.
398
-
399
- == Microsoft SQL Server Database Setup
400
-
401
- Microsoft SQL Server has a concept of database owners, but similar to MySQL
402
- usage it's recommended to use the +ph+ account as the superuser for the
403
- database, and have it GRANT permissions to the +app+ account:
404
-
405
- CREATE LOGIN rodauth_test WITH PASSWORD = 'rodauth_test';
406
- CREATE LOGIN rodauth_test_password WITH PASSWORD = 'rodauth_test';
407
- CREATE DATABASE rodauth_test;
408
- USE rodauth_test;
409
- CREATE USER rodauth_test FOR LOGIN rodauth_test;
410
- GRANT CONNECT, EXECUTE TO rodauth_test;
411
- EXECUTE sp_changedbowner 'rodauth_test_password';
412
-
413
- You should run all migrations as the +ph+ account, and GRANT specific access
414
- to the +app+ account as needed.
415
-
416
- == Creating tables
417
-
418
- Because two different database accounts are used, two different migrations
419
- are required, one for each database account. Here are example migrations.
420
- You can modify them to add support for additional columns, or remove tables
421
- or columns related to features that you don't need.
422
-
423
- First migration. On PostgreSQL, this should be run with the +app+ account,
424
- on MySQL and Microsoft SQL Server this should be run with the +ph+ account.
425
-
426
- Note that these migrations require Sequel 4.35.0+.
427
-
428
- Sequel.migration do
429
- up do
430
- extension :date_arithmetic
431
-
432
- # Used by the account verification and close account features
433
- create_table(:account_statuses) do
434
- Integer :id, primary_key: true
435
- String :name, null: false, unique: true
436
- end
437
- from(:account_statuses).import([:id, :name], [[1, 'Unverified'], [2, 'Verified'], [3, 'Closed']])
438
-
439
- db = self
440
- create_table(:accounts) do
441
- primary_key :id, type: :Bignum
442
- foreign_key :status_id, :account_statuses, null: false, default: 1
443
- if db.database_type == :postgres
444
- citext :email, null: false
445
- constraint :valid_email, email: /^[^,;@ \r\n]+@[^,@; \r\n]+\.[^,@; \r\n]+$/
446
- else
447
- String :email, null: false
448
- end
449
- if db.supports_partial_indexes?
450
- index :email, unique: true, where: {status_id: [1, 2]}
451
- else
452
- index :email, unique: true
453
- end
454
- end
455
-
456
- deadline_opts = proc do |days|
457
- if database_type == :mysql
458
- {null: false}
459
- else
460
- {null: false, default: Sequel.date_add(Sequel::CURRENT_TIMESTAMP, days: days)}
461
- end
462
- end
463
-
464
- # Used by the audit logging feature
465
- json_type = case database_type
466
- when :postgres
467
- :jsonb
468
- when :sqlite, :mysql
469
- :json
470
- else
471
- String
472
- end
473
- create_table(:account_authentication_audit_logs) do
474
- primary_key :id, type: :Bignum
475
- foreign_key :account_id, :accounts, null: false, type: :Bignum
476
- DateTime :at, null: false, default: Sequel::CURRENT_TIMESTAMP
477
- String :message, null: false
478
- column :metadata, json_type
479
- index [:account_id, :at], name: :audit_account_at_idx
480
- index :at, name: :audit_at_idx
481
- end
482
-
483
- # Used by the password reset feature
484
- create_table(:account_password_reset_keys) do
485
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
486
- String :key, null: false
487
- DateTime :deadline, deadline_opts[1]
488
- DateTime :email_last_sent, null: false, default: Sequel::CURRENT_TIMESTAMP
489
- end
490
-
491
- # Used by the jwt refresh feature
492
- create_table(:account_jwt_refresh_keys) do
493
- primary_key :id, type: :Bignum
494
- foreign_key :account_id, :accounts, null: false, type: :Bignum
495
- String :key, null: false
496
- DateTime :deadline, deadline_opts[1]
497
- index :account_id, name: :account_jwt_rk_account_id_idx
498
- end
499
-
500
- # Used by the account verification feature
501
- create_table(:account_verification_keys) do
502
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
503
- String :key, null: false
504
- DateTime :requested_at, null: false, default: Sequel::CURRENT_TIMESTAMP
505
- DateTime :email_last_sent, null: false, default: Sequel::CURRENT_TIMESTAMP
506
- end
507
-
508
- # Used by the verify login change feature
509
- create_table(:account_login_change_keys) do
510
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
511
- String :key, null: false
512
- String :login, null: false
513
- DateTime :deadline, deadline_opts[1]
514
- end
515
-
516
- # Used by the remember me feature
517
- create_table(:account_remember_keys) do
518
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
519
- String :key, null: false
520
- DateTime :deadline, deadline_opts[14]
521
- end
522
-
523
- # Used by the lockout feature
524
- create_table(:account_login_failures) do
525
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
526
- Integer :number, null: false, default: 1
527
- end
528
- create_table(:account_lockouts) do
529
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
530
- String :key, null: false
531
- DateTime :deadline, deadline_opts[1]
532
- DateTime :email_last_sent
533
- end
534
-
535
- # Used by the email auth feature
536
- create_table(:account_email_auth_keys) do
537
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
538
- String :key, null: false
539
- DateTime :deadline, deadline_opts[1]
540
- DateTime :email_last_sent, null: false, default: Sequel::CURRENT_TIMESTAMP
541
- end
542
-
543
- # Used by the password expiration feature
544
- create_table(:account_password_change_times) do
545
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
546
- DateTime :changed_at, null: false, default: Sequel::CURRENT_TIMESTAMP
547
- end
548
-
549
- # Used by the account expiration feature
550
- create_table(:account_activity_times) do
551
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
552
- DateTime :last_activity_at, null: false
553
- DateTime :last_login_at, null: false
554
- DateTime :expired_at
555
- end
556
-
557
- # Used by the single session feature
558
- create_table(:account_session_keys) do
559
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
560
- String :key, null: false
561
- end
562
-
563
- # Used by the active sessions feature
564
- create_table(:account_active_session_keys) do
565
- foreign_key :account_id, :accounts, type: :Bignum
566
- String :session_id
567
- Time :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
568
- Time :last_use, null: false, default: Sequel::CURRENT_TIMESTAMP
569
- primary_key [:account_id, :session_id]
570
- end
571
-
572
- # Used by the webauthn feature
573
- create_table(:account_webauthn_user_ids) do
574
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
575
- String :webauthn_id, null: false
576
- end
577
- create_table(:account_webauthn_keys) do
578
- foreign_key :account_id, :accounts, type: :Bignum
579
- String :webauthn_id
580
- String :public_key, null: false
581
- Integer :sign_count, null: false
582
- Time :last_use, null: false, default: Sequel::CURRENT_TIMESTAMP
583
- primary_key [:account_id, :webauthn_id]
584
- end
585
-
586
- # Used by the otp feature
587
- create_table(:account_otp_keys) do
588
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
589
- String :key, null: false
590
- Integer :num_failures, null: false, default: 0
591
- Time :last_use, null: false, default: Sequel::CURRENT_TIMESTAMP
592
- end
593
-
594
- # Used by the otp_unlock feature
595
- create_table(:account_otp_unlocks) do
596
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
597
- Integer :num_successes, null: false, default: 1
598
- Time :next_auth_attempt_after, null: false, default: Sequel::CURRENT_TIMESTAMP
599
- end
600
-
601
- # Used by the recovery codes feature
602
- create_table(:account_recovery_codes) do
603
- foreign_key :id, :accounts, type: :Bignum
604
- String :code
605
- primary_key [:id, :code]
606
- end
607
-
608
- # Used by the sms codes feature
609
- create_table(:account_sms_codes) do
610
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
611
- String :phone_number, null: false
612
- Integer :num_failures
613
- String :code
614
- DateTime :code_issued_at, null: false, default: Sequel::CURRENT_TIMESTAMP
615
- end
616
-
617
- case database_type
618
- when :postgres
619
- user = get(Sequel.lit('current_user')) + '_password'
620
- run "GRANT REFERENCES ON accounts TO #{user}"
621
- when :mysql, :mssql
622
- user = if database_type == :mysql
623
- get(Sequel.lit('current_user')).sub(/_password@/, '@')
624
- else
625
- get(Sequel.function(:DB_NAME))
626
- end
627
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_statuses TO #{user}"
628
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON accounts TO #{user}"
629
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_authentication_audit_logs TO #{user}"
630
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_password_reset_keys TO #{user}"
631
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_jwt_refresh_keys TO #{user}"
632
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_verification_keys TO #{user}"
633
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_login_change_keys TO #{user}"
634
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_remember_keys TO #{user}"
635
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_login_failures TO #{user}"
636
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_email_auth_keys TO #{user}"
637
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_lockouts TO #{user}"
638
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_password_change_times TO #{user}"
639
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_activity_times TO #{user}"
640
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_session_keys TO #{user}"
641
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_active_session_keys TO #{user}"
642
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_webauthn_user_ids TO #{user}"
643
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_webauthn_keys TO #{user}"
644
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_otp_keys TO #{user}"
645
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_otp_unlocks TO #{user}"
646
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_recovery_codes TO #{user}"
647
- run "GRANT SELECT, INSERT, UPDATE, DELETE ON account_sms_codes TO #{user}"
648
- end
649
- end
650
-
651
- down do
652
- drop_table(:account_sms_codes,
653
- :account_recovery_codes,
654
- :account_otp_unlocks,
655
- :account_otp_keys,
656
- :account_webauthn_keys,
657
- :account_webauthn_user_ids,
658
- :account_session_keys,
659
- :account_active_session_keys,
660
- :account_activity_times,
661
- :account_password_change_times,
662
- :account_email_auth_keys,
663
- :account_lockouts,
664
- :account_login_failures,
665
- :account_remember_keys,
666
- :account_login_change_keys,
667
- :account_verification_keys,
668
- :account_jwt_refresh_keys,
669
- :account_password_reset_keys,
670
- :account_authentication_audit_logs,
671
- :accounts,
672
- :account_statuses)
673
- end
674
- end
675
-
676
- Second migration, run using the +ph+ account:
677
-
678
- require 'rodauth/migrations'
679
-
680
- Sequel.migration do
681
- up do
682
- create_table(:account_password_hashes) do
683
- foreign_key :id, :accounts, primary_key: true, type: :Bignum
684
- String :password_hash, null: false
685
- end
686
- Rodauth.create_database_authentication_functions(self)
687
- case database_type
688
- when :postgres
689
- user = get(Sequel.lit('current_user')).sub(/_password\z/, '')
690
- run "REVOKE ALL ON account_password_hashes FROM public"
691
- run "REVOKE ALL ON FUNCTION rodauth_get_salt(int8) FROM public"
692
- run "REVOKE ALL ON FUNCTION rodauth_valid_password_hash(int8, text) FROM public"
693
- run "GRANT INSERT, UPDATE, DELETE ON account_password_hashes TO #{user}"
694
- run "GRANT SELECT(id) ON account_password_hashes TO #{user}"
695
- run "GRANT EXECUTE ON FUNCTION rodauth_get_salt(int8) TO #{user}"
696
- run "GRANT EXECUTE ON FUNCTION rodauth_valid_password_hash(int8, text) TO #{user}"
697
- when :mysql
698
- user = get(Sequel.lit('current_user')).sub(/_password@/, '@')
699
- db_name = get(Sequel.function(:database))
700
- run "GRANT EXECUTE ON #{db_name}.* TO #{user}"
701
- run "GRANT INSERT, UPDATE, DELETE ON account_password_hashes TO #{user}"
702
- run "GRANT SELECT (id) ON account_password_hashes TO #{user}"
703
- when :mssql
704
- user = get(Sequel.function(:DB_NAME))
705
- run "GRANT EXECUTE ON rodauth_get_salt TO #{user}"
706
- run "GRANT EXECUTE ON rodauth_valid_password_hash TO #{user}"
707
- run "GRANT INSERT, UPDATE, DELETE ON account_password_hashes TO #{user}"
708
- run "GRANT SELECT ON account_password_hashes(id) TO #{user}"
709
- end
710
-
711
- # Used by the disallow_password_reuse feature
712
- create_table(:account_previous_password_hashes) do
713
- primary_key :id, type: :Bignum
714
- foreign_key :account_id, :accounts, type: :Bignum
715
- String :password_hash, null: false
716
- end
717
- Rodauth.create_database_previous_password_check_functions(self)
718
-
719
- case database_type
720
- when :postgres
721
- user = get(Sequel.lit('current_user')).sub(/_password\z/, '')
722
- run "REVOKE ALL ON account_previous_password_hashes FROM public"
723
- run "REVOKE ALL ON FUNCTION rodauth_get_previous_salt(int8) FROM public"
724
- run "REVOKE ALL ON FUNCTION rodauth_previous_password_hash_match(int8, text) FROM public"
725
- run "GRANT INSERT, UPDATE, DELETE ON account_previous_password_hashes TO #{user}"
726
- run "GRANT SELECT(id, account_id) ON account_previous_password_hashes TO #{user}"
727
- run "GRANT USAGE ON account_previous_password_hashes_id_seq TO #{user}"
728
- run "GRANT EXECUTE ON FUNCTION rodauth_get_previous_salt(int8) TO #{user}"
729
- run "GRANT EXECUTE ON FUNCTION rodauth_previous_password_hash_match(int8, text) TO #{user}"
730
- when :mysql
731
- user = get(Sequel.lit('current_user')).sub(/_password@/, '@')
732
- db_name = get(Sequel.function(:database))
733
- run "GRANT EXECUTE ON #{db_name}.* TO #{user}"
734
- run "GRANT INSERT, UPDATE, DELETE ON account_previous_password_hashes TO #{user}"
735
- run "GRANT SELECT (id, account_id) ON account_previous_password_hashes TO #{user}"
736
- when :mssql
737
- user = get(Sequel.function(:DB_NAME))
738
- run "GRANT EXECUTE ON rodauth_get_previous_salt TO #{user}"
739
- run "GRANT EXECUTE ON rodauth_previous_password_hash_match TO #{user}"
740
- run "GRANT INSERT, UPDATE, DELETE ON account_previous_password_hashes TO #{user}"
741
- run "GRANT SELECT ON account_previous_password_hashes(id, account_id) TO #{user}"
742
- end
743
- end
744
-
745
- down do
746
- Rodauth.drop_database_previous_password_check_functions(self)
747
- Rodauth.drop_database_authentication_functions(self)
748
- drop_table(:account_previous_password_hashes, :account_password_hashes)
749
- end
750
- end
751
-
752
- To support multiple separate migration users, you can run the migration
753
- for the password user using Sequel's migration API:
754
-
755
- Sequel.extension :migration
756
- Sequel.postgres('DATABASE_NAME', user: 'PASSWORD_USER_NAME') do |db|
757
- Sequel::Migrator.run(db, 'path/to/password_user/migrations', table: 'schema_info_password')
758
- end
759
-
760
- If the database is not PostgreSQL, MySQL, or Microsoft SQL Server, or you
761
- cannot use multiple user accounts, just combine the two migrations into a
762
- single migration, removing all the code related to database permissions
763
- and database functions.
764
-
765
- One thing to notice in the above migrations is that Rodauth uses additional
766
- tables for additional features, instead of additional columns in a single
767
- table.
768
-
769
- === Revoking schema rights (PostgreSQL 15+)
770
-
771
- If you explicit granted access to the public schema before running the
772
- migration, revoke it afterward:
773
-
774
- psql -U postgres -c "REVOKE CREATE ON SCHEMA public FROM ${DATABASE_NAME}_password" ${DATABASE_NAME}
775
-
776
- === Locking Down (PostgreSQL only)
777
-
778
- After running the migrations, you can increase security slightly by making
779
- it not possible for the +ph+ account to login to the database directly.
780
- This can be accomplished by modifying the +pg_hba.conf+ file. You can also
781
- consider restricting access using GRANT/REVOKE.
782
-
783
- You can restrict access to the database itself to just the +app+ account. You
784
- can run this using the +app+ account, since that account owns the database:
785
-
786
- GRANT ALL ON DATABASE ${DATABASE_NAME} TO ${DATABASE_NAME};
787
- REVOKE ALL ON DATABASE ${DATABASE_NAME} FROM public;
788
-
789
- You can also restrict access to the public schema (this is not needed if you
790
- are using a custom schema). Note that by default, the database superuser
791
- owns the public schema, so you have to run this as the database superuser
792
- account (generally +postgres+):
793
-
794
- GRANT ALL ON SCHEMA public TO ${DATABASE_NAME};
795
- GRANT USAGE ON SCHEMA public TO ${DATABASE_NAME}_password;
796
- REVOKE ALL ON SCHEMA public FROM public;
797
-
798
- If you are using MySQL or Microsoft SQL Server, please consult their
799
- documentation for how to restrict access so that the +ph+ account cannot
800
- login directly.
801
-
802
- == Usage
803
-
804
- === Basic Usage
805
-
806
- Rodauth is a Roda plugin and loaded the same way other Roda plugins
807
- are loaded:
808
-
809
- plugin :rodauth do
810
- end
811
-
812
- The block passed to the plugin call uses the Rodauth configuration DSL.
813
- The one configuration method that should always be used is +enable+,
814
- which chooses which features you would like to load:
815
-
816
- plugin :rodauth do
817
- enable :login, :logout
818
- end
819
-
820
- Once features are loaded, you can use any of the configuration methods
821
- supported by the features. There are two types of configuration
822
- methods. The first type are called auth methods, and they take a
823
- block which overrides the default method that Rodauth uses. Inside the
824
- block, you can call super if you want to get the default behavior, though
825
- you must provide explicit arguments to super. There is no need to
826
- call super in before or after hooks, though. For example, if you want to
827
- add additional logging when a user logs in:
828
-
829
- plugin :rodauth do
830
- enable :login, :logout
831
- after_login do
832
- LOGGER.info "#{account[:email]} logged in!"
833
- end
834
- end
835
-
836
- Inside the block, you are in the context of the Rodauth::Auth
837
- instance related to the request. This object has access to everything
838
- related to the request via methods:
839
-
840
- request :: RodaRequest instance
841
- response :: RodaResponse instance
842
- scope :: Roda instance
843
- session :: session hash
844
- flash :: flash message hash
845
- account :: account hash (if set by an earlier Rodauth method)
846
- current_route :: route name symbol (if Rodauth is handling the route)
847
-
848
- So if you want to log the IP address for the user during login:
849
-
850
- plugin :rodauth do
851
- enable :login, :logout
852
- after_login do
853
- LOGGER.info "#{account[:email]} logged in from #{request.ip}"
854
- end
855
- end
856
-
857
- The second type of configuration methods are called auth value
858
- methods. They are similar to auth methods, but instead of just
859
- accepting a block, they can optionally accept a single argument
860
- without a block, which will be treated as a block that just returns
861
- that value. For example, the accounts_table method sets the database
862
- table storing accounts, so to override it, you can call the method
863
- with a symbol for the table:
864
-
865
- plugin :rodauth do
866
- enable :login, :logout
867
- accounts_table :users
868
- end
869
-
870
- Note that all auth value methods can still take a block, allowing
871
- overriding for all behavior, using any information from the request:
872
-
873
- plugin :rodauth do
874
- enable :login, :logout
875
- accounts_table do
876
- request.ip.start_with?("192.168.1.") ? :admins : :users
877
- end
878
- end
879
-
880
- By allowing every configuration method to take a block, Rodauth
881
- should be flexible enough to integrate into most legacy systems.
882
-
883
- === Plugin Options
884
-
885
- When loading the rodauth plugin, you can also pass an options hash,
886
- which configures which dependent plugins should be loaded. Options:
887
-
888
- :csrf :: Set to +false+ to not load a csrf plugin. Set to +:rack_csrf+
889
- to use the csrf plugin instead of the route_csrf plugin.
890
- :flash :: Set to +false+ to not load the flash plugin
891
- :render :: Set to +false+ to not load the render plugin. This is useful
892
- to avoid the dependency on tilt when using alternative view libaries.
893
- :json :: Set to +true+ to load the json and json_parser plugins. Set
894
- to +:only+ to only load those plugins and not any other plugins.
895
- Note that if you are enabling features that send email, you
896
- still need to load the render plugin manually.
897
- :name :: Provide a name for the given Rodauth configuration, used to
898
- support multiple Rodauth configurations in a given Roda application.
899
- :auth_class :: Provide a specific Rodauth::Auth subclass that should be set
900
- on the Roda application. By default, an anonymous
901
- Rodauth::Auth subclass is created.
902
-
903
- === Feature Documentation
904
-
905
- The options/methods for the supported features are listed on a
906
- separate page per feature. If these links are not active, please
907
- view the appropriate file in the doc directory.
908
-
909
- * {Base}[rdoc-ref:doc/base.rdoc] (this feature is autoloaded)
910
- * {Login Password Requirements Base}[rdoc-ref:doc/login_password_requirements_base.rdoc] (this feature is autoloaded by features that set logins/passwords)
911
- * {Email Base}[rdoc-ref:doc/email_base.rdoc] (this feature is autoloaded by features that send email)
912
- * {Two Factor Base}[rdoc-ref:doc/two_factor_base.rdoc] (this feature is autoloaded by 2 factor authentication features)
913
- * {Account Expiration}[rdoc-ref:doc/account_expiration.rdoc]
914
- * {Active Sessions}[rdoc-ref:doc/active_sessions.rdoc]
915
- * {Audit Logging}[rdoc-ref:doc/audit_logging.rdoc]
916
- * {Argon2}[rdoc-ref:doc/argon2.rdoc]
917
- * {Change Login}[rdoc-ref:doc/change_login.rdoc]
918
- * {Change Password}[rdoc-ref:doc/change_password.rdoc]
919
- * {Change Password Notify}[rdoc-ref:doc/change_password_notify.rdoc]
920
- * {Close Account}[rdoc-ref:doc/close_account.rdoc]
921
- * {Confirm Password}[rdoc-ref:doc/confirm_password.rdoc]
922
- * {Create Account}[rdoc-ref:doc/create_account.rdoc]
923
- * {Disallow Common Passwords}[rdoc-ref:doc/disallow_common_passwords.rdoc]
924
- * {Disallow Password Reuse}[rdoc-ref:doc/disallow_password_reuse.rdoc]
925
- * {Email Authentication}[rdoc-ref:doc/email_auth.rdoc]
926
- * {HTTP Basic Auth}[rdoc-ref:doc/http_basic_auth.rdoc]
927
- * {Internal Request}[rdoc-ref:doc/internal_request.rdoc]
928
- * {JSON}[rdoc-ref:doc/json.rdoc]
929
- * {JWT CORS}[rdoc-ref:doc/jwt_cors.rdoc]
930
- * {JWT Refresh}[rdoc-ref:doc/jwt_refresh.rdoc]
931
- * {JWT}[rdoc-ref:doc/jwt.rdoc]
932
- * {Lockout}[rdoc-ref:doc/lockout.rdoc]
933
- * {Login}[rdoc-ref:doc/login.rdoc]
934
- * {Logout}[rdoc-ref:doc/logout.rdoc]
935
- * {OTP}[rdoc-ref:doc/otp.rdoc]
936
- * {OTP Lockout Email}[rdoc-ref:doc/otp_lockout_email.rdoc]
937
- * {OTP Modify Email}[rdoc-ref:doc/otp_modify_email.rdoc]
938
- * {OTP Unlock}[rdoc-ref:doc/otp_unlock.rdoc]
939
- * {Password Complexity}[rdoc-ref:doc/password_complexity.rdoc]
940
- * {Password Expiration}[rdoc-ref:doc/password_expiration.rdoc]
941
- * {Password Grace Period}[rdoc-ref:doc/password_grace_period.rdoc]
942
- * {Password Pepper}[rdoc-ref:doc/password_pepper.rdoc]
943
- * {Path Class Methods}[rdoc-ref:doc/path_class_methods.rdoc]
944
- * {Recovery Codes}[rdoc-ref:doc/recovery_codes.rdoc]
945
- * {Remember}[rdoc-ref:doc/remember.rdoc]
946
- * {Reset Password}[rdoc-ref:doc/reset_password.rdoc]
947
- * {Reset Password Notify}[rdoc-ref:doc/reset_password_notify.rdoc]
948
- * {Session Expiration}[rdoc-ref:doc/session_expiration.rdoc]
949
- * {Single Session}[rdoc-ref:doc/single_session.rdoc]
950
- * {SMS Codes}[rdoc-ref:doc/sms_codes.rdoc]
951
- * {Update Password Hash}[rdoc-ref:doc/update_password_hash.rdoc]
952
- * {Verify Account}[rdoc-ref:doc/verify_account.rdoc]
953
- * {Verify Account Grace Period}[rdoc-ref:doc/verify_account_grace_period.rdoc]
954
- * {Verify Login Change}[rdoc-ref:doc/verify_login_change.rdoc]
955
- * {WebAuthn}[rdoc-ref:doc/webauthn.rdoc]
956
- * {WebAuthn Autofill}[rdoc-ref:doc/webauthn_autofill.rdoc]
957
- * {WebAuthn Login}[rdoc-ref:doc/webauthn_login.rdoc]
958
- * {WebAuthn Modify Email}[rdoc-ref:doc/webauthn_modify_email.rdoc]
959
- * {WebAuthn Verify Account}[rdoc-ref:doc/webauthn_verify_account.rdoc]
960
-
961
- === Calling Rodauth in the Routing Tree
962
-
963
- In general, you will usually want to call +r.rodauth+ early in your
964
- route block:
965
-
966
- route do |r|
967
- r.rodauth
968
-
969
- # ...
970
- end
971
-
972
- Note that will allow Rodauth to run, but it won't force people
973
- to login or add any security to your site. If you want to force
974
- all users to login, you need to redirect to them login page if
975
- they are not already logged in:
976
-
977
- route do |r|
978
- r.rodauth
979
- rodauth.require_authentication
980
-
981
- # ...
982
- end
983
-
984
- If only certain parts of your site require logins, then you can
985
- only redirect if they are not logged in certain branches of the
986
- routing tree:
987
-
988
- route do |r|
989
- r.rodauth
990
-
991
- r.on "admin" do
992
- rodauth.require_authentication
993
-
994
- # ...
995
- end
996
-
997
- # ...
998
- end
999
-
1000
- In some cases you may want to have rodauth run inside a branch of
1001
- the routing tree, instead of in the root. You can do this by
1002
- setting a +:prefix+ when configuring Rodauth, and calling +r.rodauth+
1003
- inside a matching routing tree branch:
1004
-
1005
- plugin :rodauth do
1006
- enable :login, :logout
1007
- prefix "/auth"
1008
- end
1009
-
1010
- route do |r|
1011
- r.on "auth" do
1012
- r.rodauth
1013
- end
1014
-
1015
- rodauth.require_authentication
1016
-
1017
- # ...
1018
- end
1019
-
1020
- === +rodauth+ Methods
1021
-
1022
- Most of Rodauth's functionality is exposed via +r.rodauth+, which allows
1023
- Rodauth to handle routes for the features you have enabled (such as +/login+
1024
- for login). However, as you have seen above, you may want to call methods on
1025
- the +rodauth+ object, such as for checking if the current request has been
1026
- authenticated.
1027
-
1028
- Here are methods designed to be callable on the +rodauth+ object outside
1029
- +r.rodauth+:
1030
-
1031
- require_login :: Require the session be logged in, redirecting the request to the
1032
- login page if the request has not been logged in.
1033
- require_authentication :: Similar to +require_login+, but also requires
1034
- two factor authentication if the account has setup
1035
- two factor authentication. Redirects the request to
1036
- the two factor authentication page if logged in but not
1037
- authenticated via two factors.
1038
- require_account :: Similar to +require_authentication+, but also loads the logged
1039
- in account to ensure it exists in the database. If the account
1040
- doesn't exist, or if it exists but isn't verified, the session
1041
- is cleared and the request redirected to the login page.
1042
- logged_in? :: Whether the session has been logged in.
1043
- authenticated? :: Similar to +logged_in?+, but if the account has setup two
1044
- factor authentication, whether the session has authenticated
1045
- via two factors.
1046
- account! :: Returns the current account record if it has already been loaded,
1047
- otherwise retrieves the account from session if logged in.
1048
- authenticated_by :: An array of strings for successful authentication methods for
1049
- the current session (e.g. password/remember/webauthn).
1050
- possible_authentication_methods :: An array of strings for possible authentication
1051
- types that can be used for the account.
1052
- autologin_type :: If the current session was authenticated via autologin, the
1053
- type of autologin used.
1054
- require_two_factor_setup :: (two_factor_base feature) Require the session to have
1055
- setup two factor authentication, redirecting the
1056
- request to the two factor authentication setup page
1057
- if not.
1058
- uses_two_factor_authentication? :: (two_factor_base feature) Whether the account
1059
- for the current session has setup two factor
1060
- authentication.
1061
- update_last_activity :: (account_expiration feature) Update the last activity
1062
- time for the current account. Only makes sense to use
1063
- this if you are expiring accounts based on last activity.
1064
- require_current_password :: (password_expiration feature) Require a current
1065
- password, redirecting the request to the change
1066
- password page if the password for the account has
1067
- expired.
1068
- require_password_authentication :: (confirm_password feature) If not authenticated
1069
- via password and the account has a password,
1070
- redirect to the password confirmation page,
1071
- saving the current location to redirect back
1072
- to after password has been successfully
1073
- confirmed. If the password_grace_period feature
1074
- is used, also redirect if the password has not
1075
- been recently entered.
1076
- load_memory :: (remember feature) If the session has not been authenticated, look
1077
- for the remember cookie. If present and valid, automatically
1078
- log the session in, but mark that it was logged in via a remember
1079
- key.
1080
- logged_in_via_remember_key? :: (remember feature) Whether the current session has
1081
- been logged in via a remember key. For security
1082
- sensitive actions where you want to require the user
1083
- to reenter the password, you can use the
1084
- confirm_password feature.
1085
- http_basic_auth :: (http_basic_auth feature) Use HTTP Basic Authentication information
1086
- to login the user if provided.
1087
- require_http_basic_auth :: (http_basic_auth feature) Require that HTTP Basic
1088
- Authentication be provided in the request.
1089
- check_session_expiration :: (session_expiration feature) Check whether the current
1090
- session has expired, automatically logging the session
1091
- out if so.
1092
- check_active_session :: (active_sessions feature) Check whether the current session
1093
- is still active, automatically logging the session out if not.
1094
- check_single_session :: (single_session feature) Check whether the current
1095
- session is still the only valid session, automatically logging
1096
- the session out if not.
1097
- verified_account? :: (verify_grace_period feature) Whether the account is currently
1098
- verified. If false, it is because the account is allowed to
1099
- login as they are in the grace period.
1100
- locked_out? :: (lockout feature) Whether the account for the current session has been
1101
- locked out.
1102
- authenticated_webauthn_id :: (webauthn feature) If the current session was
1103
- authenticated via webauthn, the webauthn id of the
1104
- credential used.
1105
- *_path :: One of these is added for each of the routes added by Rodauth, giving the
1106
- relative path to the route. Any options passed to this method will be
1107
- converted into query parameters.
1108
- *_url :: One of these is added for each of the routes added by Rodauth, giving the
1109
- URL to the route. Any options passed to this method will be converted
1110
- into query parameters.
1111
-
1112
- === Calling Rodauth Methods for Other Accounts
1113
-
1114
- In some cases, you may want to interact with Rodauth directly on behalf
1115
- of a user. For example, let's say you want to create accounts or change passwords
1116
- for existing accounts. Using Rodauth's internal_request feature, you can do this
1117
- by:
1118
-
1119
- plugin :rodauth do
1120
- enable :create_account, :change_password, :internal_request
1121
- end
1122
- rodauth.create_account(login: 'foo@example.com', password: '...')
1123
- rodauth.change_password(account_id: 24601, password: '...')
1124
-
1125
- Here the +rodauth+ method is called as the Roda class level, which returns
1126
- the appropriate <tt>Rodauth::Auth</tt> subclass. You call internal request
1127
- methods on that class to perform actions on behalf of a user. See the
1128
- {internal request feature documentation}[rdoc-ref:doc/internal_request.rdoc]
1129
- for details.
1130
-
1131
- == Using Rodauth as a Library
1132
-
1133
- Rodauth was designed to serve as an authentication framework for Rack applications.
1134
- However, Rodauth can be used purely as a library outside of a web application. You
1135
- can do this by requiring +rodauth+, and using the +Rodauth.lib+ method to return
1136
- a <tt>Rodauth::Auth</tt> subclass, which you can call methods on. You pass the
1137
- +Rodauth.lib+ method an optional hash of Rodauth plugin options and a Rodauth
1138
- configuration block:
1139
-
1140
- require 'rodauth'
1141
- rodauth = Rodauth.lib do
1142
- enable :create_account, :change_password
1143
- end
1144
- rodauth.create_account(login: 'foo@example.com', password: '...')
1145
- rodauth.change_password(account_id: 24601, password: '...')
1146
-
1147
- This supports builds on top of the internal_request support (it implicitly loads
1148
- the internal_request feature before processing the configuration block), and
1149
- allows the use of Rodauth in non-web applications. Note that you still have to
1150
- setup a Sequel::Database connection for Rodauth to use for data storage.
1151
-
1152
- === With Multiple Configurations
1153
-
1154
- Rodauth supports using multiple rodauth configurations in the same
1155
- application. You just need to load the plugin a second time,
1156
- providing a name for any alternate configuration:
1157
-
1158
- plugin :rodauth do
1159
- end
1160
- plugin :rodauth, name: :secondary do
1161
- end
1162
-
1163
- Then in your routing code, any time you call rodauth, you can provide
1164
- the name as an argument to use that configuration:
1165
-
1166
- route do |r|
1167
- r.on 'secondary' do
1168
- r.rodauth(:secondary)
1169
- end
1170
-
1171
- r.rodauth
1172
- end
1173
-
1174
- By default, alternate configurations will use the same session keys as the
1175
- primary configuration, which may be undesirable. To ensure session state is
1176
- separated between configurations, you can set a session key prefix for
1177
- alternate configurations. If you are using the remember feature in both
1178
- configurations, you may also want to set a different remember key in the
1179
- alternate configuration:
1180
-
1181
- plugin :rodauth, name: :secondary do
1182
- session_key_prefix "secondary_"
1183
- remember_cookie_key "_secondary_remember"
1184
- end
1185
-
1186
- === With Password Hashes Inside the Accounts Table
1187
-
1188
- You can use Rodauth if you are storing password hashes in the same
1189
- table as the accounts. You just need to specify which column
1190
- stores the password hash:
1191
-
1192
- plugin :rodauth do
1193
- account_password_hash_column :password_hash
1194
- end
1195
-
1196
- When this option is set, Rodauth will do the password hash check
1197
- in ruby.
1198
-
1199
- === When Using PostgreSQL/MySQL/Microsoft SQL Server without Database Functions
1200
-
1201
- If you want to use Rodauth on PostgreSQL, MySQL, or Microsoft SQL Server
1202
- without using database functions for authentication, but still storing password
1203
- hashes in a separate table, you can do so:
1204
-
1205
- plugin :rodauth do
1206
- use_database_authentication_functions? false
1207
- end
1208
-
1209
- Conversely, if you implement the rodauth_get_salt and
1210
- rodauth_valid_password_hash functions on a database that isn't
1211
- PostgreSQL, MySQL, or Microsoft SQL Server, you can set this value to true.
1212
-
1213
- === With Custom Authentication
1214
-
1215
- You can use Rodauth with other authentication types, by using some
1216
- of Rodauth's configuration methods.
1217
-
1218
- Note that when using custom authentication, using some of Rodauth's
1219
- features such as change login and change password either would not
1220
- make sense or would require some additional custom configuration.
1221
- The login and logout features should work correctly with the examples
1222
- below, though.
1223
-
1224
- ==== Using LDAP Authentication
1225
-
1226
- If you have accounts stored in the database, but authentication happens
1227
- via LDAP, you can use the +simple_ldap_authenticator+ library:
1228
-
1229
- require 'simple_ldap_authenticator'
1230
- plugin :rodauth do
1231
- enable :login, :logout
1232
- require_bcrypt? false
1233
- password_match? do |password|
1234
- SimpleLdapAuthenticator.valid?(account[:email], password)
1235
- end
1236
- end
1237
-
1238
- If you aren't storing accounts in the database, but want to allow
1239
- any valid LDAP user to login, you can do something like this:
1240
-
1241
- require 'simple_ldap_authenticator'
1242
- plugin :rodauth do
1243
- enable :login, :logout
1244
-
1245
- # Don't require the bcrypt library, since using LDAP for auth
1246
- require_bcrypt? false
1247
-
1248
- # Store session value in :login key, since the :account_id
1249
- # default wouldn't make sense
1250
- session_key :login
1251
-
1252
- # Use the login provided as the session value
1253
- account_session_value{account}
1254
-
1255
- # Treat the login itself as the account
1256
- account_from_login{|l| l.to_s}
1257
-
1258
- password_match? do |password|
1259
- SimpleLdapAuthenticator.valid?(account, password)
1260
- end
1261
- end
1262
-
1263
- ==== Using Facebook Authentication
1264
-
1265
- Here's an example of authentication using Facebook with a JSON API.
1266
- This setup assumes you have client-side code to submit JSON POST requests
1267
- to +/login+ with an +access_token+ parameter that is set to the user's
1268
- Facebook OAuth access token.
1269
-
1270
-
1271
- require 'koala'
1272
- plugin :rodauth do
1273
- enable :login, :logout, :jwt
1274
-
1275
- require_bcrypt? false
1276
- session_key :facebook_email
1277
- account_session_value{account}
1278
-
1279
- login_param 'access_token'
1280
-
1281
- account_from_login do |access_token|
1282
- fb = Koala::Facebook::API.new(access_token)
1283
- if me = fb.get_object('me', fields: [:email])
1284
- me['email']
1285
- end
1286
- end
1287
-
1288
- # there is no password!
1289
- password_match? do |pass|
1290
- true
1291
- end
1292
- end
1293
-
1294
- === With Rails
1295
-
1296
- If you're using Rails, you can use the
1297
- {rodauth-rails}[https://github.com/janko/rodauth-rails] gem which provides
1298
- Rails integration for Rodauth. Some of its features include:
1299
-
1300
- * generators for Rodauth & Sequel configuration, as well as views and mailers
1301
- * uses Rails' flash messages and CSRF protection
1302
- * automatically sets HMAC secret to Rails' secret key base
1303
- * uses Action Controller & Action View for rendering templates
1304
- * uses Action Mailer for sending emails
1305
-
1306
- Follow the instructions in the rodauth-rails README to get started.
1307
-
1308
- === With Other Web Frameworks
1309
-
1310
- You can use Rodauth even if your application does not use the Roda web
1311
- framework. This is possible by adding a Roda middleware that uses
1312
- Rodauth:
1313
-
1314
- require 'roda'
1315
-
1316
- class RodauthApp < Roda
1317
- plugin :middleware
1318
- plugin :rodauth do
1319
- enable :login
1320
- end
1321
-
1322
- route do |r|
1323
- r.rodauth
1324
- rodauth.require_authentication
1325
- env['rodauth'] = rodauth
1326
- end
1327
- end
1328
-
1329
- use RodauthApp
1330
-
1331
- Note that Rodauth expects the Roda app it is used in to provide a
1332
- layout. So if you are using Rodauth as middleware for another app,
1333
- if you don't have a +views/layout.erb+ file that Rodauth can use,
1334
- you should probably also add load Roda's +render+ plugin
1335
- with the appropriate settings that allow Rodauth to use the same
1336
- layout as the application.
1337
-
1338
- By setting <tt>env['rodauth'] = rodauth</tt> in the route block
1339
- inside the middleware, you can easily provide a way for your
1340
- application to call Rodauth methods.
1341
-
1342
- If you're using the remember feature with +extend_remember_deadline?+ set to
1343
- true, you'll want to load roda's middleware plugin with
1344
- <tt>forward_response_headers: true</tt> option, so that +Set-Cookie+ header changes
1345
- from the +load_memory+ call in the route block are propagated when the request
1346
- is forwarded to the main app.
1347
-
1348
- Here are some examples of integrating Rodauth into applications that
1349
- don't use Roda:
1350
-
1351
- * {Ginatra, a Sinatra-based git repository viewer}[https://github.com/jeremyevans/ginatra/commit/28108ebec96e8d42596ee55b01c3f7b50c155dd1]
1352
- * {Rodauth's demo site as a Rails 6 application}[https://github.com/janko/rodauth-demo-rails]
1353
- * {Grape application}[https://github.com/davydovanton/grape-rodauth]
1354
- * {Hanami application}[https://github.com/davydovanton/rodauth_hanami]
1355
-
1356
- === Using 2 Factor Authentication
1357
-
1358
- Rodauth ships with 2 factor authentication support via the following
1359
- methods:
1360
-
1361
- * WebAuthn
1362
- * TOTP (Time-Based One-Time Passwords, RFC 6238).
1363
- * SMS Codes
1364
- * Recovery Codes
1365
-
1366
- There are multiple ways to integrate 2 factor authentication with
1367
- Rodauth, based on the needs of the application. By default, SMS
1368
- codes and recovery codes are treated only as backup 2nd factors,
1369
- a user cannot enable them without first enabling another 2nd factor
1370
- authentication method. However, you can change this by using
1371
- a configuration method.
1372
-
1373
- If you want to support but not require 2 factor authentication:
1374
-
1375
- plugin :rodauth do
1376
- enable :login, :logout, :otp, :recovery_codes, :sms_codes
1377
- end
1378
- route do |r|
1379
- r.rodauth
1380
- rodauth.require_authentication
1381
-
1382
- # ...
1383
- end
1384
-
1385
- If you want to force all users to use 2 factor authentication, requiring users
1386
- that don't currently have two authentication to set it up:
1387
-
1388
- route do |r|
1389
- r.rodauth
1390
- rodauth.require_authentication
1391
- rodauth.require_two_factor_setup
1392
-
1393
- # ...
1394
- end
1395
-
1396
- Similarly to requiring authentication in general, it's possible to require
1397
- login authentication for most of the site, but require 2 factor
1398
- authentication only for particular branches:
1399
-
1400
- route do |r|
1401
- r.rodauth
1402
- rodauth.require_login
1403
-
1404
- r.on "admin" do
1405
- rodauth.require_two_factor_authenticated
1406
- end
1407
-
1408
- # ...
1409
- end
1410
-
1411
- === JSON API Support
1412
-
1413
- To add support for handling JSON responses, you can pass the +:json+
1414
- option to the plugin, and enable the JWT feature in addition to
1415
- other features you plan to use:
1416
-
1417
- plugin :rodauth, json: true do
1418
- enable :login, :logout, :jwt
1419
- end
1420
-
1421
- If you do not want to load the HTML plugins that Rodauth usually loads
1422
- (render, csrf, flash, h), because you are building a JSON-only API,
1423
- pass <tt>:json => :only</tt>
1424
-
1425
- plugin :rodauth, json: :only do
1426
- enable :login, :logout, :jwt
1427
- end
1428
-
1429
- Note that by default, the features that send email depend on the
1430
- render plugin, so if using the <tt>json: :only</tt> option, you
1431
- either need to load the render plugin manually or you need to
1432
- use the necessary *_email_body configuration options to specify
1433
- the body of the emails.
1434
-
1435
- The JWT feature enables JSON API support for all of the other features
1436
- that Rodauth ships with. If you would like JSON API access that still uses
1437
- rack session for storing session data, enable the JSON feature instead:
1438
-
1439
- plugin :rodauth, json: true do
1440
- enable :login, :logout, :json
1441
- only_json? true # if you want to only handle JSON requests
1442
- end
1443
-
1444
- === Adding Custom Methods to the +rodauth+ Object
1445
-
1446
- Inside the configuration block, you can use +auth_class_eval+ to add
1447
- custom methods that will be callable on the +rodauth+ object.
1448
-
1449
- plugin :rodauth do
1450
- enable :login
1451
-
1452
- auth_class_eval do
1453
- def require_admin
1454
- request.redirect("/") unless account[:admin]
1455
- end
1456
- end
1457
- end
1458
-
1459
- route do |r|
1460
- r.rodauth
1461
-
1462
- r.on "admin" do
1463
- rodauth.require_admin
1464
- end
1465
- end
1466
-
1467
- === Using External Features
1468
-
1469
- The +enable+ configuration method is able to load features external to
1470
- Rodauth. You need to place the external feature file where it can be
1471
- required via rodauth/features/feature_name. That file should
1472
- use the following basic structure
1473
-
1474
- module Rodauth
1475
- # :feature_name will be the argument given to enable to
1476
- # load the feature, :FeatureName is optional and will be used to
1477
- # set a constant name for prettier inspect output.
1478
- Feature.define(:feature_name, :FeatureName) do
1479
- # Shortcut for defining auth value methods with static values
1480
- auth_value_method :method_name, 1 # method_value
1481
-
1482
- auth_value_methods # one argument per auth value method
1483
-
1484
- auth_methods # one argument per auth method
1485
-
1486
- route do |r|
1487
- # This block is taken for requests to the feature's route.
1488
- # This block is evaluated in the scope of the Rodauth::Auth instance.
1489
- # r is the Roda::RodaRequest instance for the request
1490
-
1491
- r.get do
1492
- end
1493
-
1494
- r.post do
1495
- end
1496
- end
1497
-
1498
- configuration_eval do
1499
- # define additional configuration specific methods here, if any
1500
- end
1501
-
1502
- # define the default behavior for the auth_methods
1503
- # and auth_value_methods
1504
- # ...
1505
- end
1506
- end
1507
-
1508
- See the {internals guide}[rdoc-ref:doc/guides/internals.rdoc] for a more complete
1509
- example of how to construct features.
1510
-
1511
- === Overriding Route-Level Behavior
1512
-
1513
- All of Rodauth's configuration methods change the behavior of the
1514
- Rodauth::Auth instance. However, in some cases you may want to
1515
- overriding handling at the routing layer. You can do this easily
1516
- by adding an appropriate route before calling +r.rodauth+:
1517
-
1518
- route do |r|
1519
- r.post 'login' do
1520
- # Custom POST /login handling here
1521
- end
1522
-
1523
- r.rodauth
1524
- end
1525
-
1526
- === Precompiling Rodauth Templates
1527
-
1528
- Rodauth serves templates from it's gem folder. If you are using
1529
- a forking webserver and want to preload the compiled templates
1530
- to save memory, or if you are chrooting your application, you can
1531
- benefit from precompiling your rodauth templates:
1532
-
1533
- plugin :rodauth do
1534
- # ...
1535
- end
1536
- precompile_rodauth_templates
1537
-
1538
- == Ruby Support Policy
1539
-
1540
- Rodauth fully supports the currently supported versions of Ruby (MRI) and JRuby. It may
1541
- support unsupported versions of Ruby or JRuby, but such support may be dropped in any
1542
- minor version if keeping it becomes a support issue. The minimum Ruby version
1543
- required to run the current version of Rodauth is 1.9.2.
1544
-
1545
- == Similar Projects
1546
-
1547
- All of these are Rails-specific:
1548
-
1549
- * {Devise}[https://github.com/heartcombo/devise]
1550
- * {Authlogic}[https://github.com/binarylogic/authlogic]
1551
- * {Sorcery}[https://github.com/Sorcery/sorcery]
1552
-
1553
- == Author
1554
-
1555
- Jeremy Evans <code@jeremyevans.net>