workos 1.6.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd493c247c202074fa3d93d6f4db6f1cb4cffb19b63f140eeb37a3236255be1a
4
- data.tar.gz: a266a358383a5242299a2df002b04486d6ef1203f0d3448736b6d5904d657643
3
+ metadata.gz: e98cbe7f34c4d550972ac7b4dc734e17ed9b2390b08898d2b20fdf5e69da71ea
4
+ data.tar.gz: c998bf772be7cc75e1730debd7efefa764d87676c62b325daf45784846ce3a12
5
5
  SHA512:
6
- metadata.gz: d05f397238b7e94d6f8e7e513523de96c87da44042c65638dbe8ce947076b5383f38491997a887a30e05a0c47e4193178dd39f0e4c62b5f14ebb1fcfb40b3299
7
- data.tar.gz: 28158f92efaff774bbfaaf02e9be76552dd94bfebb996515824e278faf4011b4996846990074e30694f4306ba26c2cb76440294a020e5832b8bf25c3c504ccb3
6
+ metadata.gz: 01d4bcee2864d6a8b58e8cd3ffef78d77e11028bfbcd9005c4a2cecafaabe0cec97856f94b70aa9391dee50d08502ed8d7afa9456763d16a44f0fcc78a912694
7
+ data.tar.gz: ae83d9e5e204771f3d261a2f3135e077cc8b19d700ccf7984447e5536297ba65fba3779c3988daf612ce2c9624c9a825b8dd9b0e633e47c8839f3466a6837440
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.0.1
1
+ 3.0.2
@@ -66,10 +66,10 @@ blocks:
66
66
  - sem-version ruby 2.7.3
67
67
  - bundle install
68
68
  - bundle exec rspec
69
- - name: Ruby 3.0.1
69
+ - name: Ruby 3.0.2
70
70
  commands:
71
71
  - checkout
72
- - sem-version ruby 3.0.1
72
+ - sem-version ruby 3.0.2
73
73
  - bundle install
74
74
  - bundle exec rspec
75
75
  promotions:
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- workos (1.6.0)
4
+ workos (2.1.1)
5
5
  sorbet-runtime (~> 0.5)
6
6
 
7
7
  GEM
@@ -60,7 +60,7 @@ GEM
60
60
  simplecov_json_formatter (0.1.2)
61
61
  sorbet (0.5.6388)
62
62
  sorbet-static (= 0.5.6388)
63
- sorbet-runtime (0.5.9094)
63
+ sorbet-runtime (0.5.9528)
64
64
  sorbet-static (0.5.6388-universal-darwin-14)
65
65
  sorbet-static (0.5.6388-universal-darwin-15)
66
66
  sorbet-static (0.5.6388-universal-darwin-16)
@@ -93,4 +93,4 @@ DEPENDENCIES
93
93
  yard
94
94
 
95
95
  BUNDLED WITH
96
- 2.2.16
96
+ 2.2.33
@@ -21,7 +21,7 @@ module WorkOS
21
21
  @name = T.let(raw.name, String)
22
22
  @connection_type = T.let(raw.connection_type, String)
23
23
  @domains = T.let(raw.domains, Array)
24
- @organization_id = T.let(raw.organization_id, String)
24
+ @organization_id = raw.organization_id
25
25
  @state = T.let(raw.state, String)
26
26
  @status = T.let(raw.status, String)
27
27
  @created_at = T.let(raw.created_at, String)
@@ -17,10 +17,10 @@ module WorkOS
17
17
 
18
18
  @id = T.let(raw.id, String)
19
19
  @name = T.let(raw.name, String)
20
- @domain = T.let(raw.domain, String)
20
+ @domain = raw.domain
21
21
  @type = T.let(raw.type, String)
22
22
  @state = T.let(raw.state, String)
23
- @organization_id = T.let(raw.organization_id, String)
23
+ @organization_id = raw.organization_id
24
24
  @created_at = T.let(raw.created_at, String)
25
25
  @updated_at = T.let(raw.updated_at, String)
26
26
  end
@@ -53,6 +53,35 @@ module WorkOS
53
53
  )
54
54
  end
55
55
 
56
+ # Retrieve directory.
57
+ #
58
+ # @param [String] id Directory unique identifier
59
+ #
60
+ # @example
61
+ # WorkOS::SSO.get_directory(id: 'directory_01FK17DWRHH7APAFXT5B52PV0W')
62
+ # => #<WorkOS::Directory:0x00007fb6e4193d20
63
+ # @id="directory_01FK17DWRHH7APAFXT5B52PV0W",
64
+ # @name="Foo Corp",
65
+ # @domain="foo-corp.com",
66
+ # @type="okta scim v2.0",
67
+ # @state="linked",
68
+ # @organization_id="org_01F6Q6TFP7RD2PF6J03ANNWDKV",
69
+ # @created_at="2021-10-27T15:55:47.856Z",
70
+ # @updated_at="2021-10-27T16:03:43.990Z"
71
+ #
72
+ # @return [WorkOS::Directory]
73
+ sig { params(id: String).returns(WorkOS::Directory) }
74
+ def get_directory(id:)
75
+ request = get_request(
76
+ auth: true,
77
+ path: "/directories/#{id}",
78
+ )
79
+
80
+ response = execute_request(request: request)
81
+
82
+ WorkOS::Directory.new(response.body)
83
+ end
84
+
56
85
  # Retrieve directory groups.
57
86
  #
58
87
  # @param [Hash] options An options hash
@@ -23,7 +23,7 @@ module WorkOS
23
23
  @email = T.let(raw.email, String)
24
24
  @first_name = raw.first_name
25
25
  @last_name = raw.last_name
26
- @organization_id = T.let(raw.organization_id, String)
26
+ @organization_id = raw.organization_id
27
27
  @connection_id = T.let(raw.connection_id, String)
28
28
  @connection_type = T.let(raw.connection_type, String)
29
29
  @idp_id = raw.idp_id
data/lib/workos/sso.rb CHANGED
@@ -21,23 +21,27 @@ module WorkOS
21
21
  # Generate an Oauth2 authorization URL where your users will
22
22
  # authenticate using the configured SSO Identity Provider.
23
23
  #
24
+ # @param [String] redirect_uri The URI where users are directed
25
+ # after completing the authentication step. Must match a
26
+ # configured redirect URI on your WorkOS dashboard.
27
+ # @param [String] client_id The WorkOS client ID for the environment
28
+ # where you've configured your SSO connection.
24
29
  # @param [String] domain The domain for the relevant SSO Connection
25
- # configured on your WorkOS dashboard. One of provider or domain is
26
- # required
30
+ # configured on your WorkOS dashboard. One of provider, domain,
31
+ # connection, or organization is required.
32
+ # The domain is deprecated.
27
33
  # @param [String] provider A provider name for an Identity Provider
28
- # configured on your WorkOS dashboard. Only 'Google' is supported.
34
+ # configured on your WorkOS dashboard. Only 'GoogleOAuth' and
35
+ # 'MicrosoftOAuth' are supported.
29
36
  # @param [String] connection The ID for a Connection configured on
30
37
  # WorkOS.
31
- # @param [String] client_id The WorkOS client ID for the environment
32
- # where you've configured your SSO connection.
33
- # @param [String] redirect_uri The URI where users are directed
34
- # after completing the authentication step. Must match a
35
- # configured redirect URI on your WorkOS dashboard.
36
- # @param [String] state An aribtrary state object
38
+ # @param [String] organization The ID for an Organization configured
39
+ # on WorkOS.
40
+ # @param [String] state An arbitrary state object
37
41
  # that is preserved and available to the client in the response.
38
42
  # @example
39
43
  # WorkOS::SSO.authorization_url(
40
- # domain: 'acme.com',
44
+ # connection: 'conn_123',
41
45
  # client_id: 'project_01DG5TGK363GRVXP3ZS40WNGEZ',
42
46
  # redirect_uri: 'https://workos.com/callback',
43
47
  # state: {
@@ -45,19 +49,23 @@ module WorkOS
45
49
  # }.to_s
46
50
  # )
47
51
  #
48
- # => "https://api.workos.com/sso/authorize?domain=acme.com" \
52
+ # => "https://api.workos.com/sso/authorize?connection=conn_123" \
49
53
  # "&client_id=project_01DG5TGK363GRVXP3ZS40WNGEZ" \
50
54
  # "&redirect_uri=https%3A%2F%2Fworkos.com%2Fcallback&" \
51
55
  # "response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdocs%22%7D"
52
56
  #
53
57
  # @return [String]
58
+ # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
54
59
  sig do
55
60
  params(
56
61
  redirect_uri: String,
57
62
  client_id: T.nilable(String),
58
63
  domain: T.nilable(String),
64
+ domain_hint: T.nilable(String),
65
+ login_hint: T.nilable(String),
59
66
  provider: T.nilable(String),
60
67
  connection: T.nilable(String),
68
+ organization: T.nilable(String),
61
69
  state: T.nilable(String),
62
70
  ).returns(String)
63
71
  end
@@ -65,14 +73,23 @@ module WorkOS
65
73
  redirect_uri:,
66
74
  client_id: nil,
67
75
  domain: nil,
76
+ domain_hint: nil,
77
+ login_hint: nil,
68
78
  provider: nil,
69
79
  connection: nil,
80
+ organization: nil,
70
81
  state: ''
71
82
  )
83
+ if domain
84
+ warn '[DEPRECATION] `domain` is deprecated.
85
+ Please use `organization` instead.'
86
+ end
87
+
72
88
  validate_authorization_url_arguments(
73
89
  provider: provider,
74
90
  domain: domain,
75
91
  connection: connection,
92
+ organization: organization,
76
93
  )
77
94
 
78
95
  query = URI.encode_www_form({
@@ -81,12 +98,16 @@ module WorkOS
81
98
  response_type: 'code',
82
99
  state: state,
83
100
  domain: domain,
101
+ domain_hint: domain_hint,
102
+ login_hint: login_hint,
84
103
  provider: provider,
85
104
  connection: connection,
105
+ organization: organization,
86
106
  }.compact)
87
107
 
88
108
  "https://#{WorkOS::API_HOSTNAME}/sso/authorize?#{query}"
89
109
  end
110
+ # rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
90
111
 
91
112
  sig do
92
113
  params(
@@ -229,16 +250,18 @@ module WorkOS
229
250
  domain: T.nilable(String),
230
251
  provider: T.nilable(String),
231
252
  connection: T.nilable(String),
253
+ organization: T.nilable(String),
232
254
  ).void
233
255
  end
234
256
  def validate_authorization_url_arguments(
235
257
  domain:,
236
258
  provider:,
237
- connection:
259
+ connection:,
260
+ organization:
238
261
  )
239
- if [domain, provider, connection].all?(&:nil?)
240
- raise ArgumentError, 'Either connection, domain, or ' \
241
- 'provider is required.'
262
+ if [domain, provider, connection, organization].all?(&:nil?)
263
+ raise ArgumentError, 'Either connection, domain, ' \
264
+ 'provider, or organization is required.'
242
265
  end
243
266
 
244
267
  return unless provider && !PROVIDERS.include?(provider)
@@ -10,7 +10,7 @@ module WorkOS
10
10
  const :name, String
11
11
  const :connection_type, String
12
12
  const :domains, T::Array[T.untyped]
13
- const :organization_id, String
13
+ const :organization_id, T.nilable(String)
14
14
  const :state, String
15
15
  const :status, String
16
16
  const :created_at, String
@@ -8,10 +8,10 @@ module WorkOS
8
8
  class DirectoryStruct < T::Struct
9
9
  const :id, String
10
10
  const :name, String
11
- const :domain, String
11
+ const :domain, T.nilable(String)
12
12
  const :type, String
13
13
  const :state, String
14
- const :organization_id, String
14
+ const :organization_id, T.nilable(String)
15
15
  const :created_at, String
16
16
  const :updated_at, String
17
17
  end
@@ -10,7 +10,7 @@ module WorkOS
10
10
  const :email, String
11
11
  const :first_name, T.nilable(String)
12
12
  const :last_name, T.nilable(String)
13
- const :organization_id, String
13
+ const :organization_id, T.nilable(String)
14
14
  const :connection_id, String
15
15
  const :connection_type, String
16
16
  const :idp_id, T.nilable(String)
@@ -2,5 +2,5 @@
2
2
  # typed: strong
3
3
 
4
4
  module WorkOS
5
- VERSION = '1.6.0'
5
+ VERSION = '2.1.1'
6
6
  end
@@ -65,7 +65,7 @@ module WorkOS
65
65
  tolerance: Integer,
66
66
  ).returns(T::Boolean)
67
67
  end
68
- # rubocop:disable Metrics/MethodLength
68
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
69
69
  def verify_header(
70
70
  payload:,
71
71
  sig_header:,
@@ -86,7 +86,9 @@ module WorkOS
86
86
  )
87
87
  end
88
88
 
89
- if timestamp < Time.now - tolerance
89
+ timestamp_to_time = Time.at(timestamp.to_i / 1000)
90
+
91
+ if timestamp_to_time < Time.now - tolerance
90
92
  raise WorkOS::SignatureVerificationError.new(
91
93
  message: 'Timestamp outside the tolerance zone',
92
94
  )
@@ -101,7 +103,7 @@ module WorkOS
101
103
 
102
104
  true
103
105
  end
104
- # rubocop:enable Metrics/MethodLength
106
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
105
107
 
106
108
  sig do
107
109
  params(
@@ -122,12 +124,12 @@ module WorkOS
122
124
  timestamp = timestamp.sub('t=', '')
123
125
  signature_hash = signature_hash.sub('v1=', '')
124
126
 
125
- [Time.at(timestamp.to_i), signature_hash]
127
+ [timestamp, signature_hash]
126
128
  end
127
129
 
128
130
  sig do
129
131
  params(
130
- timestamp: Time,
132
+ timestamp: String,
131
133
  payload: String,
132
134
  secret: String,
133
135
  ).returns(String)
@@ -137,7 +139,7 @@ module WorkOS
137
139
  payload:,
138
140
  secret:
139
141
  )
140
- unhashed_string = "#{timestamp.to_i}.#{payload}"
142
+ unhashed_string = "#{timestamp}.#{payload}"
141
143
  digest = OpenSSL::Digest.new('sha256')
142
144
  OpenSSL::HMAC.hexdigest(digest, secret, unhashed_string)
143
145
  end
@@ -15,7 +15,7 @@ describe WorkOS::DirectorySync do
15
15
  VCR.use_cassette 'directory_sync/list_directories/with_no_options' do
16
16
  directories = described_class.list_directories
17
17
 
18
- expect(directories.data.size).to eq(3)
18
+ expect(directories.data.size).to eq(10)
19
19
  expect(directories.list_metadata).to eq(expected_metadata)
20
20
  end
21
21
  end
@@ -46,7 +46,7 @@ describe WorkOS::DirectorySync do
46
46
  context 'with search option' do
47
47
  it 'forms the proper request to the API' do
48
48
  request_args = [
49
- '/directories?search=Foo',
49
+ '/directories?search=Testing',
50
50
  'Content-Type' => 'application/json'
51
51
  ]
52
52
 
@@ -57,10 +57,11 @@ describe WorkOS::DirectorySync do
57
57
 
58
58
  VCR.use_cassette 'directory_sync/list_directories/with_search' do
59
59
  directories = described_class.list_directories(
60
- search: 'Foo',
60
+ search: 'Testing',
61
61
  )
62
62
 
63
- expect(directories.data.size).to eq(1)
63
+ expect(directories.data.size).to eq(2)
64
+ expect(directories.data[0].name).to include('Testing')
64
65
  end
65
66
  end
66
67
  end
@@ -68,7 +69,7 @@ describe WorkOS::DirectorySync do
68
69
  context 'with the before option' do
69
70
  it 'forms the proper request to the API' do
70
71
  request_args = [
71
- '/directories?before=before-id',
72
+ '/directories?before=directory_01FGCPNV312FHFRCX0BYWHVSE1',
72
73
  'Content-Type' => 'application/json'
73
74
  ]
74
75
 
@@ -79,10 +80,10 @@ describe WorkOS::DirectorySync do
79
80
 
80
81
  VCR.use_cassette 'directory_sync/list_directories/with_before' do
81
82
  directories = described_class.list_directories(
82
- before: 'before-id',
83
+ before: 'directory_01FGCPNV312FHFRCX0BYWHVSE1',
83
84
  )
84
85
 
85
- expect(directories.data.size).to eq(3)
86
+ expect(directories.data.size).to eq(6)
86
87
  end
87
88
  end
88
89
  end
@@ -90,7 +91,7 @@ describe WorkOS::DirectorySync do
90
91
  context 'with the after option' do
91
92
  it 'forms the proper request to the API' do
92
93
  request_args = [
93
- '/directories?after=after-id',
94
+ '/directories?after=directory_01FGCPNV312FHFRCX0BYWHVSE1',
94
95
  'Content-Type' => 'application/json'
95
96
  ]
96
97
 
@@ -100,9 +101,9 @@ describe WorkOS::DirectorySync do
100
101
  and_return(expected_request)
101
102
 
102
103
  VCR.use_cassette 'directory_sync/list_directories/with_after' do
103
- directories = described_class.list_directories(after: 'after-id')
104
+ directories = described_class.list_directories(after: 'directory_01FGCPNV312FHFRCX0BYWHVSE1')
104
105
 
105
- expect(directories.data.size).to eq(3)
106
+ expect(directories.data.size).to eq(4)
106
107
  end
107
108
  end
108
109
  end
@@ -142,6 +143,38 @@ describe WorkOS::DirectorySync do
142
143
  end
143
144
  end
144
145
 
146
+ describe '.get_directory' do
147
+ context 'with a valid id' do
148
+ it 'gets the directory details' do
149
+ VCR.use_cassette('directory_sync/get_directory_with_valid_id') do
150
+ directory = WorkOS::DirectorySync.get_directory(
151
+ id: 'directory_01FK17DWRHH7APAFXT5B52PV0W',
152
+ )
153
+
154
+ expect(directory.id).to eq('directory_01FK17DWRHH7APAFXT5B52PV0W')
155
+ expect(directory.name).to eq('Testing Active Attribute')
156
+ expect(directory.domain).to eq('example.me')
157
+ expect(directory.type).to eq('azure scim v2.0')
158
+ expect(directory.state).to eq('linked')
159
+ expect(directory.organization_id).to eq('org_01F6Q6TFP7RD2PF6J03ANNWDKV')
160
+ end
161
+ end
162
+ end
163
+
164
+ context 'with an invalid id' do
165
+ it 'raises an error' do
166
+ VCR.use_cassette('directory_sync/get_directory_with_invalid_id') do
167
+ expect do
168
+ WorkOS::DirectorySync.get_directory(id: 'invalid')
169
+ end.to raise_error(
170
+ WorkOS::APIError,
171
+ "Status 404, Directory not found: 'invalid'. - request ID: ",
172
+ )
173
+ end
174
+ end
175
+ end
176
+ end
177
+
145
178
  describe '.list_groups' do
146
179
  context 'with no options' do
147
180
  it 'raises an error' do
@@ -109,7 +109,145 @@ describe WorkOS::SSO do
109
109
  end
110
110
  end
111
111
 
112
- context 'with neither connection, domain, or provider' do
112
+ context 'with a domain' do
113
+ let(:args) do
114
+ {
115
+ domain: 'foo.com',
116
+ client_id: 'workos-proj-123',
117
+ redirect_uri: 'foo.com/auth/callback',
118
+ state: {
119
+ next_page: '/dashboard/edit',
120
+ }.to_s,
121
+ }
122
+ end
123
+ it 'returns a valid URL' do
124
+ authorization_url = described_class.authorization_url(**args)
125
+
126
+ expect(URI.parse(authorization_url)).to be_a URI
127
+ end
128
+
129
+ it 'returns the expected hostname' do
130
+ authorization_url = described_class.authorization_url(**args)
131
+
132
+ expect(URI.parse(authorization_url).host).to eq(WorkOS::API_HOSTNAME)
133
+ end
134
+
135
+ it 'returns the expected query string' do
136
+ authorization_url = described_class.authorization_url(**args)
137
+
138
+ expect(URI.parse(authorization_url).query).to eq(
139
+ 'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
140
+ '&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2F' \
141
+ 'edit%22%7D&domain=foo.com',
142
+ )
143
+ end
144
+ end
145
+
146
+ context 'with a domain_hint' do
147
+ let(:args) do
148
+ {
149
+ connection: 'connection_123',
150
+ domain_hint: 'foo.com',
151
+ client_id: 'workos-proj-123',
152
+ redirect_uri: 'foo.com/auth/callback',
153
+ state: {
154
+ next_page: '/dashboard/edit',
155
+ }.to_s,
156
+ }
157
+ end
158
+ it 'returns a valid URL' do
159
+ authorization_url = described_class.authorization_url(**args)
160
+
161
+ expect(URI.parse(authorization_url)).to be_a URI
162
+ end
163
+
164
+ it 'returns the expected hostname' do
165
+ authorization_url = described_class.authorization_url(**args)
166
+
167
+ expect(URI.parse(authorization_url).host).to eq(WorkOS::API_HOSTNAME)
168
+ end
169
+
170
+ it 'returns the expected query string' do
171
+ authorization_url = described_class.authorization_url(**args)
172
+
173
+ expect(URI.parse(authorization_url).query).to eq(
174
+ 'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
175
+ '&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2' \
176
+ 'Fedit%22%7D&domain_hint=foo.com&connection=connection_123',
177
+ )
178
+ end
179
+ end
180
+
181
+ context 'with a login_hint' do
182
+ let(:args) do
183
+ {
184
+ connection: 'connection_123',
185
+ login_hint: 'foo@workos.com',
186
+ client_id: 'workos-proj-123',
187
+ redirect_uri: 'foo.com/auth/callback',
188
+ state: {
189
+ next_page: '/dashboard/edit',
190
+ }.to_s,
191
+ }
192
+ end
193
+ it 'returns a valid URL' do
194
+ authorization_url = described_class.authorization_url(**args)
195
+
196
+ expect(URI.parse(authorization_url)).to be_a URI
197
+ end
198
+
199
+ it 'returns the expected hostname' do
200
+ authorization_url = described_class.authorization_url(**args)
201
+
202
+ expect(URI.parse(authorization_url).host).to eq(WorkOS::API_HOSTNAME)
203
+ end
204
+
205
+ it 'returns the expected query string' do
206
+ authorization_url = described_class.authorization_url(**args)
207
+
208
+ expect(URI.parse(authorization_url).query).to eq(
209
+ 'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
210
+ '&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2' \
211
+ 'Fedit%22%7D&login_hint=foo%40workos.com&connection=connection_123',
212
+ )
213
+ end
214
+ end
215
+
216
+ context 'with an organization' do
217
+ let(:args) do
218
+ {
219
+ organization: 'org_123',
220
+ client_id: 'workos-proj-123',
221
+ redirect_uri: 'foo.com/auth/callback',
222
+ state: {
223
+ next_page: '/dashboard/edit',
224
+ }.to_s,
225
+ }
226
+ end
227
+ it 'returns a valid URL' do
228
+ authorization_url = described_class.authorization_url(**args)
229
+
230
+ expect(URI.parse(authorization_url)).to be_a URI
231
+ end
232
+
233
+ it 'returns the expected hostname' do
234
+ authorization_url = described_class.authorization_url(**args)
235
+
236
+ expect(URI.parse(authorization_url).host).to eq(WorkOS::API_HOSTNAME)
237
+ end
238
+
239
+ it 'returns the expected query string' do
240
+ authorization_url = described_class.authorization_url(**args)
241
+
242
+ expect(URI.parse(authorization_url).query).to eq(
243
+ 'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
244
+ '&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2F' \
245
+ 'edit%22%7D&organization=org_123',
246
+ )
247
+ end
248
+ end
249
+
250
+ context 'with neither connection, domain, provider, or organization' do
113
251
  let(:args) do
114
252
  {
115
253
  client_id: 'workos-proj-123',
@@ -124,7 +262,7 @@ describe WorkOS::SSO do
124
262
  described_class.authorization_url(**args)
125
263
  end.to raise_error(
126
264
  ArgumentError,
127
- 'Either connection, domain, or provider is required.',
265
+ 'Either connection, domain, provider, or organization is required.',
128
266
  )
129
267
  end
130
268
  end
@@ -177,7 +177,7 @@ describe WorkOS::Webhooks do
177
177
  expect do
178
178
  described_class.construct_event(
179
179
  payload: @payload,
180
- sig_header: "t=9999, v1=#{@signature_hash}",
180
+ sig_header: "t=#{@timestamp.to_i - (200 * 1000)}, v1=#{@signature_hash}",
181
181
  secret: @secret,
182
182
  )
183
183
  end.to raise_error(