workos 0.11.2 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64322be12c1dad447bc34d760225e99c47dc6611119ea74dd9a638bac6f23085
4
- data.tar.gz: 99df76eeb89edac09cc58323049efeaad694bf3bd945d07c8d8fb492bb45052f
3
+ metadata.gz: f8a9f985318b4480c50a4d0528cf5036018235833585746e3ed632020fca3d00
4
+ data.tar.gz: bc75b64c4a4ffa8b32ee2b841af1c6bdb39df729bda95cc59d9ad36206cab387
5
5
  SHA512:
6
- metadata.gz: 56de86af09e8c79821cb1789b0ceb27db74ac8f11176ff6b43ee36ebe0b18c0bcc60fd459c35dcfa369bd86a70c0f78724861380689c1afcc21296d77d8a9baa
7
- data.tar.gz: b77ac5436b1d5f7a150778c68e259897576689a032d7490835e6ebf7411ba8dc1b3268548648c60261b0273528901a2d63edc3eb4d1e765cf75de7d4448da83e
6
+ metadata.gz: 56d3896fd8bb4194cbb50464759c9babfe2421e56148827fe282af956fa4fb9f38eb308363e30427bed0ef3596e5c1ba99150f108208835ecdb40921e99bf67e
7
+ data.tar.gz: e5f09155ab5a7e92dc0ccd6a10af885d5802925a7db1fdaf21cbeb9902b231642284ed06aa1ce0806271fceab5f42209d1c3c1c5442c6ea42a780a6264670ce4
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- workos (0.11.2)
4
+ workos (1.0.0)
5
5
  sorbet-runtime (~> 0.5)
6
6
 
7
7
  GEM
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2019 WorkOS
3
+ Copyright (c) 2021 WorkOS
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/lib/workos.rb CHANGED
@@ -35,9 +35,11 @@ module WorkOS
35
35
  autoload :Directory, 'workos/directory'
36
36
  autoload :DirectoryGroup, 'workos/directory_group'
37
37
  autoload :Organization, 'workos/organization'
38
+ autoload :Organizations, 'workos/organizations'
38
39
  autoload :Passwordless, 'workos/passwordless'
39
40
  autoload :Portal, 'workos/portal'
40
41
  autoload :Profile, 'workos/profile'
42
+ autoload :ProfileAndToken, 'workos/profile_and_token'
41
43
  autoload :SSO, 'workos/sso'
42
44
  autoload :DirectoryUser, 'workos/directory_user'
43
45
 
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ require 'net/http'
5
+
6
+ module WorkOS
7
+ # The Organizations module provides resource methods for working with Organizations
8
+ module Organizations
9
+ class << self
10
+ extend T::Sig
11
+ include Base
12
+ include Client
13
+
14
+ # Retrieve a list of organizations that have connections configured
15
+ # within your WorkOS dashboard.
16
+ #
17
+ # @param [Array<String>] domains Filter organizations to only return those
18
+ # that are associated with the provided domains.
19
+ # @param [String] before A pagination argument used to request
20
+ # organizations before the provided Organization ID.
21
+ # @param [String] after A pagination argument used to request
22
+ # organizations after the provided Organization ID.
23
+ # @param [Integer] limit A pagination argument used to limit the number
24
+ # of listed Organizations that are returned.
25
+ sig do
26
+ params(
27
+ options: T::Hash[Symbol, String],
28
+ ).returns(WorkOS::Types::ListStruct)
29
+ end
30
+ def list_organizations(options = {})
31
+ response = execute_request(
32
+ request: get_request(
33
+ path: '/organizations',
34
+ auth: true,
35
+ params: options,
36
+ ),
37
+ )
38
+
39
+ parsed_response = JSON.parse(response.body)
40
+
41
+ organizations = parsed_response['data'].map do |organization|
42
+ ::WorkOS::Organization.new(organization.to_json)
43
+ end
44
+
45
+ WorkOS::Types::ListStruct.new(
46
+ data: organizations,
47
+ list_metadata: parsed_response['listMetadata'],
48
+ )
49
+ end
50
+
51
+ # Get an Organization
52
+ #
53
+ # @param [String] id Organization unique identifier
54
+ #
55
+ # @example
56
+ # WorkOS::Portal.get_organization(id: 'org_02DRA1XNSJDZ19A31F183ECQW9')
57
+ # => #<WorkOS::Organization:0x00007fb6e4193d20
58
+ # @id="org_02DRA1XNSJDZ19A31F183ECQW9",
59
+ # @name="Foo Corp",
60
+ # @domains=
61
+ # [{:object=>"organization_domain",
62
+ # :id=>"org_domain_01E6PK9N3XMD8RHWF7S66380AR",
63
+ # :domain=>"foo-corp.com"}]>
64
+ #
65
+ # @return [WorkOS::Connection]
66
+ sig { params(id: String).returns(WorkOS::Organization) }
67
+ def get_organization(id:)
68
+ request = get_request(
69
+ auth: true,
70
+ path: "/organizations/#{id}",
71
+ )
72
+
73
+ response = execute_request(request: request)
74
+
75
+ WorkOS::Organization.new(response.body)
76
+ end
77
+
78
+ # Create an organization
79
+ #
80
+ # @param [Array<String>] domains List of domains that belong to the
81
+ # organization
82
+ # @param [String] name A unique, descriptive name for the organization
83
+ sig do
84
+ params(
85
+ domains: T::Array[String],
86
+ name: String,
87
+ ).returns(WorkOS::Organization)
88
+ end
89
+ def create_organization(domains:, name:)
90
+ request = post_request(
91
+ auth: true,
92
+ body: { domains: domains, name: name },
93
+ path: '/organizations',
94
+ )
95
+
96
+ response = execute_request(request: request)
97
+ check_and_raise_organization_error(response: response)
98
+
99
+ WorkOS::Organization.new(response.body)
100
+ end
101
+
102
+ # Update an organization
103
+ #
104
+ # @param [String] organization Organization unique identifier
105
+ # @param [Array<String>] domains List of domains that belong to the
106
+ # organization
107
+ # @param [String] name A unique, descriptive name for the organization
108
+ sig do
109
+ params(
110
+ organization: String,
111
+ domains: T::Array[String],
112
+ name: String,
113
+ ).returns(WorkOS::Organization)
114
+ end
115
+ def update_organization(organization:, domains:, name:)
116
+ request = put_request(
117
+ auth: true,
118
+ body: { domains: domains, name: name },
119
+ path: "/organizations/#{organization}",
120
+ )
121
+
122
+ response = execute_request(request: request)
123
+ check_and_raise_organization_error(response: response)
124
+
125
+ WorkOS::Organization.new(response.body)
126
+ end
127
+
128
+ private
129
+
130
+ sig { params(response: Net::HTTPResponse).void }
131
+ def check_and_raise_organization_error(response:)
132
+ begin
133
+ body = JSON.parse(response.body)
134
+ return unless body['message']
135
+
136
+ message = body['message']
137
+ request_id = response['x-request-id']
138
+ rescue StandardError
139
+ message = 'Something went wrong'
140
+ end
141
+
142
+ raise APIError.new(
143
+ message: message,
144
+ http_status: nil,
145
+ request_id: request_id,
146
+ )
147
+ end
148
+ end
149
+ end
150
+ end
data/lib/workos/portal.rb CHANGED
@@ -15,30 +15,6 @@ module WorkOS
15
15
  GENERATE_LINK_INTENTS = WorkOS::Types::Intent.values.map(&:serialize).
16
16
  freeze
17
17
 
18
- # Create an organization
19
- #
20
- # @param [Array<String>] domains List of domains that belong to the
21
- # organization
22
- # @param [String] name A unique, descriptive name for the organization
23
- sig do
24
- params(
25
- domains: T::Array[String],
26
- name: String,
27
- ).returns(WorkOS::Organization)
28
- end
29
- def create_organization(domains:, name:)
30
- request = post_request(
31
- auth: true,
32
- body: { domains: domains, name: name },
33
- path: '/organizations',
34
- )
35
-
36
- response = execute_request(request: request)
37
- check_and_raise_organization_error(response: response)
38
-
39
- WorkOS::Organization.new(response.body)
40
- end
41
-
42
18
  # Generate a link to grant access to an organization's Admin Portal
43
19
  #
44
20
  # @param [String] intent The access scope for the generated Admin Portal
@@ -73,117 +49,8 @@ module WorkOS
73
49
  JSON.parse(response.body)['link']
74
50
  end
75
51
 
76
- # Retrieve a list of organizations that have connections configured
77
- # within your WorkOS dashboard.
78
- #
79
- # @param [Array<String>] domains Filter organizations to only return those
80
- # that are associated with the provided domains.
81
- # @param [String] before A pagination argument used to request
82
- # organizations before the provided Organization ID.
83
- # @param [String] after A pagination argument used to request
84
- # organizations after the provided Organization ID.
85
- # @param [Integer] limit A pagination argument used to limit the number
86
- # of listed Organizations that are returned.
87
- sig do
88
- params(
89
- options: T::Hash[Symbol, String],
90
- ).returns(WorkOS::Types::ListStruct)
91
- end
92
- def list_organizations(options = {})
93
- response = execute_request(
94
- request: get_request(
95
- path: '/organizations',
96
- auth: true,
97
- params: options,
98
- ),
99
- )
100
-
101
- parsed_response = JSON.parse(response.body)
102
-
103
- organizations = parsed_response['data'].map do |organization|
104
- ::WorkOS::Organization.new(organization.to_json)
105
- end
106
-
107
- WorkOS::Types::ListStruct.new(
108
- data: organizations,
109
- list_metadata: parsed_response['listMetadata'],
110
- )
111
- end
112
-
113
- # Get an Organization
114
- #
115
- # @param [String] id Organization unique identifier
116
- #
117
- # @example
118
- # WorkOS::Portal.get_organization(id: 'org_02DRA1XNSJDZ19A31F183ECQW9')
119
- # => #<WorkOS::Organization:0x00007fb6e4193d20
120
- # @id="org_02DRA1XNSJDZ19A31F183ECQW9",
121
- # @name="Foo Corp",
122
- # @domains=
123
- # [{:object=>"organization_domain",
124
- # :id=>"org_domain_01E6PK9N3XMD8RHWF7S66380AR",
125
- # :domain=>"foo-corp.com"}]>
126
- #
127
- # @return [WorkOS::Connection]
128
- sig { params(id: String).returns(WorkOS::Organization) }
129
- def get_organization(id:)
130
- request = get_request(
131
- auth: true,
132
- path: "/organizations/#{id}",
133
- )
134
-
135
- response = execute_request(request: request)
136
-
137
- WorkOS::Organization.new(response.body)
138
- end
139
-
140
- # Update an organization
141
- #
142
- # @param [String] organization Organization unique identifier
143
- # @param [Array<String>] domains List of domains that belong to the
144
- # organization
145
- # @param [String] name A unique, descriptive name for the organization
146
- sig do
147
- params(
148
- organization: String,
149
- domains: T::Array[String],
150
- name: String,
151
- ).returns(WorkOS::Organization)
152
- end
153
- def update_organization(organization:, domains:, name:)
154
- request = put_request(
155
- auth: true,
156
- body: { domains: domains, name: name },
157
- path: "/organizations/#{organization}",
158
- )
159
-
160
- response = execute_request(request: request)
161
- check_and_raise_organization_error(response: response)
162
-
163
- WorkOS::Organization.new(response.body)
164
- end
165
-
166
52
  private
167
53
 
168
- sig { params(response: Net::HTTPResponse).void }
169
- def check_and_raise_organization_error(response:)
170
- begin
171
- body = JSON.parse(response.body)
172
- return unless body['message']
173
-
174
- message = body['message']
175
- request_id = response['x-request-id']
176
- rescue StandardError
177
- message = 'Something went wrong'
178
- end
179
-
180
- raise APIError.new(
181
- message: message,
182
- http_status: nil,
183
- request_id: request_id,
184
- )
185
- end
186
-
187
54
  sig { params(intent: String).void }
188
55
  def validate_intent(intent)
189
56
  return if GENERATE_LINK_INTENTS.include?(intent)
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module WorkOS
5
+ # The ProfileAndToken class represents a Profile and a corresponding
6
+ # Access Token. This class is not meant to be instantiated in user space, and
7
+ # is instantiated internally but exposed.
8
+ class ProfileAndToken
9
+ extend T::Sig
10
+
11
+ attr_accessor :access_token, :profile
12
+
13
+ sig { params(profile_and_token_json: String).void }
14
+ def initialize(profile_and_token_json)
15
+ json = JSON.parse(profile_and_token_json, symbolize_names: true)
16
+
17
+ @access_token = T.let(json[:access_token], String)
18
+ @profile = WorkOS::Profile.new(profile_and_token_json)
19
+ end
20
+
21
+ def to_json(*)
22
+ {
23
+ access_token: access_token,
24
+ profile: profile.to_json,
25
+ }
26
+ end
27
+ end
28
+ end
data/lib/workos/sso.rb CHANGED
@@ -30,8 +30,6 @@ module WorkOS
30
30
  # WorkOS.
31
31
  # @param [String] client_id The WorkOS client ID for the environment
32
32
  # where you've configured your SSO connection.
33
- # @param [String] project_id The WorkOS project ID for the project.
34
- # The project_id is deprecated in Dashboard2.
35
33
  # @param [String] redirect_uri The URI where users are directed
36
34
  # after completing the authentication step. Must match a
37
35
  # configured redirect URI on your WorkOS dashboard.
@@ -56,7 +54,6 @@ module WorkOS
56
54
  sig do
57
55
  params(
58
56
  redirect_uri: String,
59
- project_id: T.nilable(String),
60
57
  client_id: T.nilable(String),
61
58
  domain: T.nilable(String),
62
59
  provider: T.nilable(String),
@@ -64,22 +61,14 @@ module WorkOS
64
61
  state: T.nilable(String),
65
62
  ).returns(String)
66
63
  end
67
- # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
68
64
  def authorization_url(
69
65
  redirect_uri:,
70
- project_id: nil,
71
66
  client_id: nil,
72
67
  domain: nil,
73
68
  provider: nil,
74
69
  connection: nil,
75
70
  state: ''
76
71
  )
77
- if project_id
78
- warn '[DEPRECATION] `project_id` is deprecated.
79
- Please use `client_id` instead.'
80
- client_id = project_id
81
- end
82
-
83
72
  validate_authorization_url_arguments(
84
73
  provider: provider,
85
74
  domain: domain,
@@ -98,46 +87,21 @@ module WorkOS
98
87
 
99
88
  "https://#{WorkOS::API_HOSTNAME}/sso/authorize?#{query}"
100
89
  end
101
- # rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
102
90
 
103
91
  # Fetch the profile details for the authenticated SSO user.
104
92
  #
105
93
  # @param [String] code The authorization code provided in the callback URL
106
94
  # @param [String] client_id The WorkOS client ID for the environment
107
- # where you've configured your SSO connection
108
- # @param [String] project_id The WorkOS project ID for the project.
109
- # The project_id is deprecated in Dashboard2.
110
- #
111
- # @example
112
- # WorkOS::SSO.profile(
113
- # code: 'acme.com',
114
- # client_id: 'project_01DG5TGK363GRVXP3ZS40WNGEZ'
115
- # )
116
- # => #<WorkOS::Profile:0x00007fb6e4193d20
117
- # @id="prof_01DRA1XNSJDZ19A31F183ECQW5",
118
- # @email="demo@workos-okta.com",
119
- # @first_name="WorkOS",
120
- # @connection_type="OktaSAML",
121
- # @last_name="Demo",
122
- # @idp_id="00u1klkowm8EGah2H357",
123
- # @access_token="01DVX6QBS3EG6FHY2ESAA5Q65X"
124
- # >
95
+ # where you've configured your SSO connection
125
96
  #
126
- # @return [WorkOS::Profile]
97
+ # @return [WorkOS::ProfileAndToken]
127
98
  sig do
128
99
  params(
129
100
  code: String,
130
- project_id: T.nilable(String),
131
101
  client_id: T.nilable(String),
132
- ).returns(WorkOS::Profile)
102
+ ).returns(WorkOS::ProfileAndToken)
133
103
  end
134
- def profile(code:, project_id: nil, client_id: nil)
135
- if project_id
136
- warn '[DEPRECATION] `project_id` is deprecated.
137
- Please use `client_id` instead.'
138
- client_id = project_id
139
- end
140
-
104
+ def profile_and_token(code:, client_id: nil)
141
105
  body = {
142
106
  client_id: client_id,
143
107
  client_secret: WorkOS.key!,
@@ -146,65 +110,9 @@ module WorkOS
146
110
  }
147
111
 
148
112
  response = client.request(post_request(path: '/sso/token', body: body))
149
- check_and_raise_profile_error(response: response)
150
-
151
- WorkOS::Profile.new(response.body)
152
- end
153
-
154
- # Promote a DraftConnection created via the WorkOS.js embed such that the
155
- # Enterprise users can begin signing into your application.
156
- #
157
- # @param [String] token The Draft Connection token that's been provided to
158
- # you by the WorkOS.js
159
- #
160
- # @example
161
- # WorkOS::SSO.promote_draft_connection(
162
- # token: 'draft_conn_429u59js',
163
- # )
164
- # => true
165
- #
166
- # @return [Bool] - returns `true` if successful, `false` otherwise.
167
- # @see https://github.com/workos-inc/ruby-idp-link-example
168
- sig { params(token: String).returns(T::Boolean) }
169
- def promote_draft_connection(token:)
170
- request = post_request(
171
- auth: true,
172
- path: "/draft_connections/#{token}/activate",
173
- )
174
-
175
- response = client.request(request)
176
-
177
- response.is_a? Net::HTTPSuccess
178
- end
113
+ check_and_raise_profile_and_token_error(response: response)
179
114
 
180
- # Create a Connection
181
- #
182
- # @param [String] source The Draft Connection token that's been provided
183
- # to you by WorkOS.js
184
- #
185
- # @example
186
- # WorkOS::SSO.create_connection(source: 'draft_conn_429u59js')
187
- # => #<WorkOS::Connection:0x00007fb6e4193d20
188
- # @id="conn_02DRA1XNSJDZ19A31F183ECQW9",
189
- # @name="Foo Corp",
190
- # @connection_type="OktaSAML",
191
- # @domains=
192
- # [{:object=>"connection_domain",
193
- # :id=>"domain_01E6PK9N3XMD8RHWF7S66380AR",
194
- # :domain=>"example.com"}]>
195
- #
196
- # @return [WorkOS::Connection]
197
- sig { params(source: String).returns(WorkOS::Connection) }
198
- def create_connection(source:)
199
- request = post_request(
200
- auth: true,
201
- path: '/connections',
202
- body: { source: source },
203
- )
204
-
205
- response = execute_request(request: request)
206
-
207
- WorkOS::Connection.new(response.body)
115
+ WorkOS::ProfileAndToken.new(response.body)
208
116
  end
209
117
 
210
118
  # Retrieve connections.
@@ -323,10 +231,10 @@ module WorkOS
323
231
  end
324
232
 
325
233
  sig { params(response: Net::HTTPResponse).void }
326
- def check_and_raise_profile_error(response:)
234
+ def check_and_raise_profile_and_token_error(response:)
327
235
  begin
328
236
  body = JSON.parse(response.body)
329
- return if body['profile']
237
+ return if body['access_token'] && body['profile']
330
238
 
331
239
  message = body['message']
332
240
  request_id = response['x-request-id']
@@ -2,5 +2,5 @@
2
2
  # typed: strong
3
3
 
4
4
  module WorkOS
5
- VERSION = '0.11.2'
5
+ VERSION = '1.0.0'
6
6
  end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ describe WorkOS::Organizations do
5
+ describe '.create_organization' do
6
+ context 'with valid payload' do
7
+ it 'creates an organization' do
8
+ VCR.use_cassette 'organization/create' do
9
+ organization = described_class.create_organization(
10
+ domains: ['example.com'],
11
+ name: 'Test Organization',
12
+ )
13
+
14
+ expect(organization.id).to eq('org_01EHT88Z8J8795GZNQ4ZP1J81T')
15
+ expect(organization.name).to eq('Test Organization')
16
+ expect(organization.domains.first[:domain]).to eq('example.com')
17
+ end
18
+ end
19
+ end
20
+
21
+ context 'with an invalid payload' do
22
+ it 'returns an error' do
23
+ VCR.use_cassette 'organization/create_invalid' do
24
+ expect do
25
+ described_class.create_organization(
26
+ domains: ['example.com'],
27
+ name: 'Test Organization 2',
28
+ )
29
+ end.to raise_error(
30
+ WorkOS::APIError,
31
+ /An Organization with the domain example.com already exists/,
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ describe '.list_organizations' do
39
+ context 'with no options' do
40
+ it 'returns organizations and metadata' do
41
+ expected_metadata = {
42
+ 'after' => nil,
43
+ 'before' => 'before-id',
44
+ }
45
+
46
+ VCR.use_cassette 'organization/list' do
47
+ organizations = described_class.list_organizations
48
+
49
+ expect(organizations.data.size).to eq(7)
50
+ expect(organizations.list_metadata).to eq(expected_metadata)
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'with the before option' do
56
+ it 'forms the proper request to the API' do
57
+ request_args = [
58
+ '/organizations?before=before-id',
59
+ 'Content-Type' => 'application/json'
60
+ ]
61
+
62
+ expected_request = Net::HTTP::Get.new(*request_args)
63
+
64
+ expect(Net::HTTP::Get).to receive(:new).with(*request_args).
65
+ and_return(expected_request)
66
+
67
+ VCR.use_cassette 'organization/list', match_requests_on: [:path] do
68
+ organizations = described_class.list_organizations(
69
+ before: 'before-id',
70
+ )
71
+
72
+ expect(organizations.data.size).to eq(7)
73
+ end
74
+ end
75
+ end
76
+
77
+ context 'with the after option' do
78
+ it 'forms the proper request to the API' do
79
+ request_args = [
80
+ '/organizations?after=after-id',
81
+ 'Content-Type' => 'application/json'
82
+ ]
83
+
84
+ expected_request = Net::HTTP::Get.new(*request_args)
85
+
86
+ expect(Net::HTTP::Get).to receive(:new).with(*request_args).
87
+ and_return(expected_request)
88
+
89
+ VCR.use_cassette 'organization/list', match_requests_on: [:path] do
90
+ organizations = described_class.list_organizations(after: 'after-id')
91
+
92
+ expect(organizations.data.size).to eq(7)
93
+ end
94
+ end
95
+ end
96
+
97
+ context 'with the limit option' do
98
+ it 'forms the proper request to the API' do
99
+ request_args = [
100
+ '/organizations?limit=10',
101
+ 'Content-Type' => 'application/json'
102
+ ]
103
+
104
+ expected_request = Net::HTTP::Get.new(*request_args)
105
+
106
+ expect(Net::HTTP::Get).to receive(:new).with(*request_args).
107
+ and_return(expected_request)
108
+
109
+ VCR.use_cassette 'organization/list', match_requests_on: [:path] do
110
+ organizations = described_class.list_organizations(limit: 10)
111
+
112
+ expect(organizations.data.size).to eq(7)
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ describe '.get_organization' do
119
+ context 'with a valid id' do
120
+ it 'gets the organization details' do
121
+ VCR.use_cassette('organization/get') do
122
+ organization = described_class.get_organization(
123
+ id: 'org_01EZDF20TZEJXKPSX2BJRN6TV6',
124
+ )
125
+
126
+ expect(organization.id).to eq('org_01EZDF20TZEJXKPSX2BJRN6TV6')
127
+ expect(organization.name).to eq('Foo Corp')
128
+ expect(organization.domains.first[:domain]).to eq('foo-corp.com')
129
+ end
130
+ end
131
+ end
132
+
133
+ context 'with an invalid id' do
134
+ it 'raises an error' do
135
+ VCR.use_cassette('organization/get_invalid') do
136
+ expect do
137
+ described_class.get_organization(id: 'invalid')
138
+ end.to raise_error(
139
+ WorkOS::APIError,
140
+ 'Status 404, Not Found - request ID: ',
141
+ )
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ describe '.update_organization' do
148
+ context 'with valid payload' do
149
+ it 'creates an organization' do
150
+ VCR.use_cassette 'organization/update' do
151
+ organization = described_class.update_organization(
152
+ organization: 'org_01F29YJ068E52HGEB8ZQGC9MJG',
153
+ domains: ['example.me'],
154
+ name: 'Test Organization',
155
+ )
156
+
157
+ expect(organization.id).to eq('org_01F29YJ068E52HGEB8ZQGC9MJG')
158
+ expect(organization.name).to eq('Test Organization')
159
+ expect(organization.domains.first[:domain]).to eq('example.me')
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -2,39 +2,6 @@
2
2
  # typed: false
3
3
 
4
4
  describe WorkOS::Portal do
5
- describe '.create_organization' do
6
- context 'with valid payload' do
7
- it 'creates an organization' do
8
- VCR.use_cassette 'organization/create' do
9
- organization = described_class.create_organization(
10
- domains: ['example.com'],
11
- name: 'Test Organization',
12
- )
13
-
14
- expect(organization.id).to eq('org_01EHT88Z8J8795GZNQ4ZP1J81T')
15
- expect(organization.name).to eq('Test Organization')
16
- expect(organization.domains.first[:domain]).to eq('example.com')
17
- end
18
- end
19
- end
20
-
21
- context 'with an invalid payload' do
22
- it 'returns an error' do
23
- VCR.use_cassette 'organization/create_invalid' do
24
- expect do
25
- described_class.create_organization(
26
- domains: ['example.com'],
27
- name: 'Test Organization 2',
28
- )
29
- end.to raise_error(
30
- WorkOS::APIError,
31
- /An Organization with the domain example.com already exists/,
32
- )
33
- end
34
- end
35
- end
36
- end
37
-
38
5
  describe '.generate_link' do
39
6
  let(:organization) { 'org_01EHQMYV6MBK39QC5PZXHY59C3' }
40
7
 
@@ -100,131 +67,4 @@ describe WorkOS::Portal do
100
67
  end
101
68
  end
102
69
  end
103
-
104
- describe '.list_organizations' do
105
- context 'with no options' do
106
- it 'returns organizations and metadata' do
107
- expected_metadata = {
108
- 'after' => nil,
109
- 'before' => 'before-id',
110
- }
111
-
112
- VCR.use_cassette 'organization/list' do
113
- organizations = described_class.list_organizations
114
-
115
- expect(organizations.data.size).to eq(7)
116
- expect(organizations.list_metadata).to eq(expected_metadata)
117
- end
118
- end
119
- end
120
-
121
- context 'with the before option' do
122
- it 'forms the proper request to the API' do
123
- request_args = [
124
- '/organizations?before=before-id',
125
- 'Content-Type' => 'application/json'
126
- ]
127
-
128
- expected_request = Net::HTTP::Get.new(*request_args)
129
-
130
- expect(Net::HTTP::Get).to receive(:new).with(*request_args).
131
- and_return(expected_request)
132
-
133
- VCR.use_cassette 'organization/list', match_requests_on: [:path] do
134
- organizations = described_class.list_organizations(
135
- before: 'before-id',
136
- )
137
-
138
- expect(organizations.data.size).to eq(7)
139
- end
140
- end
141
- end
142
-
143
- context 'with the after option' do
144
- it 'forms the proper request to the API' do
145
- request_args = [
146
- '/organizations?after=after-id',
147
- 'Content-Type' => 'application/json'
148
- ]
149
-
150
- expected_request = Net::HTTP::Get.new(*request_args)
151
-
152
- expect(Net::HTTP::Get).to receive(:new).with(*request_args).
153
- and_return(expected_request)
154
-
155
- VCR.use_cassette 'organization/list', match_requests_on: [:path] do
156
- organizations = described_class.list_organizations(after: 'after-id')
157
-
158
- expect(organizations.data.size).to eq(7)
159
- end
160
- end
161
- end
162
-
163
- context 'with the limit option' do
164
- it 'forms the proper request to the API' do
165
- request_args = [
166
- '/organizations?limit=10',
167
- 'Content-Type' => 'application/json'
168
- ]
169
-
170
- expected_request = Net::HTTP::Get.new(*request_args)
171
-
172
- expect(Net::HTTP::Get).to receive(:new).with(*request_args).
173
- and_return(expected_request)
174
-
175
- VCR.use_cassette 'organization/list', match_requests_on: [:path] do
176
- organizations = described_class.list_organizations(limit: 10)
177
-
178
- expect(organizations.data.size).to eq(7)
179
- end
180
- end
181
- end
182
- end
183
-
184
- describe '.get_organization' do
185
- context 'with a valid id' do
186
- it 'gets the organization details' do
187
- VCR.use_cassette('organization/get') do
188
- organization = described_class.get_organization(
189
- id: 'org_01EZDF20TZEJXKPSX2BJRN6TV6',
190
- )
191
-
192
- expect(organization.id).to eq('org_01EZDF20TZEJXKPSX2BJRN6TV6')
193
- expect(organization.name).to eq('Foo Corp')
194
- expect(organization.domains.first[:domain]).to eq('foo-corp.com')
195
- end
196
- end
197
- end
198
-
199
- context 'with an invalid id' do
200
- it 'raises an error' do
201
- VCR.use_cassette('organization/get_invalid') do
202
- expect do
203
- described_class.get_organization(id: 'invalid')
204
- end.to raise_error(
205
- WorkOS::APIError,
206
- 'Status 404, Not Found - request ID: ',
207
- )
208
- end
209
- end
210
- end
211
- end
212
-
213
- describe '.update_organization' do
214
- context 'with valid payload' do
215
- it 'creates an organization' do
216
- VCR.use_cassette 'organization/update' do
217
- organization = described_class.update_organization(
218
- organization: 'org_01F29YJ068E52HGEB8ZQGC9MJG',
219
- domains: ['example.me'],
220
- name: 'Test Organization',
221
- )
222
-
223
- expect(organization.id).to eq('org_01F29YJ068E52HGEB8ZQGC9MJG')
224
- expect(organization.name).to eq('Test Organization')
225
- expect(organization.domains.first[:domain]).to eq('example.me')
226
- end
227
- end
228
- end
229
- end
230
70
  end
@@ -147,52 +147,9 @@ describe WorkOS::SSO do
147
147
  )
148
148
  end
149
149
  end
150
-
151
- context 'passing the project_id' do
152
- let(:args) do
153
- {
154
- domain: 'foo.com',
155
- project_id: 'workos-proj-123',
156
- redirect_uri: 'foo.com/auth/callback',
157
- state: {
158
- next_page: '/dashboard/edit',
159
- }.to_s,
160
- }
161
- end
162
- it 'raises a deprecation warning' do
163
- expect do
164
- described_class.authorization_url(**args)
165
- end.to output(
166
- "[DEPRECATION] `project_id` is deprecated.
167
- Please use `client_id` instead.\n",
168
- ).to_stderr
169
- end
170
-
171
- it 'returns a valid URL' do
172
- authorization_url = described_class.authorization_url(**args)
173
-
174
- expect(URI.parse(authorization_url)).to be_a URI
175
- end
176
-
177
- it 'returns the expected hostname' do
178
- authorization_url = described_class.authorization_url(**args)
179
-
180
- expect(URI.parse(authorization_url).host).to eq(WorkOS::API_HOSTNAME)
181
- end
182
-
183
- it 'returns the expected query string' do
184
- authorization_url = described_class.authorization_url(**args)
185
-
186
- expect(URI.parse(authorization_url).query).to eq(
187
- 'client_id=workos-proj-123&redirect_uri=foo.com%2Fauth%2Fcallback' \
188
- '&response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdashboard%2F' \
189
- 'edit%22%7D&domain=foo.com',
190
- )
191
- end
192
- end
193
150
  end
194
151
 
195
- describe '.profile' do
152
+ describe '.profile_and_token' do
196
153
  let(:args) do
197
154
  {
198
155
  code: SecureRandom.hex(10),
@@ -225,15 +182,15 @@ describe WorkOS::SSO do
225
182
  end
226
183
 
227
184
  it 'includes the SDK Version header' do
228
- described_class.profile(**args)
185
+ described_class.profile_and_token(**args)
229
186
 
230
187
  expect(a_request(:post, 'https://api.workos.com/sso/token').
231
188
  with(headers: headers, body: request_body)).to have_been_made
232
189
  end
233
190
 
234
- it 'returns a WorkOS::Profile' do
235
- profile = described_class.profile(**args)
236
- expect(profile).to be_a(WorkOS::Profile)
191
+ it 'returns a WorkOS::ProfileAndToken' do
192
+ profile_and_token = described_class.profile_and_token(**args)
193
+ expect(profile_and_token).to be_a(WorkOS::ProfileAndToken)
237
194
 
238
195
  expectation = {
239
196
  connection_id: 'conn_01EMH8WAK20T42N2NBMNBCYHAG',
@@ -252,7 +209,8 @@ describe WorkOS::SSO do
252
209
  },
253
210
  }
254
211
 
255
- expect(profile.to_json).to eq(expectation)
212
+ expect(profile_and_token.access_token).to eq('01DVX6QBS3EG6FHY2ESAA5Q65X')
213
+ expect(profile_and_token.profile.to_json).to eq(expectation)
256
214
  end
257
215
  end
258
216
 
@@ -269,7 +227,7 @@ describe WorkOS::SSO do
269
227
 
270
228
  it 'raises an exception with request ID' do
271
229
  expect do
272
- described_class.profile(**args)
230
+ described_class.profile_and_token(**args)
273
231
  end.to raise_error(
274
232
  WorkOS::APIError,
275
233
  'some error message - request ID: request-id',
@@ -293,7 +251,7 @@ describe WorkOS::SSO do
293
251
 
294
252
  it 'raises an exception' do
295
253
  expect do
296
- described_class.profile(**args)
254
+ described_class.profile_and_token(**args)
297
255
  end.to raise_error(
298
256
  WorkOS::APIError,
299
257
  "The code '01DVX3C5Z367SFHR8QNDMK7V24'" \
@@ -303,76 +261,6 @@ describe WorkOS::SSO do
303
261
  end
304
262
  end
305
263
 
306
- describe '.create_connection' do
307
- context 'with a valid source' do
308
- it 'creates a connection' do
309
- VCR.use_cassette('sso/create_connection_with_valid_source') do
310
- connection = WorkOS::SSO.create_connection(
311
- source: 'draft_conn_01E6PK87QP6NQ29RRX0G100YGV',
312
- )
313
-
314
- expect(connection.id).to eq('conn_01E4F9T2YWZFD218DN04KVFDSY')
315
- expect(connection.connection_type).to eq('GoogleOAuth')
316
- expect(connection.name).to eq('Foo Corp')
317
- expect(connection.domains.first[:domain]).to eq('example.com')
318
- expect(connection.organization_id).to eq('12345')
319
- expect(connection.state).to eq('active')
320
- expect(connection.status).to eq('linked')
321
- end
322
- end
323
- end
324
-
325
- context 'with an invalid source' do
326
- it 'raises an error' do
327
- VCR.use_cassette('sso/create_connection_with_invalid_source') do
328
- expect do
329
- WorkOS::SSO.create_connection(source: 'invalid')
330
- end.to raise_error(
331
- WorkOS::APIError,
332
- 'Status 404, Not Found - request ID: ',
333
- )
334
- end
335
- end
336
- end
337
- end
338
-
339
- describe '.promote_draft_connection' do
340
- let(:token) { 'draft_conn_id' }
341
- let(:client_id) { 'proj_0239u590h' }
342
-
343
- context 'with a valid request' do
344
- before do
345
- stub_request(
346
- :post,
347
- "https://api.workos.com/draft_connections/#{token}/activate",
348
- ).to_return(status: 200)
349
- end
350
- it 'returns true' do
351
- response = described_class.promote_draft_connection(
352
- token: token,
353
- )
354
-
355
- expect(response).to be(true)
356
- end
357
- end
358
-
359
- context 'with an invalid request' do
360
- before do
361
- stub_request(
362
- :post,
363
- "https://api.workos.com/draft_connections/#{token}/activate",
364
- ).to_return(status: 403)
365
- end
366
- it 'returns true' do
367
- response = described_class.promote_draft_connection(
368
- token: token,
369
- )
370
-
371
- expect(response).to be(false)
372
- end
373
- end
374
- end
375
-
376
264
  describe '.list_connections' do
377
265
  context 'with no options' do
378
266
  it 'returns connections and metadata' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: workos
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - WorkOS
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-10 00:00:00.000000000 Z
11
+ date: 2021-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sorbet-runtime
@@ -217,9 +217,11 @@ files:
217
217
  - lib/workos/directory_user.rb
218
218
  - lib/workos/errors.rb
219
219
  - lib/workos/organization.rb
220
+ - lib/workos/organizations.rb
220
221
  - lib/workos/passwordless.rb
221
222
  - lib/workos/portal.rb
222
223
  - lib/workos/profile.rb
224
+ - lib/workos/profile_and_token.rb
223
225
  - lib/workos/sso.rb
224
226
  - lib/workos/types.rb
225
227
  - lib/workos/types/connection_struct.rb
@@ -270,6 +272,7 @@ files:
270
272
  - spec/lib/workos/audit_trail_spec.rb
271
273
  - spec/lib/workos/base_spec.rb
272
274
  - spec/lib/workos/directory_sync_spec.rb
275
+ - spec/lib/workos/organizations_spec.rb
273
276
  - spec/lib/workos/passwordless_spec.rb
274
277
  - spec/lib/workos/portal_spec.rb
275
278
  - spec/lib/workos/sso_spec.rb
@@ -318,8 +321,6 @@ files:
318
321
  - spec/support/fixtures/vcr_cassettes/portal/generate_link_dsync.yml
319
322
  - spec/support/fixtures/vcr_cassettes/portal/generate_link_invalid.yml
320
323
  - spec/support/fixtures/vcr_cassettes/portal/generate_link_sso.yml
321
- - spec/support/fixtures/vcr_cassettes/sso/create_connection_with_invalid_source.yml
322
- - spec/support/fixtures/vcr_cassettes/sso/create_connection_with_valid_source.yml
323
324
  - spec/support/fixtures/vcr_cassettes/sso/delete_connection_with_invalid_id.yml
324
325
  - spec/support/fixtures/vcr_cassettes/sso/delete_connection_with_valid_id.yml
325
326
  - spec/support/fixtures/vcr_cassettes/sso/get_connection_with_invalid_id.yml
@@ -361,6 +362,7 @@ test_files:
361
362
  - spec/lib/workos/audit_trail_spec.rb
362
363
  - spec/lib/workos/base_spec.rb
363
364
  - spec/lib/workos/directory_sync_spec.rb
365
+ - spec/lib/workos/organizations_spec.rb
364
366
  - spec/lib/workos/passwordless_spec.rb
365
367
  - spec/lib/workos/portal_spec.rb
366
368
  - spec/lib/workos/sso_spec.rb
@@ -409,8 +411,6 @@ test_files:
409
411
  - spec/support/fixtures/vcr_cassettes/portal/generate_link_dsync.yml
410
412
  - spec/support/fixtures/vcr_cassettes/portal/generate_link_invalid.yml
411
413
  - spec/support/fixtures/vcr_cassettes/portal/generate_link_sso.yml
412
- - spec/support/fixtures/vcr_cassettes/sso/create_connection_with_invalid_source.yml
413
- - spec/support/fixtures/vcr_cassettes/sso/create_connection_with_valid_source.yml
414
414
  - spec/support/fixtures/vcr_cassettes/sso/delete_connection_with_invalid_id.yml
415
415
  - spec/support/fixtures/vcr_cassettes/sso/delete_connection_with_valid_id.yml
416
416
  - spec/support/fixtures/vcr_cassettes/sso/get_connection_with_invalid_id.yml
@@ -1,58 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: post
5
- uri: https://api.workos.com/connections
6
- body:
7
- encoding: UTF-8
8
- string: '{"source":"invalid"}'
9
- headers:
10
- Content-Type:
11
- - application/json
12
- Accept-Encoding:
13
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
- Accept:
15
- - "*/*"
16
- User-Agent:
17
- - WorkOS; ruby/2.7.1; x86_64-darwin19; v0.2.2
18
- Authorization:
19
- - Bearer <API_KEY>
20
- response:
21
- status:
22
- code: 404
23
- message: Not Found
24
- headers:
25
- Vary:
26
- - Origin, Accept-Encoding
27
- Access-Control-Allow-Credentials:
28
- - 'true'
29
- X-Dns-Prefetch-Control:
30
- - 'off'
31
- X-Frame-Options:
32
- - SAMEORIGIN
33
- Strict-Transport-Security:
34
- - max-age=15552000; includeSubDomains
35
- X-Download-Options:
36
- - noopen
37
- X-Content-Type-Options:
38
- - nosniff
39
- X-Xss-Protection:
40
- - 1; mode=block
41
- X-Request-Id:
42
- - ''
43
- Content-Type:
44
- - application/json; charset=utf-8
45
- Content-Length:
46
- - '23'
47
- Etag:
48
- - W/"17-SuRA/yvUWUo8rK6x7dKURLeBo+0"
49
- Date:
50
- - Fri, 24 Apr 2020 02:16:27 GMT
51
- Connection:
52
- - keep-alive
53
- body:
54
- encoding: UTF-8
55
- string: '{"message":"Not Found"}'
56
- http_version:
57
- recorded_at: Fri, 24 Apr 2020 02:16:27 GMT
58
- recorded_with: VCR 5.0.0
@@ -1,63 +0,0 @@
1
- ---
2
- http_interactions:
3
- - request:
4
- method: post
5
- uri: https://api.workos.com/connections
6
- body:
7
- encoding: UTF-8
8
- string: '{"source":"draft_conn_01E6PK87QP6NQ29RRX0G100YGV"}'
9
- headers:
10
- Content-Type:
11
- - application/json
12
- Accept-Encoding:
13
- - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
- Accept:
15
- - "*/*"
16
- User-Agent:
17
- - WorkOS; ruby/2.7.1; x86_64-darwin19; v0.2.2
18
- Authorization:
19
- - Bearer <API_KEY>
20
- response:
21
- status:
22
- code: 201
23
- message: Created
24
- headers:
25
- Server:
26
- - Cowboy
27
- Connection:
28
- - keep-alive
29
- Vary:
30
- - Origin, Accept-Encoding
31
- Access-Control-Allow-Credentials:
32
- - 'true'
33
- X-Dns-Prefetch-Control:
34
- - 'off'
35
- X-Frame-Options:
36
- - SAMEORIGIN
37
- Strict-Transport-Security:
38
- - max-age=15552000; includeSubDomains
39
- X-Download-Options:
40
- - noopen
41
- X-Content-Type-Options:
42
- - nosniff
43
- X-Xss-Protection:
44
- - 1; mode=block
45
- X-Request-Id:
46
- - 8cd03fab-ca1a-4c0b-9953-1f918849a9de
47
- Content-Type:
48
- - application/json; charset=utf-8
49
- Etag:
50
- - W/"55a-z00MNCfGmS/7RWJwhsBrAXo09Ls"
51
- Date:
52
- - Fri, 24 Apr 2020 17:20:52 GMT
53
- Transfer-Encoding:
54
- - chunked
55
- Via:
56
- - 1.1 vegur
57
- body:
58
- encoding: ASCII-8BIT
59
- string: '{"object":"connection","id":"conn_01E4F9T2YWZFD218DN04KVFDSY","state":"active","status":"linked","name":"Foo Corp","connection_type":"GoogleOAuth","oauth_uid":"demo
60
- client id","oauth_secret":"demo client secret","oauth_redirect_uri":"https://auth.workos.com/sso/oauth/google/gcrSPYSytyQeZKkwKs6Ye4ogM/callback","saml_entity_id":null,"saml_idp_url":null,"saml_relying_party_trust_cert":null,"saml_x509_certs":null,"organization_id":"12345","domains":[{"object":"connection_domain","id":"domain_01E6PK9N3XMD8RHWF7S66380AR","domain":"example.com"}]}'
61
- http_version:
62
- recorded_at: Fri, 24 Apr 2020 17:20:52 GMT
63
- recorded_with: VCR 5.0.0