omniauth-auth0 3.1.0 → 3.2.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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/devcontainer.json +1 -1
  3. data/.github/CODEOWNERS +1 -1
  4. data/.github/ISSUE_TEMPLATE/Bug Report.yml +76 -0
  5. data/.github/ISSUE_TEMPLATE/Feature Request.yml +53 -0
  6. data/.github/ISSUE_TEMPLATE/config.yml +2 -2
  7. data/.github/actions/get-prerelease/action.yml +30 -0
  8. data/.github/actions/get-release-notes/action.yml +42 -0
  9. data/.github/actions/get-version/action.yml +21 -0
  10. data/.github/actions/release-create/action.yml +47 -0
  11. data/.github/actions/rl-scanner/action.yml +71 -0
  12. data/.github/actions/rubygems-publish/action.yml +30 -0
  13. data/.github/actions/setup/action.yml +28 -0
  14. data/.github/actions/tag-exists/action.yml +36 -0
  15. data/.github/dependabot.yml +13 -0
  16. data/.github/workflows/codeql.yml +53 -0
  17. data/.github/workflows/matrix.json +7 -0
  18. data/.github/workflows/publish.yml +33 -0
  19. data/.github/workflows/rl-scanner.yml +65 -0
  20. data/.github/workflows/ruby-release.yml +72 -0
  21. data/.github/workflows/snyk.yml +40 -0
  22. data/.github/workflows/test.yml +69 -0
  23. data/.shiprc +2 -1
  24. data/.version +1 -0
  25. data/CHANGELOG.md +20 -0
  26. data/EXAMPLES.md +19 -5
  27. data/Gemfile +4 -5
  28. data/Gemfile.lock +128 -91
  29. data/README.md +42 -1
  30. data/lib/omniauth/auth0/jwt_token.rb +38 -0
  31. data/lib/omniauth/auth0/jwt_validator.rb +19 -3
  32. data/lib/omniauth/strategies/auth0.rb +48 -14
  33. data/lib/omniauth-auth0/version.rb +1 -1
  34. data/omniauth-auth0.gemspec +1 -0
  35. data/spec/omniauth/auth0/jwt_token_spec.rb +87 -0
  36. data/spec/omniauth/auth0/jwt_validator_spec.rb +109 -31
  37. data/spec/omniauth/strategies/auth0_spec.rb +478 -230
  38. data/spec/spec_helper.rb +1 -0
  39. metadata +39 -14
  40. data/.circleci/config.yml +0 -63
  41. data/.gemrelease +0 -2
  42. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -39
  43. data/.github/ISSUE_TEMPLATE/report_a_bug.md +0 -55
  44. data/.github/workflows/semgrep.yml +0 -24
data/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  [![codecov](https://codecov.io/gh/auth0/omniauth-auth0/branch/master/graph/badge.svg)](https://codecov.io/gh/auth0/omniauth-auth0)
6
6
  [![Gem Version](https://badge.fury.io/rb/omniauth-auth0.svg)](https://badge.fury.io/rb/omniauth-auth0)
7
7
  [![MIT licensed](https://img.shields.io/dub/l/vibe-d.svg?style=flat)](https://github.com/auth0/omniauth-auth0/blob/master/LICENSE)
8
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/auth0/omniauth-auth0)
8
9
 
9
10
  <div>
10
11
  📚 <a href="#documentation">Documentation</a> - 🚀 <a href="#getting-started">Getting started</a> - 💻 <a href="https://www.rubydoc.info/gems/omniauth-auth0">API reference</a> - 💬 <a href="#feedback">Feedback</a>
@@ -53,6 +54,8 @@ Adding the SDK to your Rails app requires a few steps:
53
54
 
54
55
  Create the file `./config/auth0.yml` within your application directory with the following content:
55
56
 
57
+ ### For client secret authentication
58
+
56
59
  ```yml
57
60
  development:
58
61
  auth0_domain: <YOUR_DOMAIN>
@@ -60,10 +63,25 @@ development:
60
63
  auth0_client_secret: <YOUR AUTH0 CLIENT SECRET>
61
64
  ```
62
65
 
66
+ #### For client assertion signing key authentication
67
+
68
+ ```yml
69
+ development:
70
+ auth0_domain: <YOUR_DOMAIN>
71
+ auth0_client_id: <YOUR_CLIENT_ID>
72
+ auth0_client_assertion_signing_key: <YOUR AUTH0 CLIENT ASSERTION SIGNING PRIVATE KEY>
73
+ auth0_client_assertion_signing_algorithm: <YOUR AUTH0 CLIENT ASSERTION SIGNING ALGORITHM>
74
+ ```
75
+ **Note**: you must upload the corresponding public key to your Auth0 tenant, so that Auth0 is able to verify the JWT signature.
76
+
77
+ client_assertion_signing_algorithm is optional and defaults to RS256.
78
+
63
79
  ### Create the initializer
64
80
 
65
81
  Create a new Ruby file in `./config/initializers/auth0.rb` to configure the OmniAuth middleware:
66
82
 
83
+ ### For client secret authentication
84
+
67
85
  ```ruby
68
86
  AUTH0_CONFIG = Rails.application.config_for(:auth0)
69
87
 
@@ -81,6 +99,29 @@ Rails.application.config.middleware.use OmniAuth::Builder do
81
99
  end
82
100
  ```
83
101
 
102
+ #### For client assertion signing key authentication
103
+
104
+ ```ruby
105
+ AUTH0_CONFIG = Rails.application.config_for(:auth0)
106
+
107
+ Rails.application.config.middleware.use OmniAuth::Builder do
108
+ provider(
109
+ :auth0,
110
+ AUTH0_CONFIG['auth0_client_id'],
111
+ nil,
112
+ AUTH0_CONFIG['auth0_domain'],
113
+ callback_path: '/auth/auth0/callback',
114
+ authorize_params: {
115
+ scope: 'openid profile'
116
+ },
117
+ client_assertion_signing_key: OpenSSL::PKey::RSA.new(AUTH0_CONFIG[:auth0_client_assertion_signing_key]),
118
+ client_assertion_signing_algorithm: AUTH0_CONFIG[:auth0_client_assertion_signing_algorithm]
119
+ )
120
+ end
121
+ ```
122
+
123
+ **Note**: The client_assertion_signing_key must be provided as a PKey object.
124
+
84
125
  ### Create the callback controller
85
126
 
86
127
  Create a new controller `./app/controllers/auth0_controller.rb` to handle the callback from Auth0.
@@ -165,4 +206,4 @@ Please do not report security vulnerabilities on the public GitHub issue tracker
165
206
  </p>
166
207
  <p align="center">
167
208
  This project is licensed under the MIT license. See the <a href="https://github.com/auth0/omniauth-auth0/blob/master/LICENSE"> LICENSE</a> file for more info.
168
- </p>
209
+ </p>
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jwt'
4
+ require 'securerandom'
5
+
6
+ module OmniAuth
7
+ module Auth0
8
+ # JWTToken class to generate a JWT token for client assertion
9
+ # as per the OAuth 2.0 Client Credentials Grant specification.
10
+ class JWTToken
11
+ attr_reader :client_id, :domain_url, :client_assertion_signing_key, :client_assertion_signing_algorithm
12
+
13
+ def initialize(client_id, domain_url, client_assertion_signing_key, client_assertion_signing_algorithm = nil)
14
+ @client_id = client_id
15
+ @domain_url = domain_url
16
+ @client_assertion_signing_key = client_assertion_signing_key
17
+ @client_assertion_signing_algorithm = client_assertion_signing_algorithm || 'RS256'
18
+ end
19
+
20
+ def jwt_token
21
+ JWT.encode(jwt_payload, client_assertion_signing_key, client_assertion_signing_algorithm)
22
+ end
23
+
24
+ private
25
+
26
+ def jwt_payload
27
+ {
28
+ iss: client_id,
29
+ sub: client_id,
30
+ aud: File.join(domain_url, '/oauth/token'),
31
+ iat: Time.now.utc.to_i,
32
+ exp: Time.now.utc.to_i + 60,
33
+ jti: SecureRandom.uuid
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -7,6 +7,7 @@ require 'omniauth/auth0/errors'
7
7
  module OmniAuth
8
8
  module Auth0
9
9
  # JWT Validator class
10
+ # rubocop:disable Metrics/
10
11
  class JWTValidator
11
12
  attr_accessor :issuer, :domain
12
13
 
@@ -264,12 +265,27 @@ module OmniAuth
264
265
  end
265
266
 
266
267
  def verify_org(id_token, organization)
267
- if organization
268
+ return unless organization
269
+
270
+ validate_as_id = organization.start_with? 'org_'
271
+
272
+ if validate_as_id
268
273
  org_id = id_token['org_id']
269
274
  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")
275
+ raise OmniAuth::Auth0::TokenValidationError,
276
+ 'Organization Id (org_id) claim must be a string present in the ID token'
271
277
  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}'")
278
+ raise OmniAuth::Auth0::TokenValidationError,
279
+ "Organization Id (org_id) claim value mismatch in the ID token; expected '#{organization}', found '#{org_id}'"
280
+ end
281
+ else
282
+ org_name = id_token['org_name']
283
+ if !org_name || !org_name.is_a?(String)
284
+ raise OmniAuth::Auth0::TokenValidationError,
285
+ 'Organization Name (org_name) claim must be a string present in the ID token'
286
+ elsif org_name != organization.downcase
287
+ raise OmniAuth::Auth0::TokenValidationError,
288
+ "Organization Name (org_name) claim value mismatch in the ID token; expected '#{organization}', found '#{org_name}'"
273
289
  end
274
290
  end
275
291
  end
@@ -4,6 +4,7 @@ require 'base64'
4
4
  require 'uri'
5
5
  require 'securerandom'
6
6
  require 'omniauth-oauth2'
7
+ require 'omniauth/auth0/jwt_token'
7
8
  require 'omniauth/auth0/jwt_validator'
8
9
  require 'omniauth/auth0/telemetry'
9
10
  require 'omniauth/auth0/errors'
@@ -13,6 +14,8 @@ module OmniAuth
13
14
  # Auth0 OmniAuth strategy
14
15
  class Auth0 < OmniAuth::Strategies::OAuth2
15
16
  include OmniAuth::Auth0::Telemetry
17
+ AUTHORIZATION_CODE_GRANT_TYPE = 'authorization_code'
18
+ CLIENT_ASSERTION_TYPE = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
16
19
 
17
20
  option :name, 'auth0'
18
21
 
@@ -28,6 +31,8 @@ module OmniAuth
28
31
  options.client_options.authorize_url = '/authorize'
29
32
  options.client_options.token_url = '/oauth/token'
30
33
  options.client_options.userinfo_url = '/userinfo'
34
+ setup_client_options_auth_scheme
35
+
31
36
  super
32
37
  end
33
38
 
@@ -100,25 +105,20 @@ module OmniAuth
100
105
  end
101
106
 
102
107
  def build_access_token
108
+ options.token_params.merge!(client_assertion_signing_key_token_params) if client_assertion_signing_key_auth?
103
109
  options.token_params[:headers] = { 'Auth0-Client' => telemetry_encoded }
104
110
  super
105
111
  end
106
112
 
107
113
  # Declarative override for the request phase of authentication
108
114
  def request_phase
109
- if no_client_id?
110
- # Do we have a client_id for this Application?
111
- fail!(:missing_client_id)
112
- elsif no_client_secret?
113
- # Do we have a client_secret for this Application?
114
- fail!(:missing_client_secret)
115
- elsif no_domain?
116
- # Do we have a domain for this Application?
117
- fail!(:missing_domain)
118
- else
119
- # All checks pass, run the Oauth2 request_phase method.
120
- super
121
- end
115
+ return fail!(:missing_client_id) if no_client_id?
116
+ return fail!(:missing_client_secret) if no_client_secret?
117
+ return fail!(:missing_domain) if no_domain?
118
+ return fail!(:missing_client_assertion_signing_key) if no_client_assertion_signing_key?
119
+
120
+ # All checks pass, run the Oauth2 request_phase method.
121
+ super
122
122
  end
123
123
 
124
124
  def callback_phase
@@ -128,10 +128,32 @@ module OmniAuth
128
128
  end
129
129
 
130
130
  private
131
+
132
+ def client_assertion_signing_key_auth?
133
+ options['client_assertion_signing_key']
134
+ end
135
+
136
+ def client_assertion_signing_key_token_params
137
+ {
138
+ grant_type: AUTHORIZATION_CODE_GRANT_TYPE,
139
+ client_id: options.client_id,
140
+ client_assertion_type: CLIENT_ASSERTION_TYPE,
141
+ client_assertion: jwt_token
142
+ }
143
+ end
144
+
131
145
  def jwt_validator
132
146
  @jwt_validator ||= OmniAuth::Auth0::JWTValidator.new(options)
133
147
  end
134
148
 
149
+ def jwt_token
150
+ OmniAuth::Auth0::JWTToken.new(options.client_id,
151
+ domain_url,
152
+ options.client_assertion_signing_key,
153
+ options.client_assertion_signing_algorithm)
154
+ .jwt_token
155
+ end
156
+
135
157
  # Parse the raw user info.
136
158
  def raw_info
137
159
  return @raw_info if @raw_info
@@ -154,7 +176,7 @@ module OmniAuth
154
176
 
155
177
  # Check if the options include a client_secret
156
178
  def no_client_secret?
157
- ['', nil].include?(options.client_secret)
179
+ ['', nil].include?(options.client_secret) && !options.key?('client_assertion_signing_key')
158
180
  end
159
181
 
160
182
  # Check if the options include a domain
@@ -162,12 +184,24 @@ module OmniAuth
162
184
  ['', nil].include?(options.domain)
163
185
  end
164
186
 
187
+ # Check if the options include a client_assertion_signing_key
188
+ def no_client_assertion_signing_key?
189
+ options.key?('client_assertion_signing_key') && ['', nil].include?(options.client_assertion_signing_key)
190
+ end
191
+
165
192
  # Normalize a domain to a URL.
166
193
  def domain_url
167
194
  domain_url = URI(options.domain)
168
195
  domain_url = URI("https://#{domain_url}") if domain_url.scheme.nil?
169
196
  domain_url.to_s
170
197
  end
198
+
199
+ # Setup the auth_scheme for the client options if using client assertion signing key
200
+ def setup_client_options_auth_scheme
201
+ return unless client_assertion_signing_key_auth?
202
+
203
+ options.client_options.auth_scheme = :request_body
204
+ end
171
205
  end
172
206
  end
173
207
  end
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module Auth0
3
- VERSION = '3.1.0'.freeze
3
+ VERSION = '3.2.0'.freeze
4
4
  end
5
5
  end
@@ -21,6 +21,7 @@ omniauth-auth0 is the OmniAuth strategy for Auth0.
21
21
  s.executables = `git ls-files -- bin/*`.split('\n').map{ |f| File.basename(f) }
22
22
  s.require_paths = ['lib']
23
23
 
24
+ s.add_runtime_dependency 'jwt', '~> 2'
24
25
  s.add_runtime_dependency 'omniauth', '~> 2'
25
26
  s.add_runtime_dependency 'omniauth-oauth2', '~> 1'
26
27
 
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'json'
5
+ require 'jwt'
6
+
7
+ describe OmniAuth::Auth0::JWTToken do
8
+ let(:client_id) { 'CLIENT_ID' }
9
+ let(:domain_url) { 'https://samples.auth0.com' }
10
+ let(:client_assertion_signing_key) { OpenSSL::PKey::RSA.generate(2048) }
11
+
12
+ describe '#jwt_token' do
13
+ it 'generates a valid JWT token' do
14
+ uuid = '12345678-1234-5678-1234-567812345678'
15
+ allow(SecureRandom).to receive(:uuid).and_return(uuid)
16
+
17
+ jwt_token = described_class.new(client_id,
18
+ domain_url,
19
+ client_assertion_signing_key,
20
+ 'RS256')
21
+ .jwt_token
22
+ decoded_token = JWT.decode(jwt_token, client_assertion_signing_key, true, { algorithm: 'RS256' })
23
+
24
+ expect(decoded_token[0]['iss']).to eq(client_id)
25
+ expect(decoded_token[0]['sub']).to eq(client_id)
26
+ expect(decoded_token[0]['aud']).to eq("#{domain_url}/oauth/token")
27
+ expect(decoded_token[0]['iat']).to be_within(5).of(Time.now.utc.to_i)
28
+ expect(decoded_token[0]['exp']).to eq(decoded_token[0]['iat'] + 60)
29
+ expect(decoded_token[0]['jti']).to eq(uuid)
30
+ end
31
+
32
+ it 'defaults to RS256 algorithm if not specified' do
33
+ uuid = '12345678-1234-5678-1234-567812345678'
34
+ allow(SecureRandom).to receive(:uuid).and_return(uuid)
35
+
36
+ jwt_token = described_class.new(client_id, domain_url, client_assertion_signing_key).jwt_token
37
+ decoded_token = JWT.decode(jwt_token, client_assertion_signing_key, true, { algorithm: 'RS256' })
38
+
39
+ expect(decoded_token[0]['iss']).to eq(client_id)
40
+ expect(decoded_token[0]['sub']).to eq(client_id)
41
+ expect(decoded_token[0]['aud']).to eq("#{domain_url}/oauth/token")
42
+ expect(decoded_token[0]['iat']).to be_within(5).of(Time.now.utc.to_i)
43
+ expect(decoded_token[0]['exp']).to eq(decoded_token[0]['iat'] + 60)
44
+ expect(decoded_token[0]['jti']).to eq(uuid)
45
+ end
46
+
47
+ context 'when using ES256 algorithm' do
48
+ let(:client_assertion_signing_key) { OpenSSL::PKey::EC.generate('prime256v1') }
49
+
50
+ it 'generates a valid JWT token' do
51
+ uuid = '12345678-1234-5678-1234-567812345678'
52
+ allow(SecureRandom).to receive(:uuid).and_return(uuid)
53
+ jwt_token = described_class.new(client_id,
54
+ domain_url,
55
+ client_assertion_signing_key,
56
+ 'ES256')
57
+ .jwt_token
58
+ decoded_token = JWT.decode(jwt_token, client_assertion_signing_key, true, { algorithm: 'ES256' })
59
+
60
+ expect(decoded_token[0]['iss']).to eq(client_id)
61
+ expect(decoded_token[0]['sub']).to eq(client_id)
62
+ expect(decoded_token[0]['aud']).to eq("#{domain_url}/oauth/token")
63
+ expect(decoded_token[0]['iat']).to be_within(5).of(Time.now.utc.to_i)
64
+ expect(decoded_token[0]['exp']).to eq(decoded_token[0]['iat'] + 60)
65
+ expect(decoded_token[0]['jti']).to eq(uuid)
66
+ end
67
+
68
+ it 'accepts client_assertion_signing_key_token_params as a string' do
69
+ uuid = '12345678-1234-5678-1234-567812345678'
70
+ allow(SecureRandom).to receive(:uuid).and_return(uuid)
71
+ jwt_token = described_class.new(client_id,
72
+ domain_url,
73
+ client_assertion_signing_key,
74
+ 'ES256')
75
+ .jwt_token
76
+ decoded_token = JWT.decode(jwt_token, client_assertion_signing_key, true, { algorithm: 'ES256' })
77
+
78
+ expect(decoded_token[0]['iss']).to eq(client_id)
79
+ expect(decoded_token[0]['sub']).to eq(client_id)
80
+ expect(decoded_token[0]['aud']).to eq("#{domain_url}/oauth/token")
81
+ expect(decoded_token[0]['iat']).to be_within(5).of(Time.now.utc.to_i)
82
+ expect(decoded_token[0]['exp']).to eq(decoded_token[0]['iat'] + 60)
83
+ expect(decoded_token[0]['jti']).to eq(uuid)
84
+ end
85
+ end
86
+ end
87
+ end
@@ -476,41 +476,119 @@ 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' do
480
- payload = {
481
- iss: "https://#{domain}/",
482
- sub: 'sub',
483
- aud: client_id,
484
- exp: future_timecode,
485
- iat: past_timecode
486
- }
479
+ context 'Organization claim validation' do
480
+ it 'should fail when authorize params has organization but org_id is missing in the token' do
481
+ payload = {
482
+ iss: "https://#{domain}/",
483
+ sub: 'sub',
484
+ aud: client_id,
485
+ exp: future_timecode,
486
+ iat: past_timecode
487
+ }
487
488
 
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
489
+ token = make_hs256_token(payload)
490
+ expect do
491
+ jwt_validator.verify(token, { organization: 'org_123' })
492
+ end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and having_attributes({
493
+ message: "Organization Id (org_id) claim must be a string present in the ID token"
494
+ }))
495
+ end
495
496
 
496
- it 'should fail when authorize params has organization but token org_id does not match' 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
- }
497
+ it 'should fail when authorize params has organization but org_name is missing in the token' do
498
+ payload = {
499
+ iss: "https://#{domain}/",
500
+ sub: 'sub',
501
+ aud: client_id,
502
+ exp: future_timecode,
503
+ iat: past_timecode
504
+ }
505
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
506
+ token = make_hs256_token(payload)
507
+ expect do
508
+ jwt_validator.verify(token, { organization: 'my-organization' })
509
+ end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and(having_attributes({
510
+ message: 'Organization Name (org_name) claim must be a string present in the ID token'
511
+ })))
512
+ end
513
513
 
514
+ it 'should fail when authorize params has organization but token org_id does not match' do
515
+ payload = {
516
+ iss: "https://#{domain}/",
517
+ sub: 'sub',
518
+ aud: client_id,
519
+ exp: future_timecode,
520
+ iat: past_timecode,
521
+ org_id: 'org_5678'
522
+ }
523
+
524
+ token = make_hs256_token(payload)
525
+ expect do
526
+ jwt_validator.verify(token, { organization: 'org_1234' })
527
+ end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and(having_attributes({
528
+ message: "Organization Id (org_id) claim value mismatch in the ID token; expected 'org_1234', found 'org_5678'"
529
+ })))
530
+ end
531
+
532
+ it 'should fail when authorize params has organization but token org_name does not match' do
533
+ payload = {
534
+ iss: "https://#{domain}/",
535
+ sub: 'sub',
536
+ aud: client_id,
537
+ exp: future_timecode,
538
+ iat: past_timecode,
539
+ org_name: 'another-organization'
540
+ }
541
+
542
+ token = make_hs256_token(payload)
543
+ expect do
544
+ jwt_validator.verify(token, { organization: 'my-organization' })
545
+ end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and(having_attributes({
546
+ message: "Organization Name (org_name) claim value mismatch in the ID token; expected 'my-organization', found 'another-organization'"
547
+ })))
548
+ end
549
+
550
+ it 'should not fail when correctly given an organization ID' do
551
+ payload = {
552
+ iss: "https://#{domain}/",
553
+ sub: 'sub',
554
+ aud: client_id,
555
+ exp: future_timecode,
556
+ iat: past_timecode,
557
+ org_id: 'org_1234'
558
+ }
559
+
560
+ token = make_hs256_token(payload)
561
+ jwt_validator.verify(token, { organization: 'org_1234' })
562
+ end
563
+
564
+ it 'should not fail when correctly given an organization name' do
565
+ payload = {
566
+ iss: "https://#{domain}/",
567
+ sub: 'sub',
568
+ aud: client_id,
569
+ exp: future_timecode,
570
+ iat: past_timecode,
571
+ org_name: 'my-organization'
572
+ }
573
+
574
+ token = make_hs256_token(payload)
575
+ jwt_validator.verify(token, { organization: 'my-organization' })
576
+ end
577
+
578
+ it 'should not fail when given an organization name in a different casing' do
579
+ payload = {
580
+ iss: "https://#{domain}/",
581
+ sub: 'sub',
582
+ aud: client_id,
583
+ exp: future_timecode,
584
+ iat: past_timecode,
585
+ org_name: 'my-organization'
586
+ }
587
+
588
+ token = make_hs256_token(payload)
589
+ jwt_validator.verify(token, { organization: 'MY-ORGANIZATION' })
590
+ end
591
+ end
514
592
  it 'should fail for RS256 token when kid is incorrect' do
515
593
  domain = 'example.org'
516
594
  sub = 'abc123'