workos 0.11.2 → 1.0.0

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: 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