workos 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.semaphore/semaphore.yml +13 -39
  3. data/Gemfile.lock +2 -2
  4. data/README.md +4 -0
  5. data/lib/workos/challenge.rb +54 -0
  6. data/lib/workos/client.rb +2 -0
  7. data/lib/workos/directory_sync.rb +1 -0
  8. data/lib/workos/errors.rb +3 -1
  9. data/lib/workos/factor.rb +58 -0
  10. data/lib/workos/mfa.rb +165 -0
  11. data/lib/workos/types/challenge_struct.rb +18 -0
  12. data/lib/workos/types/factor_struct.rb +19 -0
  13. data/lib/workos/types/verify_factor_struct.rb +15 -0
  14. data/lib/workos/types.rb +3 -0
  15. data/lib/workos/verify_factor.rb +39 -0
  16. data/lib/workos/version.rb +1 -1
  17. data/lib/workos/webhooks.rb +1 -1
  18. data/lib/workos.rb +5 -0
  19. data/spec/lib/workos/mfa_spec.rb +232 -0
  20. data/spec/lib/workos/sso_spec.rb +0 -2
  21. data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_generic_valid.yml +82 -0
  22. data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_sms_valid.yml +82 -0
  23. data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_totp_valid.yml +82 -0
  24. data/spec/support/fixtures/vcr_cassettes/mfa/delete_factor.yml +80 -0
  25. data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_generic_valid.yml +82 -0
  26. data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_sms_valid.yml +82 -0
  27. data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_totp_valid.yml +82 -0
  28. data/spec/support/fixtures/vcr_cassettes/mfa/get_factor_invalid.yml +82 -0
  29. data/spec/support/fixtures/vcr_cassettes/mfa/get_factor_valid.yml +82 -0
  30. data/spec/support/fixtures/vcr_cassettes/mfa/verify_factor_generic_expired.yml +84 -0
  31. data/spec/support/fixtures/vcr_cassettes/mfa/verify_factor_generic_invalid.yml +84 -0
  32. data/spec/support/fixtures/vcr_cassettes/mfa/verify_factor_generic_valid.yml +82 -0
  33. metadata +36 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e98cbe7f34c4d550972ac7b4dc734e17ed9b2390b08898d2b20fdf5e69da71ea
4
- data.tar.gz: c998bf772be7cc75e1730debd7efefa764d87676c62b325daf45784846ce3a12
3
+ metadata.gz: 983d578de3e27144af8a7947eebfb770ad7ee640954511586617505c520ee657
4
+ data.tar.gz: 92cb0b75234f56a1e18c47d9cb339b2f389e17463798141bc7a3a2977f5f9372
5
5
  SHA512:
6
- metadata.gz: 01d4bcee2864d6a8b58e8cd3ffef78d77e11028bfbcd9005c4a2cecafaabe0cec97856f94b70aa9391dee50d08502ed8d7afa9456763d16a44f0fcc78a912694
7
- data.tar.gz: ae83d9e5e204771f3d261a2f3135e077cc8b19d700ccf7984447e5536297ba65fba3779c3988daf612ce2c9624c9a825b8dd9b0e633e47c8839f3466a6837440
6
+ metadata.gz: 1143a28ee95755c80fe36aa5fba02e069143ebdb96e67f909d566bbf091928176ac29f23ccfa7764da163a248268f7a882616e0db7bd73612eda060c78cf8515
7
+ data.tar.gz: a2e279f2f2427dd8089eddcc692e677d21978fdd16f3918ffe162822d116b7904f1dbc6826d151f583ba1c60cd5c0e8fbe8b825fb78212f772d7a1aa11faa6da
@@ -31,45 +31,19 @@ blocks:
31
31
  - name: codecov-workos-ruby
32
32
  jobs:
33
33
  - name: Ruby 1.9.3
34
- commands:
35
- - checkout
36
- - sem-version ruby 1.9.3-p551
37
- - bundle install
38
- - bundle exec rspec
39
- - name: Ruby 2.0.0
40
- commands:
41
- - checkout
42
- - sem-version ruby 2.0.0-p648
43
- - bundle install
44
- - bundle exec rspec
45
- - name: Ruby 2.3.4
46
- commands:
47
- - checkout
48
- - sem-version ruby 2.3.4
49
- - bundle install
50
- - bundle exec rspec
51
- - name: Ruby 2.5.7
52
- commands:
53
- - checkout
54
- - sem-version ruby 2.5.7
55
- - bundle install
56
- - bundle exec rspec
57
- - name: Ruby 2.6.5
58
- commands:
59
- - checkout
60
- - sem-version ruby 2.6.5
61
- - bundle install
62
- - bundle exec rspec
63
- - name: Ruby 2.7.3
64
- commands:
65
- - checkout
66
- - sem-version ruby 2.7.3
67
- - bundle install
68
- - bundle exec rspec
69
- - name: Ruby 3.0.2
70
- commands:
71
- - checkout
72
- - sem-version ruby 3.0.2
34
+ matrix:
35
+ - env_var: RUBY_VERSION
36
+ values:
37
+ - 1.9.3-p551
38
+ - 2.0.0-p648
39
+ - 2.3.4
40
+ - 2.5.7
41
+ - 2.6.5
42
+ - 2.7.3
43
+ - 3.0.2
44
+ commands:
45
+ - checkout
46
+ - sem-version ruby $RUBY_VERSION
73
47
  - bundle install
74
48
  - bundle exec rspec
75
49
  promotions:
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- workos (2.1.1)
4
+ workos (2.2.0)
5
5
  sorbet-runtime (~> 0.5)
6
6
 
7
7
  GEM
@@ -60,7 +60,7 @@ GEM
60
60
  simplecov_json_formatter (0.1.2)
61
61
  sorbet (0.5.6388)
62
62
  sorbet-static (= 0.5.6388)
63
- sorbet-runtime (0.5.9528)
63
+ sorbet-runtime (0.5.9300)
64
64
  sorbet-static (0.5.6388-universal-darwin-14)
65
65
  sorbet-static (0.5.6388-universal-darwin-15)
66
66
  sorbet-static (0.5.6388-universal-darwin-16)
data/README.md CHANGED
@@ -38,6 +38,10 @@ Or, you may set the key yourself, such as in an initializer in your application
38
38
  WorkOS.key = '[your api key]'
39
39
  ```
40
40
 
41
+ ## SDK Versioning
42
+
43
+ For our SDKs WorkOS follows a Semantic Versioning ([SemVer](https://semver.org/)) process where all releases will have a version X.Y.Z (like 1.0.0) pattern wherein Z would be a bug fix (e.g., 1.0.1), Y would be a minor release (1.1.0) and X would be a major release (2.0.0). We permit any breaking changes to only be released in major versions and strongly recommend reading changelogs before making any major version upgrades.
44
+
41
45
  ## More Information
42
46
 
43
47
  * [Single Sign-On Guide](https://workos.com/docs/sso/guide)
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ module WorkOS
5
+ # The Challnge class provides a lightweight wrapper around
6
+ # a WorkOS DirectoryUser resource. This class is not meant to be instantiated
7
+ # in DirectoryUser space, and is instantiated internally but exposed.
8
+ class Challenge
9
+ extend T::Sig
10
+
11
+ attr_accessor :id, :object, :expires_at, :code, :authentication_factor_id, :updated_at, :created_at
12
+
13
+ sig { params(json: String).void }
14
+ def initialize(json)
15
+ raw = parse_json(json)
16
+ @id = T.let(raw.id, String)
17
+ @object = T.let(raw.object, String)
18
+ @expires_at = raw.expires_at
19
+ @code = raw.code
20
+ @authentication_factor_id = T.let(raw.authentication_factor_id, String)
21
+ @created_at = T.let(raw.created_at, String)
22
+ @updated_at = T.let(raw.updated_at, String)
23
+ end
24
+
25
+ def to_json(*)
26
+ {
27
+ id: id,
28
+ object: object,
29
+ expires_at: expires_at,
30
+ code: code,
31
+ authentication_factor_id: authentication_factor_id,
32
+ created_at: created_at,
33
+ updated_at: updated_at,
34
+ }
35
+ end
36
+
37
+ private
38
+
39
+ sig { params(json_string: String).returns(WorkOS::Types::ChallengeStruct) }
40
+ def parse_json(json_string)
41
+ hash = JSON.parse(json_string, symbolize_names: true)
42
+
43
+ WorkOS::Types::ChallengeStruct.new(
44
+ id: hash[:id],
45
+ object: hash[:object],
46
+ expires_at: hash[:expires_at],
47
+ code: hash[:code],
48
+ authentication_factor_id: hash[:authentication_factor_id],
49
+ created_at: hash[:created_at],
50
+ updated_at: hash[:updated_at],
51
+ )
52
+ end
53
+ end
54
+ end
data/lib/workos/client.rb CHANGED
@@ -144,6 +144,7 @@ module WorkOS
144
144
  )
145
145
  when 422
146
146
  message = json['message']
147
+ code = json['code']
147
148
  errors = extract_error(json['errors']) if json['errors']
148
149
  message += " (#{errors})" if errors
149
150
 
@@ -151,6 +152,7 @@ module WorkOS
151
152
  message: message,
152
153
  http_status: http_status,
153
154
  request_id: response['x-request-id'],
155
+ code: code,
154
156
  )
155
157
  end
156
158
  end
@@ -26,6 +26,7 @@ module WorkOS
26
26
  # before a provided Directory ID.
27
27
  # @option options [String] after Pagination cursor to receive records
28
28
  # before a provided Directory ID.
29
+ # @option options [String] organization_id The ID for an Organization configured on WorkOS.
29
30
  #
30
31
  # @return [Hash]
31
32
  sig do
data/lib/workos/errors.rb CHANGED
@@ -17,14 +17,16 @@ module WorkOS
17
17
  error_description: T.nilable(String),
18
18
  http_status: T.nilable(Integer),
19
19
  request_id: T.nilable(String),
20
+ code: T.nilable(String),
20
21
  ).void
21
22
  end
22
- def initialize(message: nil, error: nil, error_description: nil, http_status: nil, request_id: nil)
23
+ def initialize(message: nil, error: nil, error_description: nil, http_status: nil, request_id: nil, code: nil)
23
24
  @message = message
24
25
  @error = error
25
26
  @error_description = error_description
26
27
  @http_status = http_status
27
28
  @request_id = request_id
29
+ @code = code
28
30
  end
29
31
 
30
32
  sig { returns(String) }
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ module WorkOS
5
+ # The Factor class provides a lightweight wrapper around
6
+ # a WorkOS DirectoryUser resource. This class is not meant to be instantiated
7
+ # in DirectoryUser space, and is instantiated internally but exposed.
8
+ class Factor
9
+ # rubocop:disable Metrics/AbcSize
10
+ extend T::Sig
11
+ attr_accessor :id, :environment_id, :object, :type, :sms, :totp, :updated_at, :created_at
12
+
13
+ sig { params(json: String).void }
14
+ def initialize(json)
15
+ raw = parse_json(json)
16
+ @id = T.let(raw.id, String)
17
+ @environment_id = T.let(raw.environment_id, String)
18
+ @object = T.let(raw.object, String)
19
+ @type = T.let(raw.type, String)
20
+ @created_at = T.let(raw.created_at, String)
21
+ @updated_at = T.let(raw.updated_at, String)
22
+ @totp = raw.totp
23
+ @sms = raw.sms
24
+ end
25
+
26
+ def to_json(*)
27
+ {
28
+ id: id,
29
+ environment_id: environment_id,
30
+ object: object,
31
+ type: type,
32
+ totp: totp,
33
+ sms: sms,
34
+ created_at: created_at,
35
+ updated_at: updated_at,
36
+ }
37
+ end
38
+
39
+ private
40
+
41
+ sig { params(json_string: String).returns(WorkOS::Types::FactorStruct) }
42
+ def parse_json(json_string)
43
+ hash = JSON.parse(json_string, symbolize_names: true)
44
+
45
+ WorkOS::Types::FactorStruct.new(
46
+ id: hash[:id],
47
+ environment_id: hash[:environment_id],
48
+ object: hash[:object],
49
+ type: hash[:type],
50
+ totp: hash[:totp],
51
+ sms: hash[:sms],
52
+ created_at: hash[:created_at],
53
+ updated_at: hash[:updated_at],
54
+ )
55
+ end
56
+ # rubocop:enable Metrics/AbcSize
57
+ end
58
+ end
data/lib/workos/mfa.rb ADDED
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+
5
+ require 'net/http'
6
+ require 'uri'
7
+
8
+ module WorkOS
9
+ # The MFA module provides convenience methods for working with the WorkOS
10
+ # MFA platform. You'll need a valid API key
11
+ module MFA
12
+ class << self
13
+ extend T::Sig
14
+ include Base
15
+ include Client
16
+ sig { params(id: String).returns(T::Boolean) }
17
+ def delete_factor(id:)
18
+ response = execute_request(
19
+ request: delete_request(
20
+ path: "/auth/factors/#{id}",
21
+ auth: true,
22
+ ),
23
+ )
24
+ response.is_a? Net::HTTPSuccess
25
+ end
26
+
27
+ sig do
28
+ params(id: String).returns(WorkOS::Factor)
29
+ end
30
+ def get_factor(
31
+ id:
32
+ )
33
+ response = execute_request(
34
+ request: get_request(
35
+ path: "/auth/factors/#{id}",
36
+ auth: true,
37
+ ),
38
+ )
39
+ WorkOS::Factor.new(response.body)
40
+ end
41
+
42
+ sig do
43
+ params(
44
+ type: String,
45
+ totp_issuer: T.nilable(String),
46
+ totp_user: T.nilable(String),
47
+ phone_number: T.nilable(String),
48
+ ).void
49
+ end
50
+ # rubocop:disable Metrics/CyclomaticComplexity
51
+ # rubocop:disable Metrics/PerceivedComplexity
52
+
53
+ def validate_args(
54
+ type:,
55
+ totp_issuer: nil,
56
+ totp_user: nil,
57
+ phone_number: nil
58
+ )
59
+ if type != 'sms' && type != 'totp' && type != 'generic_otp'
60
+ raise ArgumentError, "Type argument must be either 'sms' or 'totp'"
61
+ end
62
+ if (type == 'totp' && totp_issuer.nil?) || (type == 'totp' && totp_user.nil?)
63
+ raise ArgumentError, 'Incomplete arguments. Need to specify both totp_issuer and totp_user when type is totp'
64
+ end
65
+ return unless type == 'sms' && phone_number.nil?
66
+
67
+ raise ArgumentError, 'Incomplete arguments. Need to specify phone_number when type is sms'
68
+ end
69
+ # rubocop:enable Metrics/CyclomaticComplexity
70
+ # rubocop:enable Metrics/PerceivedComplexity
71
+
72
+ sig do
73
+ params(
74
+ type: String,
75
+ totp_issuer: T.nilable(String),
76
+ totp_user: T.nilable(String),
77
+ phone_number: T.nilable(String),
78
+ ).returns(WorkOS::Factor)
79
+ end
80
+ # rubocop:disable Metrics/MethodLength
81
+ def enroll_factor(
82
+ type:,
83
+ totp_issuer: nil,
84
+ totp_user: nil,
85
+ phone_number: nil
86
+ )
87
+ validate_args(
88
+ type: type,
89
+ totp_issuer: totp_issuer,
90
+ totp_user: totp_user,
91
+ phone_number: phone_number,
92
+ )
93
+ response = execute_request(request: post_request(
94
+ auth: true,
95
+ body: {
96
+ type: type,
97
+ totp_issuer: totp_issuer,
98
+ totp_user: totp_user,
99
+ phone_number: phone_number,
100
+ },
101
+ path: '/auth/factors/enroll',
102
+ ))
103
+ WorkOS::Factor.new(response.body)
104
+ end
105
+ # rubocop:enable Metrics/MethodLength
106
+
107
+ sig do
108
+ params(
109
+ authentication_factor_id: T.nilable(String),
110
+ sms_template: T.nilable(String),
111
+ ).returns(WorkOS::Challenge)
112
+ end
113
+ def challenge_factor(
114
+ authentication_factor_id: nil,
115
+ sms_template: nil
116
+ )
117
+ if authentication_factor_id.nil?
118
+ raise ArgumentError, "Incomplete arguments: 'authentication_factor_id' is a required argument"
119
+ end
120
+
121
+ request = post_request(
122
+ auth: true,
123
+ body: {
124
+ sms_template: sms_template,
125
+ authentication_factor_id: authentication_factor_id,
126
+ },
127
+ path: '/auth/factors/challenge',
128
+ )
129
+
130
+ response = execute_request(request: request)
131
+ WorkOS::Challenge.new(response.body)
132
+ end
133
+
134
+ sig do
135
+ params(
136
+ authentication_challenge_id: T.nilable(String),
137
+ code: T.nilable(String),
138
+ ).returns(WorkOS::VerifyFactor)
139
+ end
140
+ def verify_factor(
141
+ authentication_challenge_id: nil,
142
+ code: nil
143
+ )
144
+
145
+ if authentication_challenge_id.nil? || code.nil?
146
+ raise ArgumentError, "Incomplete arguments: 'authentication_challenge_id' and 'code' are required arguments"
147
+ end
148
+
149
+ options = {
150
+ "authentication_challenge_id": authentication_challenge_id,
151
+ "code": code,
152
+ }
153
+
154
+ response = execute_request(
155
+ request: post_request(
156
+ path: '/auth/factors/verify',
157
+ auth: true,
158
+ body: options,
159
+ ),
160
+ )
161
+ WorkOS::VerifyFactor.new(response.body)
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module WorkOS
5
+ module Types
6
+ # This ChallgengeStruct acts as a typed interface
7
+ # for the Factor class
8
+ class ChallengeStruct < T::Struct
9
+ const :id, String
10
+ const :object, String
11
+ const :expires_at, T.nilable(String)
12
+ const :code, T.nilable(String)
13
+ const :authentication_factor_id, String
14
+ const :created_at, String
15
+ const :updated_at, String
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module WorkOS
5
+ module Types
6
+ # This FactorStruct acts as a typed interface
7
+ # for the Factor class
8
+ class FactorStruct < T::Struct
9
+ const :id, String
10
+ const :environment_id, String
11
+ const :object, String
12
+ const :type, String
13
+ const :totp, T.nilable(T::Hash[Symbol, Object])
14
+ const :sms, T.nilable(T::Hash[Symbol, Object])
15
+ const :created_at, String
16
+ const :updated_at, String
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module WorkOS
5
+ module Types
6
+ # This VerifyFactorStruct acts as a typed interface
7
+ # for the Factor class
8
+ class VerifyFactorStruct < T::Struct
9
+ const :challenge, T.nilable(T::Hash[Symbol, Object])
10
+ const :valid, T.nilable(TrueClass)
11
+ const :code, T.nilable(String)
12
+ const :message, T.nilable(String)
13
+ end
14
+ end
15
+ end
data/lib/workos/types.rb CHANGED
@@ -16,5 +16,8 @@ module WorkOS
16
16
  require_relative 'types/provider_enum'
17
17
  require_relative 'types/directory_user_struct'
18
18
  require_relative 'types/webhook_struct'
19
+ require_relative 'types/factor_struct'
20
+ require_relative 'types/challenge_struct'
21
+ require_relative 'types/verify_factor_struct'
19
22
  end
20
23
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ module WorkOS
5
+ # The VerifyFactor class provides a lightweight wrapper around
6
+ # a WorkOS DirectoryUser resource. This class is not meant to be instantiated
7
+ # in DirectoryUser space, and is instantiated internally but exposed.
8
+ class VerifyFactor
9
+ extend T::Sig
10
+
11
+ attr_accessor :challenge, :valid
12
+
13
+ sig { params(json: String).void }
14
+ def initialize(json)
15
+ raw = parse_json(json)
16
+ @challenge = T.let(raw.challenge, Hash)
17
+ @valid = raw.valid
18
+ end
19
+
20
+ def to_json(*)
21
+ {
22
+ challenge: challenge,
23
+ valid: valid,
24
+ }
25
+ end
26
+
27
+ private
28
+
29
+ sig { params(json_string: String).returns(WorkOS::Types::VerifyFactorStruct) }
30
+ def parse_json(json_string)
31
+ hash = JSON.parse(json_string, symbolize_names: true)
32
+
33
+ WorkOS::Types::VerifyFactorStruct.new(
34
+ challenge: hash[:challenge],
35
+ valid: hash[:valid],
36
+ )
37
+ end
38
+ end
39
+ end
@@ -2,5 +2,5 @@
2
2
  # typed: strong
3
3
 
4
4
  module WorkOS
5
- VERSION = '2.1.1'
5
+ VERSION = '2.2.0'
6
6
  end
@@ -108,7 +108,7 @@ module WorkOS
108
108
  sig do
109
109
  params(
110
110
  sig_header: String,
111
- ).returns(T::Array[T.untyped])
111
+ ).returns([String, String])
112
112
  end
113
113
  def get_timestamp_and_signature_hash(
114
114
  sig_header:
data/lib/workos.rb CHANGED
@@ -44,6 +44,11 @@ module WorkOS
44
44
  autoload :DirectoryUser, 'workos/directory_user'
45
45
  autoload :Webhook, 'workos/webhook'
46
46
  autoload :Webhooks, 'workos/webhooks'
47
+ autoload :MFA, 'workos/mfa'
48
+ autoload :Factor, 'workos/factor'
49
+ autoload :Challenge, 'workos/challenge'
50
+ autoload :VerifyFactor, 'workos/verify_factor'
51
+
47
52
 
48
53
  # Errors
49
54
  autoload :APIError, 'workos/errors'