rodauth-omniauth 0.5.1 → 0.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dad995353c13952f65bb35c561c82d755f2319318ac2409adc948b4b95fd6171
4
- data.tar.gz: 30bdc64ac42ad66ff6003e5d95ffd5123ce9564661157ffb25f0f496e2772a3e
3
+ metadata.gz: 0453fcafd04b57e1adf926663a9edb8d1f9f72f25aa952d193cf092fc877327f
4
+ data.tar.gz: 3a3211e64e8558d3fe5aea563498f79763e3ebed62e9bd964020f52f5be36857
5
5
  SHA512:
6
- metadata.gz: '099007ffbf1e055d03625fbe9d90d3b032c27a83803a900e8f3b859dc2b8f350cc10fca07e92668dd49543c1e612a01bc4b0ba582066b633ef147883715a27fa'
7
- data.tar.gz: 699b0e8890e5b117c69bf6b7a6aa89e140aebea976ec56455feaee688ef260e7dc71bb9cbc7bc05397ffef6a40f6c4d1260ef5f7885958e6213e4adc7541e270
6
+ metadata.gz: 005c3b00e023b15f033af4782dba58f0e8372b4573c17822d0d770a980568c691a85a8c16422b8d3193ade0e8bdcfdb5ca54a9cd0244465842ef51efb7a69b37
7
+ data.tar.gz: 282df1dd1951ce51c41af1622e95e486a925280e699e9e0caa438ff5528efea6954d8d1b20f412f620fa5a41f114872c4773aba110010f32cd19936540abc122
data/README.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  [Rodauth] feature that offers login and registration via multiple external providers using [OmniAuth], together with the persistence of external identities.
4
4
 
5
+ It comes with many features out of the box:
6
+
7
+ * multiple external providers (with automatic identity linking)
8
+ * automatic account creation (or login-only)
9
+ * email verification on login
10
+ * ability to count as two factors
11
+ * JSON API support (+ JWT)
12
+ * per-configuration strategies with inheritance
13
+
5
14
  ## Installation
6
15
 
7
16
  Add the gem to your project:
@@ -10,7 +19,11 @@ Add the gem to your project:
10
19
  $ bundle add rodauth-omniauth
11
20
  ```
12
21
 
13
- ## Usage
22
+ > [!NOTE]
23
+ > Rodauth's CSRF protection will be used for the request validation phase, so there is no need for gems like `omniauth-rails_csrf_protection`.
24
+
25
+
26
+ ## Getting started
14
27
 
15
28
  You'll first need to create the table for storing external identities:
16
29
 
@@ -46,17 +59,16 @@ Then enable the `omniauth` feature and register providers in your Rodauth config
46
59
  $ bundle add omniauth-facebook omniauth-twitter, omniauth-google-oauth2
47
60
  ```
48
61
  ```rb
49
- plugin :rodauth do
50
- enable :omniauth
62
+ # in your Rodauth configuration
63
+ enable :omniauth
51
64
 
52
- omniauth_provider :facebook, ENV["FACEBOOK_APP_ID"], ENV["FACEBOOK_APP_SECRET"], scope: "email"
53
- omniauth_provider :twitter, ENV["TWITTER_API_KEY"], ENV["TWITTER_API_SECRET"]
54
- omniauth_provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"], name: :google
55
- end
65
+ omniauth_provider :facebook, ENV["FACEBOOK_APP_ID"], ENV["FACEBOOK_APP_SECRET"], scope: "email"
66
+ omniauth_provider :twitter, ENV["TWITTER_API_KEY"], ENV["TWITTER_API_SECRET"]
67
+ omniauth_provider :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"], name: :google
56
68
  ```
57
69
 
58
- > [!NOTE]
59
- > It is important to note that `rodauth-omniauth` requires OmniAuth 2.x, so it's only compatible with providers gems that support it.
70
+ > [!WARNING]
71
+ > The `rodauth-omniauth` gem requires OmniAuth 2.x, so it's only compatible with providers gems that support it.
60
72
 
61
73
  You can now add authentication links to your login form:
62
74
 
@@ -88,14 +100,47 @@ account.identities #=> [#<Account::Identity ...>, ...]
88
100
 
89
101
  Currently, provider login is required to return the user's email address, and account creation is assumed not to require additional fields that need to be entered manually. There is currently also no built-in functionality for connecting/removing external identities when signed in. Both features are planned for future versions.
90
102
 
91
- ### Timestamps
92
-
93
- If you'll be adding created/updated timestamps to the identities table, also add these lines to your Rodauth configuration:
94
-
95
- ```rb
96
- omniauth_identity_insert_hash { super().merge(created_at: Time.now) }
97
- omniauth_identity_update_hash { { updated_at: Time.now } }
98
- ```
103
+ ## Configuration reference
104
+
105
+ ### Auth Value Methods
106
+
107
+ | Method | Description |
108
+ | :---- | :---------- |
109
+ | `omniauth_verify_account?` | Automatically verify unverified accounts on login (defaults to true). |
110
+ | `omniauth_login_unverified_account_error_flash` | Flash message for when existing account is unverified and automatic verification is disabled. |
111
+ | `omniauth_login_failure_redirect` | Redirect location for when OmniAuth login failed. |
112
+ | `omniauth_create_account?` | Automatically create account for new email address on OmniAuth login (defaults to true). |
113
+ | `omniauth_login_no_matching_account_error_flash` | Flash message for when no existing account was found and automatic creation is disabled. |
114
+ | `omniauth_two_factors?` | Treat OmniAuth login as two factors when using MFA (defaults to false). |
115
+ | `omniauth_identities_table` | Table name for external identities (defaults to `account_identities`). |
116
+ | `omniauth_identities_id_column` | Primary key column for identities table (defaults to `id`). |
117
+ | `omniauth_identities_account_id_column` | Foreign key column for identities table (defaults to `account_id`). |
118
+ | `omniauth_identities_provider_column` | Provider column for identities table (defaults to `provider`). |
119
+ | `omniauth_identities_uid_column` | UID column for identities table (defaults to `uid`). |
120
+ | `omniauth_prefix` | Path prefix to use for OmniAuth routes (defaults to `/auth`). |
121
+ | `omniauth_failure_error_flash` | Flash message for failed OmniAuth login. |
122
+ | `omniauth_failure_redirect` | Redirect location for failed OmniAuth login. |
123
+ | `omniauth_failure_error_status` | Response status for failed OmniAuth login (defaults to 500). |
124
+ | `omniauth_authorize_url_key` | Field name for authorization URL in JSON mode. |
125
+ | `omniauth_error_type_key` | Field name for error type in JSON mode. |
126
+
127
+ ### Auth Methods
128
+
129
+ | Method | Description |
130
+ | :---- | :---------- |
131
+ | `account_from_omniauth` | Find an existing account from OmniAuth login data (by default matches by email). |
132
+ | `before_omniauth_callback_route` | Run arbitrary code before handling the callback route. |
133
+ | `omniauth_identity_insert_hash` | Hash of column values used for creating a new identity on login. |
134
+ | `omniauth_identity_update_hash` | Hash of column values used fro updating existing identities on login. |
135
+ | `before_omniauth_create_account` | Any actions to take before creating a new account on OmniAuth login. |
136
+ | `after_omniauth_create_account` | Any actions to take after creating a new account on OmniAuth login. |
137
+ | `omniauth_setup` | Hook for OmniAuth setup phase |
138
+ | `omniauth_request_validation_phase` | Hook for OmniAuth request validation phase (defaults to CSRF protection). |
139
+ | `omniauth_before_request_phase` | Hook for OmniAuth before request phase. |
140
+ | `omniauth_before_callback_phase` | Hook for OmniAuth before callback phase. |
141
+ | `omniauth_on_failure` | Hook for OmniAuth login failure. |
142
+
143
+ ## Customizing
99
144
 
100
145
  ### Login
101
146
 
@@ -163,9 +208,28 @@ You can change the default error message for when existing account wasn't found
163
208
  omniauth_login_no_matching_account_error_flash "No existing account found"
164
209
  ```
165
210
 
211
+ ### Multifactor authentication
212
+
213
+ By default, OmniAuth login will count only as one factor. So, if the user has multifactor authentication enabled, they will be asked to authenticate with 2nd factor when required.
214
+
215
+ If you're using OmniAuth login for SSO and want to rely on 2FA policies set on the external provider, you can have OmniAuth login count as two factors:
216
+
217
+ ```rb
218
+ omniauth_two_factors? true
219
+ ```
220
+
221
+ You can also make it conditional based on data from the external provider:
222
+
223
+ ```rb
224
+ omniauth_two_factors? do
225
+ # only count as two factors if external account uses 2FA
226
+ omniauth_extra["raw_info"]["two_factor_authentication"]
227
+ end
228
+ ```
229
+
166
230
  ### Identity data
167
231
 
168
- You can also store extra data on the external identities. For example, we could override the update hash to store `info`, `credentials`, and `extra` data from the auth hash into separate columns:
232
+ You can also store extra data on the external identities. The most common use case is storing [timestamps](https://github.com/janko/rodauth-omniauth/wiki/Timestamps). You could also persist data about external identities, for example:
169
233
 
170
234
  ```rb
171
235
  alter_table :account_identities do
@@ -198,6 +262,8 @@ omniauth_identity_insert_hash do
198
262
  end
199
263
  ```
200
264
 
265
+ ### Identity schema
266
+
201
267
  You can change the table name or any of the column names:
202
268
 
203
269
  ```rb
@@ -208,33 +274,25 @@ omniauth_identities_provider_column :provider
208
274
  omniauth_identities_uid_column :uid
209
275
  ```
210
276
 
211
- ### Audit logging
212
-
213
- If you're using the `audit_logging` feature, it can be useful to include the external provider name in the `login` audit logs:
214
-
215
- ```rb
216
- audit_log_metadata_for :login do
217
- { "provider" => omniauth_provider } if authenticated_by.include?("omniauth")
218
- end
219
- ```
220
-
221
277
  ## Base
222
278
 
223
279
  The `omniauth` feature builds on top of the `omniauth_base` feature, which sets up OmniAuth and routes its requests, but has no interaction with the database. So, if you would prefer to handle external logins differently, you can load just the `omniauth_base` feature, and implement your own callback phase.
224
280
 
225
281
  ```rb
226
- plugin :rodauth do
227
- enable :omniauth_base
228
-
229
- omniauth_provider :github, ENV["GITHUB_CLIENT_ID"], ENV["GITHUB_CLIENT_SECRET"], scope: "user"
230
- omniauth_provider :apple, ENV["APPLE_CLIENT_ID"], ENV["APPLE_CLIENT_SECRET"], scope: "email name"
231
- end
282
+ # in your Rodauth configuration
283
+ enable :omniauth_base
232
284
 
233
- route do |r|
234
- r.rodauth # routes Rodauth and OmniAuth requests
235
-
236
- r.get "auth", String, "callback" do
237
- # ... handle callback request ...
285
+ omniauth_provider :github, ENV["GITHUB_CLIENT_ID"], ENV["GITHUB_CLIENT_SECRET"], scope: "user"
286
+ omniauth_provider :apple, ENV["APPLE_CLIENT_ID"], ENV["APPLE_CLIENT_SECRET"], scope: "email name"
287
+ ```
288
+ ```rb
289
+ # in your routes
290
+ get "/auth/:provider/callback", to: "rodauth#omniauth_login"
291
+ ```
292
+ ```rb
293
+ class RodauthController < ApplicationController
294
+ def omniauth_login
295
+ # ...
238
296
  end
239
297
  end
240
298
  ```
@@ -332,10 +390,6 @@ omniauth_on_failure do
332
390
  end
333
391
  ```
334
392
 
335
- #### CSRF protection
336
-
337
- The default request validation phase uses Rodauth's configured CSRF protection, so there is no need for external gems such as `omniauth-rails_csrf_protection`.
338
-
339
393
  ### Inheritance
340
394
 
341
395
  The registered providers are inherited between Rodauth auth classes, so you can have fine-grained configuration for different account types.
@@ -347,15 +401,13 @@ class RodauthBase < Rodauth::Auth
347
401
  omniauth_provider :google_oauth2, ...
348
402
  end
349
403
  end
350
- ```
351
- ```rb
404
+
352
405
  class RodauthMain < RodauthBase
353
406
  configure do
354
407
  omniauth_provider :facebook, ...
355
408
  end
356
409
  end
357
- ```
358
- ```rb
410
+
359
411
  class RodauthAdmin < RodauthBase
360
412
  configure do
361
413
  omniauth_provider :twitter, ...
@@ -364,12 +416,6 @@ class RodauthAdmin < RodauthBase
364
416
  end
365
417
  ```
366
418
  ```rb
367
- class RodauthApp < Roda
368
- plugin :rodauth, auth_class: RodauthMain
369
- plugin :rodauth, auth_class: RodauthAdmin, name: :admin
370
- end
371
- ```
372
- ```rb
373
419
  rodauth.omniauth_providers #=> [:google_oauth2, :facebook]
374
420
  rodauth(:admin).omniauth_providers #=> [:google_oauth2, :twitter, :github]
375
421
  ```
@@ -404,6 +450,9 @@ Content-Type: application/json
404
450
  { "success": "You have been logged in" }
405
451
  ```
406
452
 
453
+ > [!NOTE]
454
+ > Unless you're using JWT, make sure you're persisting cookies across requests, as most OmniAuth strategies rely on session storage.
455
+
407
456
  If there was an OmniAuth failure, the error type will be included in the response:
408
457
 
409
458
  ```http
@@ -20,6 +20,7 @@ module Rodauth
20
20
  auth_value_method :omniauth_identities_account_id_column, :account_id
21
21
  auth_value_method :omniauth_identities_provider_column, :provider
22
22
  auth_value_method :omniauth_identities_uid_column, :uid
23
+ auth_value_method :omniauth_two_factors?, false
23
24
 
24
25
  auth_value_methods(
25
26
  :omniauth_verify_account?,
@@ -57,14 +58,12 @@ module Rodauth
57
58
  def _handle_omniauth_callback
58
59
  before_omniauth_callback_route
59
60
 
60
- retrieve_omniauth_identity
61
-
62
- if !account && omniauth_identity
63
- account_from_omniauth_identity
64
- end
65
-
66
61
  unless account
67
- account_from_omniauth
62
+ if omniauth_identity
63
+ account_from_omniauth_identity
64
+ else
65
+ account_from_omniauth
66
+ end
68
67
  end
69
68
 
70
69
  if account && !open_account?
@@ -80,10 +79,7 @@ module Rodauth
80
79
  transaction do
81
80
  if !account
82
81
  if omniauth_create_account?
83
- omniauth_new_account
84
- before_omniauth_create_account
85
- omniauth_save_account
86
- after_omniauth_create_account
82
+ omniauth_create_account
87
83
  else
88
84
  set_redirect_error_flash omniauth_login_no_matching_account_error_flash
89
85
  redirect omniauth_login_failure_redirect
@@ -97,11 +93,17 @@ module Rodauth
97
93
  end
98
94
  end
99
95
 
100
- login("omniauth")
96
+ login("omniauth") do
97
+ two_factor_update_session("omniauth-two") if omniauth_second_factor?
98
+ end
99
+ end
100
+
101
+ def omniauth_identity
102
+ @omniauth_identity ||= retrieve_omniauth_identity
101
103
  end
102
104
 
103
105
  def retrieve_omniauth_identity
104
- @omniauth_identity = _retrieve_omniauth_identity(omniauth_provider, omniauth_uid)
106
+ _retrieve_omniauth_identity(omniauth_provider, omniauth_uid)
105
107
  end
106
108
 
107
109
  def account_from_omniauth_identity
@@ -142,7 +144,9 @@ module Rodauth
142
144
  remove_omniauth_identities
143
145
  end
144
146
 
145
- attr_reader :omniauth_identity
147
+ def omniauth_second_factor?
148
+ features.include?(:two_factor_base) && uses_two_factor_authentication? && omniauth_two_factors?
149
+ end
146
150
 
147
151
  def omniauth_verify_account?
148
152
  features.include?(:verify_account) && account[login_column] == omniauth_email
@@ -159,6 +163,13 @@ module Rodauth
159
163
  true
160
164
  end
161
165
 
166
+ def omniauth_create_account
167
+ omniauth_new_account
168
+ before_omniauth_create_account
169
+ omniauth_save_account
170
+ after_omniauth_create_account
171
+ end
172
+
162
173
  def _omniauth_new_account(login)
163
174
  acc = { login_column => login }
164
175
  unless skip_status_checks?
@@ -205,7 +216,7 @@ module Rodauth
205
216
  end
206
217
 
207
218
  def _account_from_omniauth_identity
208
- account_ds(omniauth_identity_account_id).first
219
+ _account_from_id(omniauth_identity_account_id)
209
220
  end
210
221
 
211
222
  def omniauth_identity_id
@@ -195,10 +195,12 @@ module Rodauth
195
195
  end
196
196
 
197
197
  def self.included(auth)
198
- auth.extend ClassMethods
198
+ auth.extend OmniauthBase::ClassMethods
199
199
  auth.instance_variable_set(:@omniauth_providers, [])
200
200
  end
201
+ end
201
202
 
203
+ module OmniauthBase
202
204
  module ClassMethods
203
205
  def inherited(subclass)
204
206
  super
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "rodauth-omniauth"
3
- spec.version = "0.5.1"
3
+ spec.version = "0.6.1"
4
4
  spec.authors = ["Janko Marohnić"]
5
5
  spec.email = ["janko@hey.com"]
6
6
 
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.files = Dir["README.md", "LICENSE.txt", "*.gemspec", "lib/**/*", "locales/**/*"]
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_dependency "rodauth", "~> 2.13"
20
+ spec.add_dependency "rodauth", "~> 2.36"
21
21
  spec.add_dependency "omniauth", "~> 2.0"
22
22
 
23
23
  spec.add_development_dependency "minitest"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodauth-omniauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-10-12 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rodauth
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '2.13'
18
+ version: '2.36'
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '2.13'
25
+ version: '2.36'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: omniauth
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -197,7 +196,6 @@ licenses:
197
196
  metadata:
198
197
  homepage_uri: https://github.com/janko/rodauth-omniauth
199
198
  source_code_uri: https://github.com/janko/rodauth-omniauth
200
- post_install_message:
201
199
  rdoc_options: []
202
200
  require_paths:
203
201
  - lib
@@ -212,8 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
212
210
  - !ruby/object:Gem::Version
213
211
  version: '0'
214
212
  requirements: []
215
- rubygems_version: 3.5.11
216
- signing_key:
213
+ rubygems_version: 3.6.9
217
214
  specification_version: 4
218
215
  summary: Rodauth extension for logging in and creating account via OmniAuth authentication.
219
216
  test_files: []