workos 0.0.1

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 (83) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +49 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +10 -0
  5. data/.ruby-version +1 -0
  6. data/.semaphore/rubygems.yml +19 -0
  7. data/.semaphore/semaphore.yml +63 -0
  8. data/CODEOWNERS +1 -0
  9. data/Gemfile +5 -0
  10. data/Gemfile.lock +84 -0
  11. data/LICENSE +21 -0
  12. data/README.md +21 -0
  13. data/bin/build +3 -0
  14. data/bin/console +3 -0
  15. data/bin/docs +5 -0
  16. data/bin/publish +3 -0
  17. data/codecov.yml +11 -0
  18. data/docs/WorkOS.html +328 -0
  19. data/docs/WorkOS/Base.html +281 -0
  20. data/docs/WorkOS/Profile.html +725 -0
  21. data/docs/WorkOS/RequestError.html +135 -0
  22. data/docs/WorkOS/SSO.html +511 -0
  23. data/docs/WorkOS/Types.html +129 -0
  24. data/docs/WorkOS/Types/ProfileStruct.html +135 -0
  25. data/docs/class_list.html +51 -0
  26. data/docs/css/common.css +1 -0
  27. data/docs/css/full_list.css +58 -0
  28. data/docs/css/style.css +496 -0
  29. data/docs/file.README.html +92 -0
  30. data/docs/file_list.html +56 -0
  31. data/docs/frames.html +17 -0
  32. data/docs/index.html +189 -0
  33. data/docs/js/app.js +303 -0
  34. data/docs/js/full_list.js +216 -0
  35. data/docs/js/jquery.js +4 -0
  36. data/docs/method_list.html +171 -0
  37. data/docs/top-level-namespace.html +110 -0
  38. data/lib/workos.rb +36 -0
  39. data/lib/workos/base.rb +18 -0
  40. data/lib/workos/profile.rb +53 -0
  41. data/lib/workos/request_error.rb +5 -0
  42. data/lib/workos/sso.rb +142 -0
  43. data/lib/workos/types.rb +11 -0
  44. data/lib/workos/types/profile_struct.rb +18 -0
  45. data/lib/workos/version.rb +7 -0
  46. data/sorbet/config +2 -0
  47. data/sorbet/rbi/gems/addressable.rbi +198 -0
  48. data/sorbet/rbi/gems/ast.rbi +47 -0
  49. data/sorbet/rbi/gems/codecov.rbi +19 -0
  50. data/sorbet/rbi/gems/crack.rbi +47 -0
  51. data/sorbet/rbi/gems/docile.rbi +31 -0
  52. data/sorbet/rbi/gems/hashdiff.rbi +65 -0
  53. data/sorbet/rbi/gems/jaro_winkler.rbi +14 -0
  54. data/sorbet/rbi/gems/parallel.rbi +81 -0
  55. data/sorbet/rbi/gems/parser.rbi +856 -0
  56. data/sorbet/rbi/gems/public_suffix.rbi +102 -0
  57. data/sorbet/rbi/gems/rack.rbi +103 -0
  58. data/sorbet/rbi/gems/rainbow.rbi +117 -0
  59. data/sorbet/rbi/gems/rake.rbi +632 -0
  60. data/sorbet/rbi/gems/rspec-core.rbi +1661 -0
  61. data/sorbet/rbi/gems/rspec-expectations.rbi +388 -0
  62. data/sorbet/rbi/gems/rspec-mocks.rbi +823 -0
  63. data/sorbet/rbi/gems/rspec-support.rbi +266 -0
  64. data/sorbet/rbi/gems/rspec.rbi +14 -0
  65. data/sorbet/rbi/gems/rubocop.rbi +7083 -0
  66. data/sorbet/rbi/gems/ruby-progressbar.rbi +304 -0
  67. data/sorbet/rbi/gems/simplecov-html.rbi +30 -0
  68. data/sorbet/rbi/gems/simplecov.rbi +225 -0
  69. data/sorbet/rbi/gems/unicode-display_width.rbi +16 -0
  70. data/sorbet/rbi/gems/webmock.rbi +526 -0
  71. data/sorbet/rbi/hidden-definitions/errors.txt +6061 -0
  72. data/sorbet/rbi/hidden-definitions/hidden.rbi +10087 -0
  73. data/sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi +8684 -0
  74. data/sorbet/rbi/sorbet-typed/lib/rainbow/all/rainbow.rbi +254 -0
  75. data/sorbet/rbi/sorbet-typed/lib/ruby/all/gem.rbi +4222 -0
  76. data/sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi +111 -0
  77. data/sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi +543 -0
  78. data/sorbet/rbi/todo.rbi +7 -0
  79. data/spec/lib/workos/sso_spec.rb +95 -0
  80. data/spec/spec_helper.rb +32 -0
  81. data/spec/support/profile.txt +1 -0
  82. data/workos.gemspec +32 -0
  83. metadata +261 -0
data/lib/workos.rb ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+
5
+ require 'workos/version'
6
+ require 'sorbet-runtime'
7
+
8
+ # Use the WorkOS module to authenticate your
9
+ # requests to the WorkOS API. The gem will read
10
+ # your API key automatically from the ENV var `WORKOS_KEY`.
11
+ # Alternatively, you can set the key yourself with
12
+ # `WorkOS.key = [your api key]` somewhere in the load path of
13
+ # your application, such as an initializer.
14
+ module WorkOS
15
+ API_HOSTNAME = 'api.workos.com'
16
+
17
+ def self.key=(value)
18
+ Base.key = value
19
+ end
20
+
21
+ def self.key
22
+ Base.key
23
+ end
24
+
25
+ def self.key!
26
+ key || raise('WorkOS.key not set')
27
+ end
28
+
29
+ autoload :Types, 'workos/types'
30
+ autoload :Base, 'workos/base'
31
+ autoload :Profile, 'workos/profile'
32
+ autoload :RequestError, 'workos/request_error'
33
+ autoload :SSO, 'workos/sso'
34
+
35
+ WorkOS.key = ENV['WORKOS_KEY'] unless ENV['WORKOS_KEY'].nil?
36
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+ # rubocop:disable Style/Documentation
4
+
5
+
6
+ module WorkOS
7
+ class Base
8
+ attr_accessor :key
9
+ class << self
10
+ attr_writer :key
11
+ end
12
+
13
+ class << self
14
+ attr_reader :key
15
+ end
16
+ end
17
+ end
18
+ # rubocop:enable Style/Documentation
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+
5
+ require 'json'
6
+
7
+ module WorkOS
8
+ # The Profile class provides a lighweight wrapper around
9
+ # a normalized response from the various IDPs WorkOS
10
+ # supports as part of the SSO integration. This class
11
+ # is not meant ot be instantiated in user space, and
12
+ # is instantiated internally but exposed.
13
+ class Profile
14
+ extend T::Sig
15
+
16
+ sig { returns(String) }
17
+ attr_accessor :id, :email, :first_name, :last_name,
18
+ :connection_type, :idp_id
19
+
20
+ sig { params(profile_json: String).void }
21
+ def initialize(profile_json)
22
+ raw = parse_json(profile_json)
23
+
24
+ @id = T.let(raw.id, String)
25
+ @email = T.let(raw.email, String)
26
+ @first_name = T.let(raw.first_name, String)
27
+ @last_name = T.let(raw.last_name, String)
28
+ @connection_type = T.let(raw.connection_type, String)
29
+ @idp_id = T.let(raw.idp_id, String)
30
+ end
31
+
32
+ sig { returns(String) }
33
+ def full_name
34
+ [first_name, last_name].compact.join(' ')
35
+ end
36
+
37
+ private
38
+
39
+ sig { params(json_string: String).returns(WorkOS::Types::ProfileStruct) }
40
+ def parse_json(json_string)
41
+ hash = JSON.parse(json_string, symbolize_names: true)
42
+
43
+ WorkOS::Types::ProfileStruct.new(
44
+ id: hash[:profile][:id],
45
+ email: hash[:profile][:email],
46
+ first_name: hash[:profile][:first_name],
47
+ last_name: hash[:profile][:last_name],
48
+ connection_type: hash[:profile][:connection_type],
49
+ idp_id: hash[:profile][:idp_id],
50
+ )
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ module WorkOS
3
+ # Raised when an API request is unsuccessful
4
+ class RequestError < StandardError; end
5
+ end
data/lib/workos/sso.rb ADDED
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+
5
+ require 'net/http'
6
+ require 'rack/utils'
7
+ require 'uri'
8
+
9
+ module WorkOS
10
+ # The SSO module provides convenience methods for working with the WorkOS
11
+ # SSO service. You'll need a valid API key, a project ID, and to have
12
+ # created an SSO connection on your WorkOS dashboard.
13
+ #
14
+ # @see https://dashboard.workos.com/docs/sso/what-is-sso
15
+ module SSO
16
+ class << self
17
+ extend T::Sig
18
+
19
+ sig do
20
+ params(
21
+ domain: String,
22
+ project_id: String,
23
+ redirect_uri: String,
24
+ state: Hash,
25
+ ).returns(String)
26
+ end
27
+
28
+ # Generate an Oauth2 authorization URL where your users will
29
+ # authenticate using the configured SSO Identity Provider.
30
+ #
31
+ # @param [String] domain The domain for the relevant SSO Connection
32
+ # configured on your WorkOS dashboard
33
+ # @param [String] project_id The WorkOS project ID for the project
34
+ # where you've configured your SSO connection
35
+ # @param [String] redirect_uri The URI where users are directed
36
+ # after completing the authentication step. Must match a
37
+ # configured redirect URI on your WorkOS dashboard
38
+ # @param [Hash] state An aribtrary state object
39
+ # that is preserved and available to the client in the response.
40
+ # @example
41
+ # WorkOS::SSO.authorization_url(
42
+ # domain: 'acme.com',
43
+ # project_id: 'project_01DG5TGK363GRVXP3ZS40WNGEZ',
44
+ # redirect_uri: 'https://workos.com/callback',
45
+ # state: {
46
+ # next_page: '/docs'
47
+ # }
48
+ # )
49
+ #
50
+ # => "https://api.workos.com/sso/authorize?domain=acme.com" \
51
+ # "&client_id=project_01DG5TGK363GRVXP3ZS40WNGEZ" \
52
+ # "&redirect_uri=https%3A%2F%2Fworkos.com%2Fcallback&" \
53
+ # "response_type=code&state=%7B%3Anext_page%3D%3E%22%2Fdocs%22%7D"
54
+ #
55
+ # @return [String]
56
+ def authorization_url(domain:, project_id:, redirect_uri:, state: {})
57
+ query = Rack::Utils.build_query(
58
+ domain: domain,
59
+ client_id: project_id,
60
+ redirect_uri: redirect_uri,
61
+ response_type: 'code',
62
+ state: state,
63
+ )
64
+
65
+ "https://#{WorkOS::API_HOSTNAME}/sso/authorize?#{query}"
66
+ end
67
+
68
+ sig do
69
+ params(
70
+ code: String,
71
+ project_id: String,
72
+ redirect_uri: String,
73
+ ).returns(WorkOS::Profile)
74
+ end
75
+
76
+ # Fetch the profile details for the authenticated SSO user.
77
+ #
78
+ # @param [String] code The authorization code provided in the callback URL
79
+ # @param [String] project_id The WorkOS project ID for the project
80
+ # where you've configured your SSO connection
81
+ # @param [String] redirect_uri The URI where the user was directed
82
+ # after completing the authentication step.
83
+ #
84
+ # @example
85
+ # WorkOS::SSO.profile(
86
+ # code: 'acme.com',
87
+ # project_id: 'project_01DG5TGK363GRVXP3ZS40WNGEZ',
88
+ # redirect_uri: 'https://workos.com/callback',
89
+ # )
90
+ # => #<WorkOS::Profile:0x00007fb6e4193d20
91
+ # @id="prof_01DRA1XNSJDZ19A31F183ECQW5",
92
+ # @email="demo@workos-okta.com",
93
+ # @first_name="WorkOS",
94
+ # @connection_type="OktaSAML",
95
+ # @last_name="Demo",
96
+ # @idp_id="00u1klkowm8EGah2H357",
97
+ # @access_token="01DVX6QBS3EG6FHY2ESAA5Q65X"
98
+ # >
99
+ #
100
+ # @return [WorkOS::Profile]
101
+ def profile(code:, project_id:, redirect_uri:)
102
+ query = Rack::Utils.build_query(
103
+ client_id: project_id,
104
+ client_secret: WorkOS.key!,
105
+ redirect_uri: redirect_uri,
106
+ grant_type: 'authorization_code',
107
+ code: code,
108
+ )
109
+
110
+ response = client.request(Net::HTTP::Post.new("/sso/token?#{query}"))
111
+ check_and_raise_error(response: response)
112
+
113
+ WorkOS::Profile.new(response.body)
114
+ end
115
+
116
+ private
117
+
118
+ sig { returns(Net::HTTP) }
119
+ def client
120
+ return @client if defined?(@client)
121
+
122
+ @client = Net::HTTP.new(WorkOS::API_HOSTNAME, 443)
123
+ @client.use_ssl = true
124
+
125
+ @client
126
+ end
127
+
128
+ sig { params(response: Net::HTTPResponse).void }
129
+ def check_and_raise_error(response:)
130
+ return if response.is_a? Net::HTTPOK
131
+
132
+ begin
133
+ message = JSON.parse(response.body)['message']
134
+ rescue StandardError
135
+ message = 'Something went wrong'
136
+ end
137
+
138
+ raise WorkOS::RequestError, message
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+
5
+ module WorkOS
6
+ # WorkOS believes strongly in typed languages,
7
+ # so we're using Sorbet throughout this Ruby gem.
8
+ module Types
9
+ require_relative 'types/profile_struct'
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+
5
+ module WorkOS
6
+ module Types
7
+ # The ProfileStruct acts as a typed interface
8
+ # for the Profile class
9
+ class ProfileStruct < T::Struct
10
+ const :id, String
11
+ const :email, String
12
+ const :first_name, String
13
+ const :last_name, String
14
+ const :connection_type, String
15
+ const :idp_id, String
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+
5
+ module WorkOS
6
+ VERSION = '0.0.1'
7
+ end
data/sorbet/config ADDED
@@ -0,0 +1,2 @@
1
+ --dir
2
+ .
@@ -0,0 +1,198 @@
1
+ # This file is autogenerated. Do not edit it by hand. Regenerate it with:
2
+ # srb rbi gems
3
+
4
+ # typed: strong
5
+ #
6
+ # If you would like to make changes to this file, great! Please create the gem's shim here:
7
+ #
8
+ # https://github.com/sorbet/sorbet-typed/new/master?filename=lib/addressable/all/addressable.rbi
9
+ #
10
+ # addressable-2.7.0
11
+ module Addressable
12
+ end
13
+ module Addressable::VERSION
14
+ end
15
+ module Addressable::IDNA
16
+ def self.lookup_unicode_combining_class(codepoint); end
17
+ def self.lookup_unicode_compatibility(codepoint); end
18
+ def self.lookup_unicode_composition(unpacked); end
19
+ def self.lookup_unicode_lowercase(codepoint); end
20
+ def self.punycode_adapt(delta, numpoints, firsttime); end
21
+ def self.punycode_basic?(codepoint); end
22
+ def self.punycode_decode(punycode); end
23
+ def self.punycode_decode_digit(codepoint); end
24
+ def self.punycode_delimiter?(codepoint); end
25
+ def self.punycode_encode(unicode); end
26
+ def self.punycode_encode_digit(d); end
27
+ def self.to_ascii(input); end
28
+ def self.to_unicode(input); end
29
+ def self.unicode_compose(unpacked); end
30
+ def self.unicode_compose_pair(ch_one, ch_two); end
31
+ def self.unicode_decompose(unpacked); end
32
+ def self.unicode_decompose_hangul(codepoint); end
33
+ def self.unicode_downcase(input); end
34
+ def self.unicode_normalize_kc(input); end
35
+ def self.unicode_sort_canonical(unpacked); end
36
+ end
37
+ class Addressable::IDNA::PunycodeBadInput < StandardError
38
+ end
39
+ class Addressable::IDNA::PunycodeBigOutput < StandardError
40
+ end
41
+ class Addressable::IDNA::PunycodeOverflow < StandardError
42
+ end
43
+ class Addressable::URI
44
+ def +(uri); end
45
+ def ==(uri); end
46
+ def ===(uri); end
47
+ def absolute?; end
48
+ def authority; end
49
+ def authority=(new_authority); end
50
+ def basename; end
51
+ def default_port; end
52
+ def defer_validation; end
53
+ def display_uri; end
54
+ def domain; end
55
+ def dup; end
56
+ def empty?; end
57
+ def eql?(uri); end
58
+ def extname; end
59
+ def fragment; end
60
+ def fragment=(new_fragment); end
61
+ def freeze; end
62
+ def hash; end
63
+ def host; end
64
+ def host=(new_host); end
65
+ def hostname; end
66
+ def hostname=(new_hostname); end
67
+ def inferred_port; end
68
+ def initialize(options = nil); end
69
+ def inspect; end
70
+ def ip_based?; end
71
+ def join!(uri); end
72
+ def join(uri); end
73
+ def merge!(uri); end
74
+ def merge(hash); end
75
+ def normalize!; end
76
+ def normalize; end
77
+ def normalized_authority; end
78
+ def normalized_fragment; end
79
+ def normalized_host; end
80
+ def normalized_password; end
81
+ def normalized_path; end
82
+ def normalized_port; end
83
+ def normalized_query(*flags); end
84
+ def normalized_scheme; end
85
+ def normalized_site; end
86
+ def normalized_user; end
87
+ def normalized_userinfo; end
88
+ def omit!(*components); end
89
+ def omit(*components); end
90
+ def origin; end
91
+ def origin=(new_origin); end
92
+ def password; end
93
+ def password=(new_password); end
94
+ def path; end
95
+ def path=(new_path); end
96
+ def port; end
97
+ def port=(new_port); end
98
+ def query; end
99
+ def query=(new_query); end
100
+ def query_values(return_type = nil); end
101
+ def query_values=(new_query_values); end
102
+ def relative?; end
103
+ def remove_composite_values; end
104
+ def replace_self(uri); end
105
+ def request_uri; end
106
+ def request_uri=(new_request_uri); end
107
+ def route_from(uri); end
108
+ def route_to(uri); end
109
+ def scheme; end
110
+ def scheme=(new_scheme); end
111
+ def self.convert_path(path); end
112
+ def self.encode(uri, return_type = nil); end
113
+ def self.encode_component(component, character_class = nil, upcase_encoded = nil); end
114
+ def self.escape(uri, return_type = nil); end
115
+ def self.form_encode(form_values, sort = nil); end
116
+ def self.form_unencode(encoded_value); end
117
+ def self.heuristic_parse(uri, hints = nil); end
118
+ def self.ip_based_schemes; end
119
+ def self.join(*uris); end
120
+ def self.normalize_component(component, character_class = nil, leave_encoded = nil); end
121
+ def self.normalize_path(path); end
122
+ def self.normalized_encode(uri, return_type = nil); end
123
+ def self.parse(uri); end
124
+ def self.port_mapping; end
125
+ def self.unencode(uri, return_type = nil, leave_encoded = nil); end
126
+ def self.unencode_component(uri, return_type = nil, leave_encoded = nil); end
127
+ def self.unescape(uri, return_type = nil, leave_encoded = nil); end
128
+ def self.unescape_component(uri, return_type = nil, leave_encoded = nil); end
129
+ def site; end
130
+ def site=(new_site); end
131
+ def split_path(path); end
132
+ def tld; end
133
+ def tld=(new_tld); end
134
+ def to_hash; end
135
+ def to_s; end
136
+ def to_str; end
137
+ def user; end
138
+ def user=(new_user); end
139
+ def userinfo; end
140
+ def userinfo=(new_userinfo); end
141
+ def validate; end
142
+ end
143
+ class Addressable::URI::InvalidURIError < StandardError
144
+ end
145
+ module Addressable::URI::CharacterClasses
146
+ end
147
+ class Addressable::Template
148
+ def ==(template); end
149
+ def eql?(template); end
150
+ def expand(mapping, processor = nil, normalize_values = nil); end
151
+ def extract(uri, processor = nil); end
152
+ def freeze; end
153
+ def generate(params = nil, recall = nil, options = nil); end
154
+ def initialize(pattern); end
155
+ def inspect; end
156
+ def join_values(operator, return_value); end
157
+ def keys; end
158
+ def match(uri, processor = nil); end
159
+ def named_captures; end
160
+ def names; end
161
+ def normalize_keys(mapping); end
162
+ def normalize_value(value); end
163
+ def ordered_variable_defaults; end
164
+ def parse_template_pattern(pattern, processor = nil); end
165
+ def partial_expand(mapping, processor = nil, normalize_values = nil); end
166
+ def pattern; end
167
+ def source; end
168
+ def to_regexp; end
169
+ def transform_capture(mapping, capture, processor = nil, normalize_values = nil); end
170
+ def transform_partial_capture(mapping, capture, processor = nil, normalize_values = nil); end
171
+ def variable_defaults; end
172
+ def variables; end
173
+ end
174
+ class Addressable::Template::InvalidTemplateValueError < StandardError
175
+ end
176
+ class Addressable::Template::InvalidTemplateOperatorError < StandardError
177
+ end
178
+ class Addressable::Template::TemplateOperatorAbortedError < StandardError
179
+ end
180
+ class Addressable::Template::MatchData
181
+ def [](key, len = nil); end
182
+ def captures; end
183
+ def initialize(uri, template, mapping); end
184
+ def inspect; end
185
+ def keys; end
186
+ def mapping; end
187
+ def names; end
188
+ def post_match; end
189
+ def pre_match; end
190
+ def string; end
191
+ def template; end
192
+ def to_a; end
193
+ def to_s; end
194
+ def uri; end
195
+ def values; end
196
+ def values_at(*indexes); end
197
+ def variables; end
198
+ end