workosv2 2.15.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 +7 -0
- data/.github/CODEOWNERS +5 -0
- data/.github/pull_request_template.md +11 -0
- data/.github/renovate.json +5 -0
- data/.gitignore +49 -0
- data/.rspec +1 -0
- data/.rubocop.yml +24 -0
- data/.ruby-version +1 -0
- data/.semaphore/rubygems.yml +24 -0
- data/.semaphore/semaphore.yml +51 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +126 -0
- data/Gemfile.lock.old +127 -0
- data/LICENSE +21 -0
- data/README.md +53 -0
- data/bin/build +3 -0
- data/bin/console +3 -0
- data/bin/docs +5 -0
- data/bin/publish +3 -0
- data/bin/tapioca +29 -0
- data/codecov.yml +12 -0
- data/docs/WorkOS/APIError.html +160 -0
- data/docs/WorkOS/AuditLog.html +235 -0
- data/docs/WorkOS/AuditTrail.html +235 -0
- data/docs/WorkOS/AuthenticationError.html +160 -0
- data/docs/WorkOS/Base.html +287 -0
- data/docs/WorkOS/Client.html +504 -0
- data/docs/WorkOS/InvalidRequestError.html +160 -0
- data/docs/WorkOS/Profile.html +788 -0
- data/docs/WorkOS/RequestError.html +135 -0
- data/docs/WorkOS/SSO.html +691 -0
- data/docs/WorkOS/Types/ProfileStruct.html +135 -0
- data/docs/WorkOS/Types/Provider.html +135 -0
- data/docs/WorkOS/Types.html +128 -0
- data/docs/WorkOS/WorkOSError.html +447 -0
- data/docs/WorkOS.html +324 -0
- data/docs/class_list.html +51 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +496 -0
- data/docs/file.README.html +252 -0
- data/docs/file_list.html +56 -0
- data/docs/frames.html +17 -0
- data/docs/index.html +250 -0
- data/docs/js/app.js +314 -0
- data/docs/js/full_list.js +216 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +267 -0
- data/docs/top-level-namespace.html +110 -0
- data/lib/workosv2/audit_log_export.rb +55 -0
- data/lib/workosv2/audit_logs.rb +114 -0
- data/lib/workosv2/audit_trail.rb +111 -0
- data/lib/workosv2/challenge.rb +55 -0
- data/lib/workosv2/client.rb +186 -0
- data/lib/workosv2/configuration.rb +17 -0
- data/lib/workosv2/connection.rb +66 -0
- data/lib/workosv2/deprecated_hash_wrapper.rb +76 -0
- data/lib/workosv2/directory.rb +65 -0
- data/lib/workosv2/directory_group.rb +68 -0
- data/lib/workosv2/directory_sync.rb +218 -0
- data/lib/workosv2/directory_user.rb +97 -0
- data/lib/workosv2/errors.rb +81 -0
- data/lib/workosv2/event.rb +51 -0
- data/lib/workosv2/events.rb +52 -0
- data/lib/workosv2/factor.rb +54 -0
- data/lib/workosv2/hash_provider.rb +19 -0
- data/lib/workosv2/mfa.rb +178 -0
- data/lib/workosv2/organization.rb +57 -0
- data/lib/workosv2/organizations.rb +188 -0
- data/lib/workosv2/passwordless.rb +85 -0
- data/lib/workosv2/portal.rb +66 -0
- data/lib/workosv2/profile.rb +76 -0
- data/lib/workosv2/profile_and_token.rb +29 -0
- data/lib/workosv2/sso.rb +297 -0
- data/lib/workosv2/types/audit_log_export_struct.rb +17 -0
- data/lib/workosv2/types/challenge_struct.rb +18 -0
- data/lib/workosv2/types/connection_struct.rb +20 -0
- data/lib/workosv2/types/directory_group_struct.rb +19 -0
- data/lib/workosv2/types/directory_struct.rb +19 -0
- data/lib/workosv2/types/directory_user_struct.rb +26 -0
- data/lib/workosv2/types/event_struct.rb +15 -0
- data/lib/workosv2/types/factor_struct.rb +18 -0
- data/lib/workosv2/types/intent_enum.rb +17 -0
- data/lib/workosv2/types/list_struct.rb +13 -0
- data/lib/workosv2/types/organization_struct.rb +17 -0
- data/lib/workosv2/types/passwordless_session_struct.rb +17 -0
- data/lib/workosv2/types/profile_struct.rb +21 -0
- data/lib/workosv2/types/provider_enum.rb +15 -0
- data/lib/workosv2/types/verify_challenge_struct.rb +13 -0
- data/lib/workosv2/types/webhook_struct.rb +15 -0
- data/lib/workosv2/types.rb +25 -0
- data/lib/workosv2/verify_challenge.rb +39 -0
- data/lib/workosv2/version.rb +6 -0
- data/lib/workosv2/webhook.rb +51 -0
- data/lib/workosv2/webhooks.rb +217 -0
- data/lib/workosv2.rb +79 -0
- data/sorbet/config +2 -0
- data/sorbet/rbi/gems/addressable@2.8.0.rbi +290 -0
- data/sorbet/rbi/gems/ast@2.4.2.rbi +54 -0
- data/sorbet/rbi/gems/codecov@0.2.12.rbi +55 -0
- data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
- data/sorbet/rbi/gems/crack@0.4.5.rbi +57 -0
- data/sorbet/rbi/gems/diff-lcs@1.4.4.rbi +185 -0
- data/sorbet/rbi/gems/docile@1.3.5.rbi +54 -0
- data/sorbet/rbi/gems/hashdiff@1.0.1.rbi +82 -0
- data/sorbet/rbi/gems/json@2.5.1.rbi +109 -0
- data/sorbet/rbi/gems/method_source@1.0.0.rbi +8 -0
- data/sorbet/rbi/gems/parallel@1.20.1.rbi +113 -0
- data/sorbet/rbi/gems/parser@3.0.1.0.rbi +1187 -0
- data/sorbet/rbi/gems/pry@0.14.2.rbi +8 -0
- data/sorbet/rbi/gems/public_suffix@4.0.6.rbi +146 -0
- data/sorbet/rbi/gems/rainbow@3.0.0.rbi +153 -0
- data/sorbet/rbi/gems/rake@13.0.3.rbi +807 -0
- data/sorbet/rbi/gems/rbi@0.0.16.rbi +2118 -0
- data/sorbet/rbi/gems/regexp_parser@2.1.1.rbi +1117 -0
- data/sorbet/rbi/gems/rexml@3.2.5.rbi +709 -0
- data/sorbet/rbi/gems/rspec-core@3.9.3.rbi +2467 -0
- data/sorbet/rbi/gems/rspec-expectations@3.9.4.rbi +1569 -0
- data/sorbet/rbi/gems/rspec-mocks@3.9.1.rbi +1493 -0
- data/sorbet/rbi/gems/rspec-support@3.9.4.rbi +511 -0
- data/sorbet/rbi/gems/rspec@3.9.0.rbi +38 -0
- data/sorbet/rbi/gems/rubocop-ast@1.4.1.rbi +1881 -0
- data/sorbet/rbi/gems/rubocop@0.93.1.rbi +11497 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +405 -0
- data/sorbet/rbi/gems/simplecov-html@0.12.3.rbi +89 -0
- data/sorbet/rbi/gems/simplecov@0.21.2.rbi +577 -0
- data/sorbet/rbi/gems/simplecov_json_formatter@0.1.2.rbi +8 -0
- data/sorbet/rbi/gems/spoom@1.1.15.rbi +1549 -0
- data/sorbet/rbi/gems/tapioca@0.7.3.rbi +1718 -0
- data/sorbet/rbi/gems/thor@1.2.1.rbi +844 -0
- data/sorbet/rbi/gems/unicode-display_width@1.7.0.rbi +22 -0
- data/sorbet/rbi/gems/unparser@0.6.2.rbi +8 -0
- data/sorbet/rbi/gems/vcr@5.0.0.rbi +699 -0
- data/sorbet/rbi/gems/webmock@3.12.2.rbi +662 -0
- data/sorbet/rbi/gems/yard-sorbet@0.8.0.rbi +268 -0
- data/sorbet/rbi/gems/yard@0.9.26.rbi +4048 -0
- data/sorbet/tapioca/config.yml +13 -0
- data/sorbet/tapioca/require.rb +4 -0
- data/spec/lib/workos/audit_logs_spec.rb +151 -0
- data/spec/lib/workos/audit_trail_spec.rb +146 -0
- data/spec/lib/workos/configuration_spec.rb +61 -0
- data/spec/lib/workos/directory_sync_spec.rb +492 -0
- data/spec/lib/workos/directory_user_spec.rb +36 -0
- data/spec/lib/workos/event_spec.rb +88 -0
- data/spec/lib/workos/mfa_spec.rb +281 -0
- data/spec/lib/workos/organizations_spec.rb +257 -0
- data/spec/lib/workos/passwordless_spec.rb +77 -0
- data/spec/lib/workos/portal_spec.rb +87 -0
- data/spec/lib/workos/sso_spec.rb +650 -0
- data/spec/lib/workos/webhooks_spec.rb +236 -0
- data/spec/spec_helper.rb +56 -0
- data/spec/support/fixtures/vcr_cassettes/audit_logs/create_event.yml +59 -0
- data/spec/support/fixtures/vcr_cassettes/audit_logs/create_event_custom_idempotency_key.yml +60 -0
- data/spec/support/fixtures/vcr_cassettes/audit_logs/create_event_invalid.yml +59 -0
- data/spec/support/fixtures/vcr_cassettes/audit_logs/create_export.yml +76 -0
- data/spec/support/fixtures/vcr_cassettes/audit_logs/create_export_with_filters.yml +77 -0
- data/spec/support/fixtures/vcr_cassettes/audit_logs/get_export.yml +73 -0
- data/spec/support/fixtures/vcr_cassettes/audit_trail/create_event.yml +65 -0
- data/spec/support/fixtures/vcr_cassettes/audit_trail/create_event_custom_idempotency_key.yml +67 -0
- data/spec/support/fixtures/vcr_cassettes/audit_trail/create_event_invalid.yml +68 -0
- data/spec/support/fixtures/vcr_cassettes/audit_trail/create_events_duplicate_idempotency_key_and_payload.yml +131 -0
- data/spec/support/fixtures/vcr_cassettes/audit_trail/create_events_duplicate_idempotency_key_different_payload.yml +134 -0
- data/spec/support/fixtures/vcr_cassettes/audit_trail/get_events.yml +61 -0
- data/spec/support/fixtures/vcr_cassettes/base/execute_request_unauthenticated.yml +66 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/delete_directory.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/get_directory_with_invalid_id.yml +83 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/get_directory_with_valid_id.yml +84 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/get_group.yml +80 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/get_group_with_invalid_id.yml +62 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/get_user.yml +83 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/get_user_with_invalid_id.yml +62 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_after.yml +87 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_before.yml +89 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_domain.yml +84 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_limit.yml +85 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_no_options.yml +93 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_directories/with_search.yml +85 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_after.yml +90 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_before.yml +90 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_directory.yml +90 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_limit.yml +84 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_no_options.yml +84 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_groups/with_user.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_after.yml +186 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_before.yml +88 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_directory.yml +194 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_group.yml +186 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_limit.yml +189 -0
- data/spec/support/fixtures/vcr_cassettes/directory_sync/list_users/with_no_options.yml +74 -0
- data/spec/support/fixtures/vcr_cassettes/events/list_events_with_after.yml +80 -0
- data/spec/support/fixtures/vcr_cassettes/events/list_events_with_event.yml +80 -0
- data/spec/support/fixtures/vcr_cassettes/events/list_events_with_no_options.yml +80 -0
- data/spec/support/fixtures/vcr_cassettes/events/list_events_with_range.yml +80 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_generic_valid.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_sms_valid.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_totp_valid.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/delete_factor.yml +80 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_generic_valid.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_sms_valid.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_totp_valid.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/get_factor_invalid.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/get_factor_valid.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/verify_challenge_generic_expired.yml +84 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/verify_challenge_generic_invalid.yml +84 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/verify_challenge_generic_valid.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/mfa/verify_challenge_generic_valid_is_false.yml +82 -0
- data/spec/support/fixtures/vcr_cassettes/organization/create.yml +84 -0
- data/spec/support/fixtures/vcr_cassettes/organization/create_invalid.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/organization/create_with_duplicate_idempotency_key_and_different_payload.yml +155 -0
- data/spec/support/fixtures/vcr_cassettes/organization/create_with_duplicate_idempotency_key_and_payload.yml +154 -0
- data/spec/support/fixtures/vcr_cassettes/organization/create_with_idempotency_key.yml +79 -0
- data/spec/support/fixtures/vcr_cassettes/organization/delete.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/organization/delete_invalid.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/organization/get.yml +84 -0
- data/spec/support/fixtures/vcr_cassettes/organization/get_invalid.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/organization/list.yml +87 -0
- data/spec/support/fixtures/vcr_cassettes/organization/update.yml +84 -0
- data/spec/support/fixtures/vcr_cassettes/passwordless/create_session.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/passwordless/create_session_invalid.yml +73 -0
- data/spec/support/fixtures/vcr_cassettes/passwordless/send_session.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/passwordless/send_session_invalid.yml +73 -0
- data/spec/support/fixtures/vcr_cassettes/portal/generate_link_audit_logs.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/portal/generate_link_dsync.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/portal/generate_link_invalid.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/portal/generate_link_sso.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/sso/delete_connection_with_invalid_id.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/sso/delete_connection_with_valid_id.yml +70 -0
- data/spec/support/fixtures/vcr_cassettes/sso/get_connection_with_invalid_id.yml +72 -0
- data/spec/support/fixtures/vcr_cassettes/sso/get_connection_with_valid_id.yml +86 -0
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_after.yml +83 -0
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_before.yml +86 -0
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_connection_type.yml +90 -0
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_domain.yml +86 -0
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_limit.yml +83 -0
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_no_options.yml +89 -0
- data/spec/support/fixtures/vcr_cassettes/sso/list_connections/with_organization_id.yml +86 -0
- data/spec/support/fixtures/vcr_cassettes/sso/profile.yml +74 -0
- data/spec/support/profile.txt +1 -0
- data/spec/support/shared_examples/client_spec.rb +30 -0
- data/spec/support/webhook_payload.txt +1 -0
- data/workosv2.gemspec +38 -0
- metadata +531 -0
data/lib/workosv2/mfa.rb
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
|
5
|
+
require 'net/http'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
module WorkOSV2
|
9
|
+
# The MFA module provides convenience methods for working with the WorkOSV2
|
10
|
+
# MFA platform. You'll need a valid API key
|
11
|
+
module MFA
|
12
|
+
class << self
|
13
|
+
extend T::Sig
|
14
|
+
include Client
|
15
|
+
sig { params(id: String).returns(T::Boolean) }
|
16
|
+
def delete_factor(id:)
|
17
|
+
response = execute_request(
|
18
|
+
request: delete_request(
|
19
|
+
path: "/auth/factors/#{id}",
|
20
|
+
auth: true,
|
21
|
+
),
|
22
|
+
)
|
23
|
+
response.is_a? Net::HTTPSuccess
|
24
|
+
end
|
25
|
+
|
26
|
+
sig do
|
27
|
+
params(id: String).returns(WorkOSV2::Factor)
|
28
|
+
end
|
29
|
+
def get_factor(
|
30
|
+
id:
|
31
|
+
)
|
32
|
+
response = execute_request(
|
33
|
+
request: get_request(
|
34
|
+
path: "/auth/factors/#{id}",
|
35
|
+
auth: true,
|
36
|
+
),
|
37
|
+
)
|
38
|
+
WorkOSV2::Factor.new(response.body)
|
39
|
+
end
|
40
|
+
|
41
|
+
sig do
|
42
|
+
params(
|
43
|
+
type: String,
|
44
|
+
totp_issuer: T.nilable(String),
|
45
|
+
totp_user: T.nilable(String),
|
46
|
+
phone_number: T.nilable(String),
|
47
|
+
).void
|
48
|
+
end
|
49
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
50
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
51
|
+
|
52
|
+
def validate_args(
|
53
|
+
type:,
|
54
|
+
totp_issuer: nil,
|
55
|
+
totp_user: nil,
|
56
|
+
phone_number: nil
|
57
|
+
)
|
58
|
+
if type != 'sms' && type != 'totp' && type != 'generic_otp'
|
59
|
+
raise ArgumentError, "Type argument must be either 'sms' or 'totp'"
|
60
|
+
end
|
61
|
+
if (type == 'totp' && totp_issuer.nil?) || (type == 'totp' && totp_user.nil?)
|
62
|
+
raise ArgumentError, 'Incomplete arguments. Need to specify both totp_issuer and totp_user when type is totp'
|
63
|
+
end
|
64
|
+
return unless type == 'sms' && phone_number.nil?
|
65
|
+
|
66
|
+
raise ArgumentError, 'Incomplete arguments. Need to specify phone_number when type is sms'
|
67
|
+
end
|
68
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
69
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
70
|
+
|
71
|
+
sig do
|
72
|
+
params(
|
73
|
+
type: String,
|
74
|
+
totp_issuer: T.nilable(String),
|
75
|
+
totp_user: T.nilable(String),
|
76
|
+
phone_number: T.nilable(String),
|
77
|
+
).returns(WorkOSV2::Factor)
|
78
|
+
end
|
79
|
+
def enroll_factor(
|
80
|
+
type:,
|
81
|
+
totp_issuer: nil,
|
82
|
+
totp_user: nil,
|
83
|
+
phone_number: nil
|
84
|
+
)
|
85
|
+
validate_args(
|
86
|
+
type: type,
|
87
|
+
totp_issuer: totp_issuer,
|
88
|
+
totp_user: totp_user,
|
89
|
+
phone_number: phone_number,
|
90
|
+
)
|
91
|
+
response = execute_request(request: post_request(
|
92
|
+
auth: true,
|
93
|
+
body: {
|
94
|
+
type: type,
|
95
|
+
totp_issuer: totp_issuer,
|
96
|
+
totp_user: totp_user,
|
97
|
+
phone_number: phone_number,
|
98
|
+
},
|
99
|
+
path: '/auth/factors/enroll',
|
100
|
+
))
|
101
|
+
WorkOSV2::Factor.new(response.body)
|
102
|
+
end
|
103
|
+
|
104
|
+
sig do
|
105
|
+
params(
|
106
|
+
authentication_factor_id: T.nilable(String),
|
107
|
+
sms_template: T.nilable(String),
|
108
|
+
).returns(WorkOSV2::Challenge)
|
109
|
+
end
|
110
|
+
def challenge_factor(
|
111
|
+
authentication_factor_id: nil,
|
112
|
+
sms_template: nil
|
113
|
+
)
|
114
|
+
if authentication_factor_id.nil?
|
115
|
+
raise ArgumentError, "Incomplete arguments: 'authentication_factor_id' is a required argument"
|
116
|
+
end
|
117
|
+
|
118
|
+
request = post_request(
|
119
|
+
auth: true,
|
120
|
+
body: {
|
121
|
+
sms_template: sms_template,
|
122
|
+
},
|
123
|
+
path: "/auth/factors/#{authentication_factor_id}/challenge",
|
124
|
+
)
|
125
|
+
|
126
|
+
response = execute_request(request: request)
|
127
|
+
WorkOSV2::Challenge.new(response.body)
|
128
|
+
end
|
129
|
+
|
130
|
+
sig do
|
131
|
+
params(
|
132
|
+
authentication_challenge_id: T.nilable(String),
|
133
|
+
code: T.nilable(String),
|
134
|
+
).returns(WorkOSV2::VerifyChallenge)
|
135
|
+
end
|
136
|
+
def verify_factor(
|
137
|
+
authentication_challenge_id: nil,
|
138
|
+
code: nil
|
139
|
+
)
|
140
|
+
warn '[DEPRECATION] `verify_factor` is deprecated. Please use `verify_challenge` instead.'
|
141
|
+
|
142
|
+
verify_challenge(
|
143
|
+
authentication_challenge_id: authentication_challenge_id,
|
144
|
+
code: code,
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
sig do
|
149
|
+
params(
|
150
|
+
authentication_challenge_id: T.nilable(String),
|
151
|
+
code: T.nilable(String),
|
152
|
+
).returns(WorkOSV2::VerifyChallenge)
|
153
|
+
end
|
154
|
+
def verify_challenge(
|
155
|
+
authentication_challenge_id: nil,
|
156
|
+
code: nil
|
157
|
+
)
|
158
|
+
|
159
|
+
if authentication_challenge_id.nil? || code.nil?
|
160
|
+
raise ArgumentError, "Incomplete arguments: 'authentication_challenge_id' and 'code' are required arguments"
|
161
|
+
end
|
162
|
+
|
163
|
+
options = {
|
164
|
+
"code": code,
|
165
|
+
}
|
166
|
+
|
167
|
+
response = execute_request(
|
168
|
+
request: post_request(
|
169
|
+
path: "/auth/challenges/#{authentication_challenge_id}/verify",
|
170
|
+
auth: true,
|
171
|
+
body: options,
|
172
|
+
),
|
173
|
+
)
|
174
|
+
WorkOSV2::VerifyChallenge.new(response.body)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module WorkOSV2
|
5
|
+
# The Organization class provides a lightweight wrapper around
|
6
|
+
# a WorkOSV2 Organization resource. This class is not meant to be instantiated
|
7
|
+
# in user space, and is instantiated internally but exposed.
|
8
|
+
class Organization
|
9
|
+
include HashProvider
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
attr_accessor :id, :domains, :name, :allow_profiles_outside_organization, :created_at, :updated_at
|
13
|
+
|
14
|
+
sig { params(json: String).void }
|
15
|
+
def initialize(json)
|
16
|
+
raw = parse_json(json)
|
17
|
+
|
18
|
+
@id = T.let(raw.id, String)
|
19
|
+
@name = T.let(raw.name, String)
|
20
|
+
@allow_profiles_outside_organization = T.let(raw.allow_profiles_outside_organization, T::Boolean)
|
21
|
+
@domains = T.let(raw.domains, Array)
|
22
|
+
@created_at = T.let(raw.created_at, String)
|
23
|
+
@updated_at = T.let(raw.updated_at, String)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_json(*)
|
27
|
+
{
|
28
|
+
id: id,
|
29
|
+
name: name,
|
30
|
+
allow_profiles_outside_organization: allow_profiles_outside_organization,
|
31
|
+
domains: domains,
|
32
|
+
created_at: created_at,
|
33
|
+
updated_at: updated_at,
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
sig do
|
40
|
+
params(
|
41
|
+
json_string: String,
|
42
|
+
).returns(WorkOSV2::Types::OrganizationStruct)
|
43
|
+
end
|
44
|
+
def parse_json(json_string)
|
45
|
+
hash = JSON.parse(json_string, symbolize_names: true)
|
46
|
+
|
47
|
+
WorkOSV2::Types::OrganizationStruct.new(
|
48
|
+
id: hash[:id],
|
49
|
+
name: hash[:name],
|
50
|
+
allow_profiles_outside_organization: hash[:allow_profiles_outside_organization],
|
51
|
+
domains: hash[:domains],
|
52
|
+
created_at: hash[:created_at],
|
53
|
+
updated_at: hash[:updated_at],
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
module WorkOSV2
|
7
|
+
# The Organizations module provides resource methods for working with Organizations
|
8
|
+
module Organizations
|
9
|
+
class << self
|
10
|
+
extend T::Sig
|
11
|
+
include Client
|
12
|
+
|
13
|
+
# Retrieve a list of organizations that have connections configured
|
14
|
+
# within your WorkOSV2 dashboard.
|
15
|
+
#
|
16
|
+
# @param [Array<String>] domains Filter organizations to only return those
|
17
|
+
# that are associated with the provided domains.
|
18
|
+
# @param [String] before A pagination argument used to request
|
19
|
+
# organizations before the provided Organization ID.
|
20
|
+
# @param [String] after A pagination argument used to request
|
21
|
+
# organizations after the provided Organization ID.
|
22
|
+
# @param [Integer] limit A pagination argument used to limit the number
|
23
|
+
# @param [String] order The order in which to paginate records
|
24
|
+
# of listed Organizations that are returned.
|
25
|
+
sig do
|
26
|
+
params(
|
27
|
+
options: T::Hash[Symbol, String],
|
28
|
+
).returns(WorkOSV2::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
|
+
::WorkOSV2::Organization.new(organization.to_json)
|
43
|
+
end
|
44
|
+
|
45
|
+
WorkOSV2::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
|
+
# WorkOSV2::Portal.get_organization(id: 'org_02DRA1XNSJDZ19A31F183ECQW9')
|
57
|
+
# => #<WorkOSV2::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 [WorkOSV2::Organization]
|
66
|
+
sig { params(id: String).returns(WorkOSV2::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
|
+
WorkOSV2::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
|
+
# @param [Boolean, nil] allow_profiles_outside_organization Whether Connections
|
84
|
+
# within the Organization allow profiles that are outside of the Organization's configured User Email Domains.
|
85
|
+
# @param [String] idempotency_key An idempotency key
|
86
|
+
sig do
|
87
|
+
params(
|
88
|
+
domains: T::Array[String],
|
89
|
+
name: String,
|
90
|
+
allow_profiles_outside_organization: T.nilable(T::Boolean),
|
91
|
+
idempotency_key: T.nilable(String),
|
92
|
+
).returns(WorkOSV2::Organization)
|
93
|
+
end
|
94
|
+
def create_organization(domains:, name:, allow_profiles_outside_organization: nil, idempotency_key: nil)
|
95
|
+
request = post_request(
|
96
|
+
auth: true,
|
97
|
+
body: {
|
98
|
+
domains: domains,
|
99
|
+
name: name,
|
100
|
+
allow_profiles_outside_organization: allow_profiles_outside_organization,
|
101
|
+
},
|
102
|
+
path: '/organizations',
|
103
|
+
idempotency_key: idempotency_key,
|
104
|
+
)
|
105
|
+
|
106
|
+
response = execute_request(request: request)
|
107
|
+
check_and_raise_organization_error(response: response)
|
108
|
+
|
109
|
+
WorkOSV2::Organization.new(response.body)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Update an organization
|
113
|
+
#
|
114
|
+
# @param [String] organization Organization unique identifier
|
115
|
+
# @param [Array<String>] domains List of domains that belong to the
|
116
|
+
# organization
|
117
|
+
# @param [String] name A unique, descriptive name for the organization
|
118
|
+
# @param [Boolean, nil] allow_profiles_outside_organization Whether Connections
|
119
|
+
# within the Organization allow profiles that are outside of the Organization's configured User Email Domains.
|
120
|
+
sig do
|
121
|
+
params(
|
122
|
+
organization: String,
|
123
|
+
domains: T::Array[String],
|
124
|
+
name: String,
|
125
|
+
allow_profiles_outside_organization: T.nilable(T::Boolean),
|
126
|
+
).returns(WorkOSV2::Organization)
|
127
|
+
end
|
128
|
+
def update_organization(organization:, domains:, name:, allow_profiles_outside_organization: nil)
|
129
|
+
request = put_request(
|
130
|
+
auth: true,
|
131
|
+
body: {
|
132
|
+
domains: domains,
|
133
|
+
name: name,
|
134
|
+
allow_profiles_outside_organization: allow_profiles_outside_organization,
|
135
|
+
},
|
136
|
+
path: "/organizations/#{organization}",
|
137
|
+
)
|
138
|
+
|
139
|
+
response = execute_request(request: request)
|
140
|
+
check_and_raise_organization_error(response: response)
|
141
|
+
|
142
|
+
WorkOSV2::Organization.new(response.body)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Delete an Organization
|
146
|
+
#
|
147
|
+
# @param [String] id Organization unique identifier
|
148
|
+
#
|
149
|
+
# @example
|
150
|
+
# WorkOSV2::SSO.delete_organization(id: 'org_01EHZNVPK3SFK441A1RGBFSHRT')
|
151
|
+
# => true
|
152
|
+
#
|
153
|
+
# @return [Bool] - returns `true` if successful
|
154
|
+
sig { params(id: String).returns(T::Boolean) }
|
155
|
+
def delete_organization(id:)
|
156
|
+
request = delete_request(
|
157
|
+
auth: true,
|
158
|
+
path: "/organizations/#{id}",
|
159
|
+
)
|
160
|
+
|
161
|
+
response = execute_request(request: request)
|
162
|
+
|
163
|
+
response.is_a? Net::HTTPSuccess
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
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
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
module WorkOSV2
|
7
|
+
# The Passwordless module provides convenience methods for working with
|
8
|
+
# passwordless sessions including the WorkOSV2 Magic Link. You'll need a valid
|
9
|
+
# API key.
|
10
|
+
#
|
11
|
+
# @see https://workos.com/docs/sso/configuring-magic-link
|
12
|
+
module Passwordless
|
13
|
+
class << self
|
14
|
+
extend T::Sig
|
15
|
+
include Client
|
16
|
+
|
17
|
+
# Create a Passwordless Session.
|
18
|
+
#
|
19
|
+
# @param [Hash] options A hash with options for the session
|
20
|
+
# @option options [String] email The email of the user to authenticate.
|
21
|
+
# @option options [String] state Optional parameter that the redirect URI
|
22
|
+
# received from WorkOSV2 will contain. The state parameter can be used to
|
23
|
+
# encode arbitrary information to help restore application state between
|
24
|
+
# redirects.
|
25
|
+
# @option options [String] connection Optional parameter for the ID of a
|
26
|
+
# specific connection. This can be used to create a Passwordless Session
|
27
|
+
# for a specific connection rather than using the domain from the email
|
28
|
+
# to determine the Organization and Connection.
|
29
|
+
# @option options [String] type The type of Passwordless Session to
|
30
|
+
# create. Currently, the only supported value is 'MagicLink'.
|
31
|
+
# @option options [String] redirect_uri The URI where users are directed
|
32
|
+
# after completing the authentication step. Must match a
|
33
|
+
# configured redirect URI on your WorkOSV2 dashboard.
|
34
|
+
#
|
35
|
+
# @return Hash
|
36
|
+
sig do
|
37
|
+
params(
|
38
|
+
options: Hash,
|
39
|
+
).returns(WorkOSV2::Types::PasswordlessSessionStruct)
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_session(options)
|
43
|
+
response = execute_request(
|
44
|
+
request: post_request(
|
45
|
+
path: '/passwordless/sessions',
|
46
|
+
auth: true,
|
47
|
+
body: options,
|
48
|
+
),
|
49
|
+
)
|
50
|
+
|
51
|
+
hash = JSON.parse(response.body)
|
52
|
+
|
53
|
+
WorkOSV2::Types::PasswordlessSessionStruct.new(
|
54
|
+
id: hash['id'],
|
55
|
+
email: hash['email'],
|
56
|
+
expires_at: Date.parse(hash['expires_at']),
|
57
|
+
link: hash['link'],
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Send a Passwordless Session via email.
|
62
|
+
#
|
63
|
+
# @param [String] session_id The unique identifier of the Passwordless
|
64
|
+
# Session to send an email for.
|
65
|
+
#
|
66
|
+
# @return Hash
|
67
|
+
sig do
|
68
|
+
params(
|
69
|
+
session_id: String,
|
70
|
+
).returns(T::Hash[String, T::Boolean])
|
71
|
+
end
|
72
|
+
|
73
|
+
def send_session(session_id)
|
74
|
+
response = execute_request(
|
75
|
+
request: post_request(
|
76
|
+
path: "/passwordless/sessions/#{session_id}/send",
|
77
|
+
auth: true,
|
78
|
+
),
|
79
|
+
)
|
80
|
+
|
81
|
+
JSON.parse(response.body)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
module WorkOSV2
|
7
|
+
# The Portal module provides resource methods for working with the Admin
|
8
|
+
# Portal product
|
9
|
+
module Portal
|
10
|
+
class << self
|
11
|
+
extend T::Sig
|
12
|
+
include Client
|
13
|
+
|
14
|
+
GENERATE_LINK_INTENTS = WorkOSV2::Types::Intent.values.map(&:serialize).
|
15
|
+
freeze
|
16
|
+
|
17
|
+
# Generate a link to grant access to an organization's Admin Portal
|
18
|
+
#
|
19
|
+
# @param [String] intent The access scope for the generated Admin Portal
|
20
|
+
# link. Valid values are: ["audit_logs", "dsync", "log_streams", "sso",]
|
21
|
+
# @param [String] organization The ID of the organization the Admin
|
22
|
+
# Portal link will be generated for.
|
23
|
+
# @param [String] The URL that the end user will be redirected to upon
|
24
|
+
# exiting the generated Admin Portal. If none is provided, the default
|
25
|
+
# redirect link set in your WorkOSV2 Dashboard will be used.
|
26
|
+
# @param [String] The URL to which WorkOSV2 will redirect users to upon
|
27
|
+
# successfully setting up Single Sign On or Directory Sync.
|
28
|
+
sig do
|
29
|
+
params(
|
30
|
+
intent: String,
|
31
|
+
organization: String,
|
32
|
+
return_url: T.nilable(String),
|
33
|
+
success_url: T.nilable(String),
|
34
|
+
).returns(String)
|
35
|
+
end
|
36
|
+
def generate_link(intent:, organization:, return_url: nil, success_url: nil)
|
37
|
+
validate_intent(intent)
|
38
|
+
|
39
|
+
request = post_request(
|
40
|
+
auth: true,
|
41
|
+
body: {
|
42
|
+
intent: intent,
|
43
|
+
organization: organization,
|
44
|
+
return_url: return_url,
|
45
|
+
success_url: success_url,
|
46
|
+
},
|
47
|
+
path: '/portal/generate_link',
|
48
|
+
)
|
49
|
+
|
50
|
+
response = execute_request(request: request)
|
51
|
+
|
52
|
+
JSON.parse(response.body)['link']
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
sig { params(intent: String).void }
|
58
|
+
def validate_intent(intent)
|
59
|
+
return if GENERATE_LINK_INTENTS.include?(intent)
|
60
|
+
|
61
|
+
raise ArgumentError, "#{intent} is not a valid value." \
|
62
|
+
" `intent` must be in #{GENERATE_LINK_INTENTS}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module WorkOSV2
|
5
|
+
# The Profile class provides a lighweight wrapper around
|
6
|
+
# a normalized response from the various IDPs WorkOSV2
|
7
|
+
# supports as part of the SSO integration. This class
|
8
|
+
# is not meant to be instantiated in user space, and
|
9
|
+
# is instantiated internally but exposed.
|
10
|
+
class Profile
|
11
|
+
include HashProvider
|
12
|
+
extend T::Sig
|
13
|
+
|
14
|
+
sig { returns(String) }
|
15
|
+
attr_accessor :id, :email, :first_name, :last_name, :groups, :organization_id,
|
16
|
+
:connection_id, :connection_type, :idp_id, :raw_attributes
|
17
|
+
|
18
|
+
# rubocop:disable Metrics/AbcSize
|
19
|
+
sig { params(profile_json: String).void }
|
20
|
+
def initialize(profile_json)
|
21
|
+
raw = parse_json(profile_json)
|
22
|
+
|
23
|
+
@id = T.let(raw.id, String)
|
24
|
+
@email = T.let(raw.email, String)
|
25
|
+
@first_name = raw.first_name
|
26
|
+
@last_name = raw.last_name
|
27
|
+
@groups = raw.groups
|
28
|
+
@organization_id = raw.organization_id
|
29
|
+
@connection_id = T.let(raw.connection_id, String)
|
30
|
+
@connection_type = T.let(raw.connection_type, String)
|
31
|
+
@idp_id = raw.idp_id
|
32
|
+
@raw_attributes = raw.raw_attributes
|
33
|
+
end
|
34
|
+
# rubocop:enable Metrics/AbcSize
|
35
|
+
|
36
|
+
sig { returns(String) }
|
37
|
+
def full_name
|
38
|
+
[first_name, last_name].compact.join(' ')
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_json(*)
|
42
|
+
{
|
43
|
+
id: id,
|
44
|
+
email: email,
|
45
|
+
first_name: first_name,
|
46
|
+
last_name: last_name,
|
47
|
+
groups: groups,
|
48
|
+
organization_id: organization_id,
|
49
|
+
connection_id: connection_id,
|
50
|
+
connection_type: connection_type,
|
51
|
+
idp_id: idp_id,
|
52
|
+
raw_attributes: raw_attributes,
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
sig { params(json_string: String).returns(WorkOSV2::Types::ProfileStruct) }
|
59
|
+
def parse_json(json_string)
|
60
|
+
hash = JSON.parse(json_string, symbolize_names: true)
|
61
|
+
|
62
|
+
WorkOSV2::Types::ProfileStruct.new(
|
63
|
+
id: hash[:id],
|
64
|
+
email: hash[:email],
|
65
|
+
first_name: hash[:first_name],
|
66
|
+
last_name: hash[:last_name],
|
67
|
+
groups: hash[:groups],
|
68
|
+
organization_id: hash[:organization_id],
|
69
|
+
connection_id: hash[:connection_id],
|
70
|
+
connection_type: hash[:connection_type],
|
71
|
+
idp_id: hash[:idp_id],
|
72
|
+
raw_attributes: hash[:raw_attributes],
|
73
|
+
)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# typed: true
|
3
|
+
|
4
|
+
module WorkOSV2
|
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
|
+
include HashProvider
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
attr_accessor :access_token, :profile
|
13
|
+
|
14
|
+
sig { params(profile_and_token_json: String).void }
|
15
|
+
def initialize(profile_and_token_json)
|
16
|
+
json = JSON.parse(profile_and_token_json, symbolize_names: true)
|
17
|
+
|
18
|
+
@access_token = T.let(json[:access_token], String)
|
19
|
+
@profile = WorkOSV2::Profile.new(json[:profile].to_json)
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_json(*)
|
23
|
+
{
|
24
|
+
access_token: access_token,
|
25
|
+
profile: profile.to_json,
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|