omniauth-auth0 2.5.0 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +69 -0
- data/lib/omniauth-auth0/version.rb +1 -1
- data/lib/omniauth/auth0/jwt_validator.rb +13 -0
- data/lib/omniauth/strategies/auth0.rb +1 -1
- data/spec/omniauth/auth0/jwt_validator_spec.rb +35 -0
- data/spec/omniauth/strategies/auth0_spec.rb +50 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f45e6ee50254603367c7de482ce5537b48c5faf1bc7a4f2797cf461f21b37198
|
4
|
+
data.tar.gz: 88eb699d3cf59148df15728b42d517e010bebe29617f1f9e972dc9656e5a79a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 829fd68186ab4685d7628b6a7c3a0cce95b1008396e6b6588e72b30ff7b077c103109bafe8e3e480539a07d715550fed27b2d73f537e505498a8b434655a0776
|
7
|
+
data.tar.gz: 8d03a181ad81f1b08618f542d1971d298a9751ca5d02e949bcf8f60bbf4d6ba2ce3463e6f5ce5a01945a82f24ce7e6f67881192f3e4214a2d05bb556ba6ef66e
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [v2.6.0](https://github.com/auth0/omniauth-auth0/tree/v2.6.0) (2021-04-01)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/auth0/omniauth-auth0/compare/v2.5.0...v2.6.0)
|
6
|
+
|
7
|
+
**Added**
|
8
|
+
- Org Support [SDK-2395] [\#124](https://github.com/auth0/omniauth-auth0/pull/124) ([davidpatrick](https://github.com/davidpatrick))
|
9
|
+
- Add login_hint to permitted params [\#123](https://github.com/auth0/omniauth-auth0/pull/123) ([Roriz](https://github.com/Roriz))
|
10
|
+
|
3
11
|
## [v2.5.0](https://github.com/auth0/omniauth-auth0/tree/v2.5.0) (2021-01-21)
|
4
12
|
|
5
13
|
[Full Changelog](https://github.com/auth0/omniauth-auth0/compare/v2.4.2...v2.5.0)
|
data/README.md
CHANGED
@@ -131,9 +131,78 @@ In some scenarios, you may need to pass specific query parameters to `/authorize
|
|
131
131
|
- `connection_scope`
|
132
132
|
- `prompt`
|
133
133
|
- `screen_hint` (only relevant to New Universal Login Experience)
|
134
|
+
- `organization`
|
135
|
+
- `invitation`
|
134
136
|
|
135
137
|
Simply pass these query parameters to your OmniAuth redirect endpoint to enable their behavior.
|
136
138
|
|
139
|
+
## Examples
|
140
|
+
|
141
|
+
### Auth0 Organizations (Closed Beta)
|
142
|
+
|
143
|
+
Organizations is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications.
|
144
|
+
|
145
|
+
Using Organizations, you can:
|
146
|
+
|
147
|
+
- Represent teams, business customers, partner companies, or any logical grouping of users that should have different ways of accessing your applications, as organizations.
|
148
|
+
- Manage their membership in a variety of ways, including user invitation.
|
149
|
+
- Configure branded, federated login flows for each organization.
|
150
|
+
- Implement role-based access control, such that users can have different roles when authenticating in the context of different organizations.
|
151
|
+
- Build administration capabilities into your products, using Organizations APIs, so that those businesses can manage their own organizations.
|
152
|
+
|
153
|
+
Note that Organizations is currently only available to customers on our Enterprise and Startup subscription plans.
|
154
|
+
|
155
|
+
#### Logging in with an Organization
|
156
|
+
|
157
|
+
Logging in with an Organization is as easy as passing the parameters to the authorize endpoint. You can do this with
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
<%=
|
161
|
+
button_to 'Login', 'auth/auth0',
|
162
|
+
method: :post,
|
163
|
+
params: {
|
164
|
+
# Found in your Auth0 dashboard, under Organization settings:
|
165
|
+
organization: '{AUTH0_ORGANIZATION}'
|
166
|
+
}
|
167
|
+
%>
|
168
|
+
```
|
169
|
+
|
170
|
+
Alternatively you can configure the organization when you register the provider:
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
provider
|
174
|
+
:auth0,
|
175
|
+
ENV['AUTH0_CLIENT_ID'],
|
176
|
+
ENV['AUTH0_CLIENT_SECRET'],
|
177
|
+
ENV['AUTH0_DOMAIN'],
|
178
|
+
{
|
179
|
+
authorize_params: {
|
180
|
+
scope: 'openid read:users',
|
181
|
+
audience: 'https://{AUTH0_DOMAIN}/api',
|
182
|
+
organization: '{AUTH0_ORGANIZATION}'
|
183
|
+
}
|
184
|
+
}
|
185
|
+
```
|
186
|
+
|
187
|
+
#### Accepting user invitations
|
188
|
+
|
189
|
+
Auth0 Organizations allow users to be invited using emailed links, which will direct a user back to your application. The URL the user will arrive at is based on your configured `Application Login URI`, which you can change from your Application's settings inside the Auth0 dashboard.
|
190
|
+
|
191
|
+
When the user arrives at your application using an invite link, you can expect three query parameters to be provided: `invitation`, `organization`, and `organization_name`. These will always be delivered using a GET request.
|
192
|
+
|
193
|
+
You can then supply those parametrs to a `button_to` or `link_to` helper
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
<%=
|
197
|
+
button_to 'Login', 'auth/auth0',
|
198
|
+
method: :post,
|
199
|
+
params: {
|
200
|
+
organization: '{YOUR_ORGANIZATION_ID}',
|
201
|
+
invitation: '{INVITE_CODE}'
|
202
|
+
}
|
203
|
+
%>
|
204
|
+
```
|
205
|
+
|
137
206
|
## Contribution
|
138
207
|
|
139
208
|
We appreciate feedback and contribution to this repo! Before you get started, please see the following:
|
@@ -174,6 +174,7 @@ module OmniAuth
|
|
174
174
|
leeway = authorize_params[:leeway] || 60
|
175
175
|
max_age = authorize_params[:max_age]
|
176
176
|
nonce = authorize_params[:nonce]
|
177
|
+
organization = authorize_params[:organization]
|
177
178
|
|
178
179
|
verify_iss(id_token)
|
179
180
|
verify_sub(id_token)
|
@@ -183,6 +184,7 @@ module OmniAuth
|
|
183
184
|
verify_nonce(id_token, nonce)
|
184
185
|
verify_azp(id_token)
|
185
186
|
verify_auth_time(id_token, leeway, max_age)
|
187
|
+
verify_org(id_token, organization)
|
186
188
|
end
|
187
189
|
|
188
190
|
def verify_iss(id_token)
|
@@ -260,6 +262,17 @@ module OmniAuth
|
|
260
262
|
end
|
261
263
|
end
|
262
264
|
end
|
265
|
+
|
266
|
+
def verify_org(id_token, organization)
|
267
|
+
if organization
|
268
|
+
org_id = id_token['org_id']
|
269
|
+
if !org_id || !org_id.is_a?(String)
|
270
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Organization Id (org_id) claim must be a string present in the ID token")
|
271
|
+
elsif org_id != organization
|
272
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Organization Id (org_id) claim value mismatch in the ID token; expected '#{organization}', found '#{org_id}'")
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
263
276
|
end
|
264
277
|
end
|
265
278
|
end
|
@@ -84,7 +84,7 @@ module OmniAuth
|
|
84
84
|
# Define the parameters used for the /authorize endpoint
|
85
85
|
def authorize_params
|
86
86
|
params = super
|
87
|
-
%w[connection connection_scope prompt screen_hint].each do |key|
|
87
|
+
%w[connection connection_scope prompt screen_hint login_hint organization invitation].each do |key|
|
88
88
|
params[key] = request.params[key] if request.params.key?(key)
|
89
89
|
end
|
90
90
|
|
@@ -476,6 +476,41 @@ describe OmniAuth::Auth0::JWTValidator do
|
|
476
476
|
expect(id_token['auth_time']).to eq(auth_time)
|
477
477
|
end
|
478
478
|
|
479
|
+
it 'should fail when authorize params has organization but org_id is missing in the token', focus: true do
|
480
|
+
payload = {
|
481
|
+
iss: "https://#{domain}/",
|
482
|
+
sub: 'sub',
|
483
|
+
aud: client_id,
|
484
|
+
exp: future_timecode,
|
485
|
+
iat: past_timecode
|
486
|
+
}
|
487
|
+
|
488
|
+
token = make_hs256_token(payload)
|
489
|
+
expect do
|
490
|
+
jwt_validator.verify(token, { organization: 'Test Org' })
|
491
|
+
end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and having_attributes({
|
492
|
+
message: "Organization Id (org_id) claim must be a string present in the ID token"
|
493
|
+
}))
|
494
|
+
end
|
495
|
+
|
496
|
+
it 'should fail when authorize params has organization but token org_id does not match', focus: true do
|
497
|
+
payload = {
|
498
|
+
iss: "https://#{domain}/",
|
499
|
+
sub: 'sub',
|
500
|
+
aud: client_id,
|
501
|
+
exp: future_timecode,
|
502
|
+
iat: past_timecode,
|
503
|
+
org_id: 'Wrong Org'
|
504
|
+
}
|
505
|
+
|
506
|
+
token = make_hs256_token(payload)
|
507
|
+
expect do
|
508
|
+
jwt_validator.verify(token, { organization: 'Test Org' })
|
509
|
+
end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and having_attributes({
|
510
|
+
message: "Organization Id (org_id) claim value mismatch in the ID token; expected 'Test Org', found 'Wrong Org'"
|
511
|
+
}))
|
512
|
+
end
|
513
|
+
|
479
514
|
it 'should fail for RS256 token when kid is incorrect' do
|
480
515
|
domain = 'example.org'
|
481
516
|
sub = 'abc123'
|
@@ -91,6 +91,9 @@ describe OmniAuth::Strategies::Auth0 do
|
|
91
91
|
expect(redirect_url).not_to have_query('connection_scope')
|
92
92
|
expect(redirect_url).not_to have_query('prompt')
|
93
93
|
expect(redirect_url).not_to have_query('screen_hint')
|
94
|
+
expect(redirect_url).not_to have_query('login_hint')
|
95
|
+
expect(redirect_url).not_to have_query('organization')
|
96
|
+
expect(redirect_url).not_to have_query('invitation')
|
94
97
|
end
|
95
98
|
|
96
99
|
it 'redirects to hosted login page' do
|
@@ -107,6 +110,9 @@ describe OmniAuth::Strategies::Auth0 do
|
|
107
110
|
expect(redirect_url).not_to have_query('connection_scope')
|
108
111
|
expect(redirect_url).not_to have_query('prompt')
|
109
112
|
expect(redirect_url).not_to have_query('screen_hint')
|
113
|
+
expect(redirect_url).not_to have_query('login_hint')
|
114
|
+
expect(redirect_url).not_to have_query('organization')
|
115
|
+
expect(redirect_url).not_to have_query('invitation')
|
110
116
|
end
|
111
117
|
|
112
118
|
it 'redirects to the hosted login page with connection_scope' do
|
@@ -130,6 +136,9 @@ describe OmniAuth::Strategies::Auth0 do
|
|
130
136
|
expect(redirect_url).to have_query('prompt', 'login')
|
131
137
|
expect(redirect_url).not_to have_query('auth0Client')
|
132
138
|
expect(redirect_url).not_to have_query('connection')
|
139
|
+
expect(redirect_url).not_to have_query('login_hint')
|
140
|
+
expect(redirect_url).not_to have_query('organization')
|
141
|
+
expect(redirect_url).not_to have_query('invitation')
|
133
142
|
end
|
134
143
|
|
135
144
|
it 'redirects to hosted login page with screen_hint=signup' do
|
@@ -144,6 +153,47 @@ describe OmniAuth::Strategies::Auth0 do
|
|
144
153
|
expect(redirect_url).to have_query('screen_hint', 'signup')
|
145
154
|
expect(redirect_url).not_to have_query('auth0Client')
|
146
155
|
expect(redirect_url).not_to have_query('connection')
|
156
|
+
expect(redirect_url).not_to have_query('login_hint')
|
157
|
+
expect(redirect_url).not_to have_query('organization')
|
158
|
+
expect(redirect_url).not_to have_query('invitation')
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'redirects to hosted login page with organization=TestOrg and invitation=TestInvite' do
|
162
|
+
get 'auth/auth0?organization=TestOrg&invitation=TestInvite'
|
163
|
+
expect(last_response.status).to eq(302)
|
164
|
+
redirect_url = last_response.headers['Location']
|
165
|
+
expect(redirect_url).to start_with('https://samples.auth0.com/authorize')
|
166
|
+
expect(redirect_url).to have_query('response_type', 'code')
|
167
|
+
expect(redirect_url).to have_query('state')
|
168
|
+
expect(redirect_url).to have_query('client_id')
|
169
|
+
expect(redirect_url).to have_query('redirect_uri')
|
170
|
+
expect(redirect_url).to have_query('organization', 'TestOrg')
|
171
|
+
expect(redirect_url).to have_query('invitation', 'TestInvite')
|
172
|
+
expect(redirect_url).not_to have_query('auth0Client')
|
173
|
+
expect(redirect_url).not_to have_query('connection')
|
174
|
+
expect(redirect_url).not_to have_query('connection_scope')
|
175
|
+
expect(redirect_url).not_to have_query('prompt')
|
176
|
+
expect(redirect_url).not_to have_query('screen_hint')
|
177
|
+
expect(redirect_url).not_to have_query('login_hint')
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'redirects to hosted login page with login_hint=example@mail.com' do
|
181
|
+
get 'auth/auth0?login_hint=example@mail.com'
|
182
|
+
expect(last_response.status).to eq(302)
|
183
|
+
redirect_url = last_response.headers['Location']
|
184
|
+
expect(redirect_url).to start_with('https://samples.auth0.com/authorize')
|
185
|
+
expect(redirect_url).to have_query('response_type', 'code')
|
186
|
+
expect(redirect_url).to have_query('state')
|
187
|
+
expect(redirect_url).to have_query('client_id')
|
188
|
+
expect(redirect_url).to have_query('redirect_uri')
|
189
|
+
expect(redirect_url).to have_query('login_hint', 'example@mail.com')
|
190
|
+
expect(redirect_url).not_to have_query('auth0Client')
|
191
|
+
expect(redirect_url).not_to have_query('connection')
|
192
|
+
expect(redirect_url).not_to have_query('connection_scope')
|
193
|
+
expect(redirect_url).not_to have_query('prompt')
|
194
|
+
expect(redirect_url).not_to have_query('screen_hint')
|
195
|
+
expect(redirect_url).not_to have_query('organization')
|
196
|
+
expect(redirect_url).not_to have_query('invitation')
|
147
197
|
end
|
148
198
|
|
149
199
|
describe 'callback' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omniauth-auth0
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Auth0
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-01
|
11
|
+
date: 2021-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: omniauth
|
@@ -118,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
118
|
- !ruby/object:Gem::Version
|
119
119
|
version: '0'
|
120
120
|
requirements: []
|
121
|
-
rubygems_version: 3.
|
121
|
+
rubygems_version: 3.1.2
|
122
122
|
signing_key:
|
123
123
|
specification_version: 4
|
124
124
|
summary: OmniAuth OAuth2 strategy for the Auth0 platform.
|