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 +4 -4
- data/README.md +102 -53
- data/lib/rodauth/features/omniauth.rb +26 -15
- data/lib/rodauth/features/omniauth_base.rb +3 -1
- data/rodauth-omniauth.gemspec +2 -2
- metadata +5 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0453fcafd04b57e1adf926663a9edb8d1f9f72f25aa952d193cf092fc877327f
|
4
|
+
data.tar.gz: 3a3211e64e8558d3fe5aea563498f79763e3ebed62e9bd964020f52f5be36857
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
50
|
-
|
62
|
+
# in your Rodauth configuration
|
63
|
+
enable :omniauth
|
51
64
|
|
52
|
-
|
53
|
-
|
54
|
-
|
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
|
-
> [!
|
59
|
-
>
|
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
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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.
|
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
|
-
|
227
|
-
|
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
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/rodauth-omniauth.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "rodauth-omniauth"
|
3
|
-
spec.version = "0.
|
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.
|
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.
|
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:
|
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.
|
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.
|
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.
|
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: []
|