workos 0.9.0 → 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.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +5 -0
  3. data/.rubocop.yml +5 -1
  4. data/.ruby-version +1 -1
  5. data/.semaphore/semaphore.yml +8 -2
  6. data/Gemfile.lock +49 -36
  7. data/LICENSE +1 -1
  8. data/README.md +13 -167
  9. data/docs/WorkOS/SSO.html +235 -235
  10. data/docs/file.README.html +20 -20
  11. data/lib/workos/audit_trail.rb +1 -0
  12. data/lib/workos/client.rb +42 -4
  13. data/lib/workos/connection.rb +12 -3
  14. data/lib/workos/directory.rb +53 -0
  15. data/lib/workos/directory_group.rb +44 -0
  16. data/lib/workos/directory_sync.rb +63 -7
  17. data/lib/workos/directory_user.rb +63 -0
  18. data/lib/workos/organization.rb +0 -2
  19. data/lib/workos/organizations.rb +150 -0
  20. data/lib/workos/passwordless.rb +7 -2
  21. data/lib/workos/portal.rb +1 -87
  22. data/lib/workos/profile.rb +3 -6
  23. data/lib/workos/profile_and_token.rb +28 -0
  24. data/lib/workos/sso.rb +106 -65
  25. data/lib/workos/types/connection_struct.rb +3 -0
  26. data/lib/workos/types/directory_group_struct.rb +13 -0
  27. data/lib/workos/types/directory_struct.rb +16 -0
  28. data/lib/workos/types/directory_user_struct.rb +19 -0
  29. data/lib/workos/types/intent_enum.rb +1 -0
  30. data/lib/workos/types.rb +3 -0
  31. data/lib/workos/version.rb +1 -1
  32. data/lib/workos.rb +6 -0
  33. data/sorbet/rbi/gems/addressable.rbi +199 -0
  34. data/sorbet/rbi/gems/ast.rbi +49 -0
  35. data/sorbet/rbi/gems/codecov.rbi +37 -0
  36. data/sorbet/rbi/gems/crack.rbi +62 -0
  37. data/sorbet/rbi/gems/docile.rbi +36 -0
  38. data/sorbet/rbi/gems/hashdiff.rbi +66 -0
  39. data/sorbet/rbi/gems/parallel.rbi +83 -0
  40. data/sorbet/rbi/gems/parser.rbi +1429 -0
  41. data/sorbet/rbi/gems/public_suffix.rbi +104 -0
  42. data/sorbet/rbi/gems/rainbow.rbi +118 -0
  43. data/sorbet/rbi/gems/rake.rbi +644 -0
  44. data/sorbet/rbi/gems/regexp_parser.rbi +926 -0
  45. data/sorbet/rbi/gems/rexml.rbi +628 -0
  46. data/sorbet/rbi/gems/rspec-core.rbi +1898 -0
  47. data/sorbet/rbi/gems/rspec-expectations.rbi +1127 -0
  48. data/sorbet/rbi/gems/rspec-mocks.rbi +1099 -0
  49. data/sorbet/rbi/gems/rspec-support.rbi +280 -0
  50. data/sorbet/rbi/gems/rspec.rbi +15 -0
  51. data/sorbet/rbi/gems/rubocop-ast.rbi +1355 -0
  52. data/sorbet/rbi/gems/rubocop.rbi +7253 -0
  53. data/sorbet/rbi/gems/ruby-progressbar.rbi +304 -0
  54. data/sorbet/rbi/gems/simplecov-html.rbi +35 -0
  55. data/sorbet/rbi/gems/simplecov.rbi +406 -0
  56. data/sorbet/rbi/gems/unicode-display_width.rbi +17 -0
  57. data/sorbet/rbi/gems/vcr.rbi +572 -0
  58. data/sorbet/rbi/gems/webmock.rbi +556 -0
  59. data/sorbet/rbi/gems/yard.rbi +1165 -0
  60. data/sorbet/rbi/sorbet-typed/lib/rake/all/rake.rbi +645 -0
  61. data/sorbet/rbi/sorbet-typed/lib/rspec-core/all/rspec-core.rbi +1891 -0
  62. data/sorbet/rbi/sorbet-typed/lib/rubocop/~>0.85/rubocop.rbi +2072 -0
  63. data/sorbet/rbi/sorbet-typed/lib/yard/all/yard.rbi +1214 -0
  64. data/sorbet/rbi/todo.rbi +1 -3
  65. data/spec/lib/workos/audit_trail_spec.rb +0 -8
  66. data/spec/lib/workos/directory_sync_spec.rb +347 -40
  67. data/spec/lib/workos/organizations_spec.rb +164 -0
  68. data/spec/lib/workos/passwordless_spec.rb +1 -8
  69. data/spec/lib/workos/portal_spec.rb +17 -123
  70. data/spec/lib/workos/sso_spec.rb +230 -71
  71. data/spec/spec_helper.rb +2 -1
  72. data/spec/support/fixtures/vcr_cassettes/audit_trail/get_events.yml +2 -2
  73. data/spec/support/fixtures/vcr_cassettes/directory_sync/delete_directory.yml +72 -0
  74. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_after.yml +72 -0
  75. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_before.yml +72 -0
  76. data/spec/support/fixtures/vcr_cassettes/directory_sync/{list_directories_with_domain_param.yml → list_directories/with_domain.yml} +19 -9
  77. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_limit.yml +74 -0
  78. data/spec/support/fixtures/vcr_cassettes/directory_sync/{list_directories.yml → list_directories/with_no_options.yml} +1 -1
  79. data/spec/support/fixtures/vcr_cassettes/directory_sync/{list_users_with_directory_param.yml → list_directories/with_search.yml} +22 -11
  80. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_after.yml +76 -0
  81. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_before.yml +74 -0
  82. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_directory.yml +78 -0
  83. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_limit.yml +74 -0
  84. data/spec/support/fixtures/vcr_cassettes/directory_sync/{list_groups.yml → list_groups/with_no_options.yml} +16 -6
  85. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_user.yml +72 -0
  86. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_after.yml +86 -0
  87. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_before.yml +75 -0
  88. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_directory.yml +93 -0
  89. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_group.yml +76 -0
  90. data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_limit.yml +75 -0
  91. data/spec/support/fixtures/vcr_cassettes/directory_sync/{list_users.yml → list_users/with_no_options.yml} +16 -6
  92. data/spec/support/fixtures/vcr_cassettes/organization/get.yml +73 -0
  93. data/spec/support/fixtures/vcr_cassettes/{directory_sync/list_groups_with_directory_param.yml → organization/get_invalid.yml} +21 -11
  94. data/spec/support/fixtures/vcr_cassettes/organization/update.yml +73 -0
  95. data/spec/support/fixtures/vcr_cassettes/organization/update_invalid.yml +73 -0
  96. data/spec/support/fixtures/vcr_cassettes/portal/generate_link_dsync.yml +72 -0
  97. data/spec/support/fixtures/vcr_cassettes/portal/{generate_link.yml → generate_link_sso.yml} +1 -1
  98. data/spec/support/fixtures/vcr_cassettes/sso/delete_connection_with_invalid_id.yml +72 -0
  99. data/spec/support/fixtures/vcr_cassettes/sso/delete_connection_with_valid_id.yml +70 -0
  100. data/spec/support/fixtures/vcr_cassettes/sso/{create_connection_with_invalid_source.yml → get_connection_with_invalid_id.yml} +26 -12
  101. data/spec/support/fixtures/vcr_cassettes/sso/get_connection_with_valid_id.yml +74 -0
  102. data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_after.yml +73 -0
  103. data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_before.yml +73 -0
  104. data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_connection_type.yml +73 -0
  105. data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_domain.yml +72 -0
  106. data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_limit.yml +74 -0
  107. data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_no_options.yml +73 -0
  108. data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_organization_id.yml +72 -0
  109. data/workos.gemspec +2 -0
  110. metadata +122 -33
  111. data/CODEOWNERS +0 -1
  112. data/sorbet/rbi/hidden-definitions/errors.txt +0 -24896
  113. data/sorbet/rbi/hidden-definitions/hidden.rbi +0 -38411
  114. data/sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi +0 -8684
  115. data/sorbet/rbi/sorbet-typed/lib/ruby/all/gem.rbi +0 -4222
  116. data/sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi +0 -111
  117. data/sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi +0 -543
  118. data/spec/support/fixtures/vcr_cassettes/sso/create_connection_with_valid_source.yml +0 -63
@@ -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
@@ -23,8 +23,15 @@ module WorkOS
23
23
  # received from WorkOS will contain. The state parameter can be used to
24
24
  # encode arbitrary information to help restore application state between
25
25
  # redirects.
26
+ # @option options [String] connection Optional parameter for the ID of a
27
+ # specific connection. This can be used to create a Passwordless Session
28
+ # for a specific connection rather than using the domain from the email
29
+ # to determine the Organization and Connection.
26
30
  # @option options [String] type The type of Passwordless Session to
27
31
  # create. Currently, the only supported value is 'MagicLink'.
32
+ # @option options [String] redirect_uri The URI where users are directed
33
+ # after completing the authentication step. Must match a
34
+ # configured redirect URI on your WorkOS dashboard.
28
35
  #
29
36
  # @return Hash
30
37
  sig do
@@ -33,7 +40,6 @@ module WorkOS
33
40
  ).returns(WorkOS::Types::PasswordlessSessionStruct)
34
41
  end
35
42
 
36
- # rubocop:disable Metrics/MethodLength
37
43
  def create_session(options)
38
44
  response = execute_request(
39
45
  request: post_request(
@@ -52,7 +58,6 @@ module WorkOS
52
58
  link: hash['link'],
53
59
  )
54
60
  end
55
- # rubocop:enable Metrics/MethodLength
56
61
 
57
62
  # Send a Passwordless Session via email.
58
63
  #
data/lib/workos/portal.rb CHANGED
@@ -15,34 +15,10 @@ 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
45
- # link. Valid values are: ["sso"]
21
+ # link. Valid values are: ["sso", "dsync"]
46
22
  # @param [String] organization The ID of the organization the Admin
47
23
  # Portal link will be generated for.
48
24
  # @param [String] The URL that the end user will be redirected to upon
@@ -55,7 +31,6 @@ module WorkOS
55
31
  return_url: T.nilable(String),
56
32
  ).returns(String)
57
33
  end
58
- # rubocop:disable Metrics/MethodLength
59
34
  def generate_link(intent:, organization:, return_url: nil)
60
35
  validate_intent(intent)
61
36
 
@@ -73,70 +48,9 @@ module WorkOS
73
48
 
74
49
  JSON.parse(response.body)['link']
75
50
  end
76
- # rubocop:enable Metrics/MethodLength
77
-
78
- # Retrieve a list of organizations that have connections configured
79
- # within your WorkOS dashboard.
80
- #
81
- # @param [Array<String>] domains Filter organizations to only return those
82
- # that are associated with the provided domains.
83
- # @param [String] before A pagination argument used to request
84
- # organizations before the provided Organization ID.
85
- # @param [String] after A pagination argument used to request
86
- # organizations after the provided Organization ID.
87
- # @param [Integer] limit A pagination argument used to limit the number
88
- # of listed Organizations that are returned.
89
- sig do
90
- params(
91
- options: T::Hash[Symbol, String],
92
- ).returns(WorkOS::Types::ListStruct)
93
- end
94
- # rubocop:disable Metrics/MethodLength
95
- def list_organizations(options = {})
96
- response = execute_request(
97
- request: get_request(
98
- path: '/organizations',
99
- auth: true,
100
- params: options,
101
- ),
102
- )
103
-
104
- parsed_response = JSON.parse(response.body)
105
-
106
- organizations = parsed_response['data'].map do |organization|
107
- ::WorkOS::Organization.new(organization.to_json)
108
- end
109
-
110
- WorkOS::Types::ListStruct.new(
111
- data: organizations,
112
- list_metadata: parsed_response['listMetadata'],
113
- )
114
- end
115
- # rubocop:enable Metrics/MethodLength
116
51
 
117
52
  private
118
53
 
119
- sig { params(response: Net::HTTPResponse).void }
120
- # rubocop:disable Metrics/MethodLength
121
- def check_and_raise_organization_error(response:)
122
- begin
123
- body = JSON.parse(response.body)
124
- return unless body['message']
125
-
126
- message = body['message']
127
- request_id = response['x-request-id']
128
- rescue StandardError
129
- message = 'Something went wrong'
130
- end
131
-
132
- raise APIError.new(
133
- message: message,
134
- http_status: nil,
135
- request_id: request_id,
136
- )
137
- end
138
- # rubocop:enable Metrics/MethodLength
139
-
140
54
  sig { params(intent: String).void }
141
55
  def validate_intent(intent)
142
56
  return if GENERATE_LINK_INTENTS.include?(intent)
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  # typed: true
3
3
 
4
- require 'json'
5
-
6
4
  module WorkOS
7
5
  # The Profile class provides a lighweight wrapper around
8
6
  # a normalized response from the various IDPs WorkOS
@@ -15,7 +13,7 @@ module WorkOS
15
13
  sig { returns(String) }
16
14
  attr_accessor :id, :email, :first_name, :last_name, :connection_id,
17
15
  :connection_type, :idp_id, :raw_attributes
18
- # rubocop:disable Metrics/AbcSize
16
+
19
17
  sig { params(profile_json: String).void }
20
18
  def initialize(profile_json)
21
19
  raw = parse_json(profile_json)
@@ -29,7 +27,6 @@ module WorkOS
29
27
  @idp_id = raw.idp_id
30
28
  @raw_attributes = raw.raw_attributes
31
29
  end
32
- # rubocop:enable Metrics/AbcSize
33
30
 
34
31
  sig { returns(String) }
35
32
  def full_name
@@ -51,7 +48,7 @@ module WorkOS
51
48
 
52
49
  private
53
50
 
54
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
51
+ # rubocop:disable Metrics/AbcSize
55
52
  sig { params(json_string: String).returns(WorkOS::Types::ProfileStruct) }
56
53
  def parse_json(json_string)
57
54
  hash = JSON.parse(json_string, symbolize_names: true)
@@ -67,6 +64,6 @@ module WorkOS
67
64
  raw_attributes: hash[:profile][:raw_attributes],
68
65
  )
69
66
  end
70
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
67
+ # rubocop:enable Metrics/AbcSize
71
68
  end
72
69
  end
@@ -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
@@ -6,7 +6,7 @@ require 'uri'
6
6
 
7
7
  module WorkOS
8
8
  # The SSO module provides convenience methods for working with the WorkOS
9
- # SSO platform. You'll need a valid API key, a project ID, and to have
9
+ # SSO platform. You'll need a valid API key, a client ID, and to have
10
10
  # created an SSO connection on your WorkOS dashboard.
11
11
  #
12
12
  # @see https://docs.workos.com/sso/overview
@@ -26,7 +26,9 @@ module WorkOS
26
26
  # required
27
27
  # @param [String] provider A provider name for an Identity Provider
28
28
  # configured on your WorkOS dashboard. Only 'Google' is supported.
29
- # @param [String] project_id The WorkOS project ID for the project
29
+ # @param [String] connection The ID for a Connection configured on
30
+ # WorkOS.
31
+ # @param [String] client_id The WorkOS client ID for the environment
30
32
  # where you've configured your SSO connection.
31
33
  # @param [String] redirect_uri The URI where users are directed
32
34
  # after completing the authentication step. Must match a
@@ -36,7 +38,7 @@ module WorkOS
36
38
  # @example
37
39
  # WorkOS::SSO.authorization_url(
38
40
  # domain: 'acme.com',
39
- # project_id: 'project_01DG5TGK363GRVXP3ZS40WNGEZ',
41
+ # client_id: 'project_01DG5TGK363GRVXP3ZS40WNGEZ',
40
42
  # redirect_uri: 'https://workos.com/callback',
41
43
  # state: {
42
44
  # next_page: '/docs'
@@ -51,25 +53,36 @@ module WorkOS
51
53
  # @return [String]
52
54
  sig do
53
55
  params(
54
- project_id: String,
55
56
  redirect_uri: String,
57
+ client_id: T.nilable(String),
56
58
  domain: T.nilable(String),
57
59
  provider: T.nilable(String),
60
+ connection: T.nilable(String),
58
61
  state: T.nilable(String),
59
62
  ).returns(String)
60
63
  end
61
64
  def authorization_url(
62
- project_id:, redirect_uri:, domain: nil, provider: nil, state: ''
65
+ redirect_uri:,
66
+ client_id: nil,
67
+ domain: nil,
68
+ provider: nil,
69
+ connection: nil,
70
+ state: ''
63
71
  )
64
- validate_domain_and_provider(provider: provider, domain: domain)
72
+ validate_authorization_url_arguments(
73
+ provider: provider,
74
+ domain: domain,
75
+ connection: connection,
76
+ )
65
77
 
66
78
  query = URI.encode_www_form({
67
- client_id: project_id,
79
+ client_id: client_id,
68
80
  redirect_uri: redirect_uri,
69
81
  response_type: 'code',
70
82
  state: state,
71
83
  domain: domain,
72
84
  provider: provider,
85
+ connection: connection,
73
86
  }.compact)
74
87
 
75
88
  "https://#{WorkOS::API_HOSTNAME}/sso/authorize?#{query}"
@@ -78,73 +91,77 @@ module WorkOS
78
91
  # Fetch the profile details for the authenticated SSO user.
79
92
  #
80
93
  # @param [String] code The authorization code provided in the callback URL
81
- # @param [String] project_id The WorkOS project ID for the project
82
- # where you've configured your SSO connection
94
+ # @param [String] client_id The WorkOS client ID for the environment
95
+ # where you've configured your SSO connection
83
96
  #
84
- # @example
85
- # WorkOS::SSO.profile(
86
- # code: 'acme.com',
87
- # project_id: 'project_01DG5TGK363GRVXP3ZS40WNGEZ'
88
- # )
89
- # => #<WorkOS::Profile:0x00007fb6e4193d20
90
- # @id="prof_01DRA1XNSJDZ19A31F183ECQW5",
91
- # @email="demo@workos-okta.com",
92
- # @first_name="WorkOS",
93
- # @connection_type="OktaSAML",
94
- # @last_name="Demo",
95
- # @idp_id="00u1klkowm8EGah2H357",
96
- # @access_token="01DVX6QBS3EG6FHY2ESAA5Q65X"
97
- # >
98
- #
99
- # @return [WorkOS::Profile]
100
- sig { params(code: String, project_id: String).returns(WorkOS::Profile) }
101
- def profile(code:, project_id:)
97
+ # @return [WorkOS::ProfileAndToken]
98
+ sig do
99
+ params(
100
+ code: String,
101
+ client_id: T.nilable(String),
102
+ ).returns(WorkOS::ProfileAndToken)
103
+ end
104
+ def profile_and_token(code:, client_id: nil)
102
105
  body = {
103
- client_id: project_id,
106
+ client_id: client_id,
104
107
  client_secret: WorkOS.key!,
105
108
  grant_type: 'authorization_code',
106
109
  code: code,
107
110
  }
108
111
 
109
112
  response = client.request(post_request(path: '/sso/token', body: body))
110
- check_and_raise_profile_error(response: response)
113
+ check_and_raise_profile_and_token_error(response: response)
111
114
 
112
- WorkOS::Profile.new(response.body)
115
+ WorkOS::ProfileAndToken.new(response.body)
113
116
  end
114
117
 
115
- # Promote a DraftConnection created via the WorkOS.js embed such that the
116
- # Enterprise users can begin signing into your application.
117
- #
118
- # @param [String] token The Draft Connection token that's been provided to
119
- # you by the WorkOS.js
118
+ # Retrieve connections.
120
119
  #
121
- # @example
122
- # WorkOS::SSO.promote_draft_connection(
123
- # token: 'draft_conn_429u59js',
124
- # )
125
- # => true
120
+ # @param [Hash] options An options hash
121
+ # @option options [String] connection_type Authentication service
122
+ # provider descriptor.
123
+ # @option options [String] domain The domain of the connection to be
124
+ # retrieved.
125
+ # @option options [String] organization_id The id of the organization
126
+ # of the connections to be retrieved.
127
+ # @option options [String] limit Maximum number of records to return.
128
+ # @option options [String] before Pagination cursor to receive records
129
+ # before a provided Connection ID.
130
+ # @option options [String] after Pagination cursor to receive records
131
+ # before a provided Connection ID.
126
132
  #
127
- # @return [Bool] - returns `true` if successful, `false` otherwise.
128
- # @see https://github.com/workos-inc/ruby-idp-link-example
129
- sig { params(token: String).returns(T::Boolean) }
130
- def promote_draft_connection(token:)
131
- request = post_request(
132
- auth: true,
133
- path: "/draft_connections/#{token}/activate",
133
+ # @return [Hash]
134
+ sig do
135
+ params(
136
+ options: T::Hash[Symbol, String],
137
+ ).returns(WorkOS::Types::ListStruct)
138
+ end
139
+ def list_connections(options = {})
140
+ response = execute_request(
141
+ request: get_request(
142
+ path: '/connections',
143
+ auth: true,
144
+ params: options,
145
+ ),
134
146
  )
135
147
 
136
- response = client.request(request)
148
+ parsed_response = JSON.parse(response.body)
149
+ connections = parsed_response['data'].map do |connection|
150
+ ::WorkOS::Connection.new(connection.to_json)
151
+ end
137
152
 
138
- response.is_a? Net::HTTPSuccess
153
+ WorkOS::Types::ListStruct.new(
154
+ data: connections,
155
+ list_metadata: parsed_response['listMetadata'],
156
+ )
139
157
  end
140
158
 
141
- # Create a Connection
159
+ # Get a Connection
142
160
  #
143
- # @param [String] source The Draft Connection token that's been provided
144
- # to you by WorkOS.js
161
+ # @param [String] id Connection unique identifier
145
162
  #
146
163
  # @example
147
- # WorkOS::SSO.create_connection(source: 'draft_conn_429u59js')
164
+ # WorkOS::SSO.get_connection(id: 'conn_02DRA1XNSJDZ19A31F183ECQW9')
148
165
  # => #<WorkOS::Connection:0x00007fb6e4193d20
149
166
  # @id="conn_02DRA1XNSJDZ19A31F183ECQW9",
150
167
  # @name="Foo Corp",
@@ -155,12 +172,11 @@ module WorkOS
155
172
  # :domain=>"example.com"}]>
156
173
  #
157
174
  # @return [WorkOS::Connection]
158
- sig { params(source: String).returns(WorkOS::Connection) }
159
- def create_connection(source:)
160
- request = post_request(
175
+ sig { params(id: String).returns(WorkOS::Connection) }
176
+ def get_connection(id:)
177
+ request = get_request(
161
178
  auth: true,
162
- path: '/connections',
163
- body: { source: source },
179
+ path: "/connections/#{id}",
164
180
  )
165
181
 
166
182
  response = execute_request(request: request)
@@ -168,17 +184,44 @@ module WorkOS
168
184
  WorkOS::Connection.new(response.body)
169
185
  end
170
186
 
187
+ # Delete a Connection
188
+ #
189
+ # @param [String] id Connection unique identifier
190
+ #
191
+ # @example
192
+ # WorkOS::SSO.delete_connection(id: 'conn_02DRA1XNSJDZ19A31F183ECQW9')
193
+ # => true
194
+ #
195
+ # @return [Bool] - returns `true` if successful
196
+ sig { params(id: String).returns(T::Boolean) }
197
+ def delete_connection(id:)
198
+ request = delete_request(
199
+ auth: true,
200
+ path: "/connections/#{id}",
201
+ )
202
+
203
+ response = execute_request(request: request)
204
+
205
+ response.is_a? Net::HTTPSuccess
206
+ end
207
+
171
208
  private
172
209
 
173
210
  sig do
174
211
  params(
175
212
  domain: T.nilable(String),
176
213
  provider: T.nilable(String),
214
+ connection: T.nilable(String),
177
215
  ).void
178
216
  end
179
- def validate_domain_and_provider(domain:, provider:)
180
- if [domain, provider].all?(&:nil?)
181
- raise ArgumentError, 'Either domain or provider is required.'
217
+ def validate_authorization_url_arguments(
218
+ domain:,
219
+ provider:,
220
+ connection:
221
+ )
222
+ if [domain, provider, connection].all?(&:nil?)
223
+ raise ArgumentError, 'Either connection, domain, or ' \
224
+ 'provider is required.'
182
225
  end
183
226
 
184
227
  return unless provider && !PROVIDERS.include?(provider)
@@ -187,12 +230,11 @@ module WorkOS
187
230
  " `provider` must be in #{PROVIDERS}"
188
231
  end
189
232
 
190
- # rubocop:disable Metrics/MethodLength
191
233
  sig { params(response: Net::HTTPResponse).void }
192
- def check_and_raise_profile_error(response:)
234
+ def check_and_raise_profile_and_token_error(response:)
193
235
  begin
194
236
  body = JSON.parse(response.body)
195
- return if body['profile']
237
+ return if body['access_token'] && body['profile']
196
238
 
197
239
  message = body['message']
198
240
  request_id = response['x-request-id']
@@ -206,7 +248,6 @@ module WorkOS
206
248
  request_id: request_id,
207
249
  )
208
250
  end
209
- # rubocop:enable Metrics/MethodLength
210
251
  end
211
252
  end
212
253
  end
@@ -10,6 +10,9 @@ 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
14
+ const :state, String
15
+ const :status, String
13
16
  end
14
17
  end
15
18
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module WorkOS
5
+ module Types
6
+ # This DirectoryGroupStruct acts as a typed interface
7
+ # for the DirectoryGroup class
8
+ class DirectoryGroupStruct < T::Struct
9
+ const :id, String
10
+ const :name, String
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module WorkOS
5
+ module Types
6
+ # This DirectoryStruct acts as a typed interface
7
+ # for the Directory class
8
+ class DirectoryStruct < T::Struct
9
+ const :id, String
10
+ const :name, String
11
+ const :domain, String
12
+ const :type, String
13
+ const :state, String
14
+ end
15
+ end
16
+ end