auth0 5.9.0 → 5.11.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 +4 -4
- data/.circleci/config.yml +3 -3
- data/.devcontainer/Dockerfile +19 -0
- data/.devcontainer/devcontainer.json +37 -0
- data/CHANGELOG.md +22 -0
- data/DEVELOPMENT.md +35 -0
- data/EXAMPLES.md +220 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +59 -63
- data/README.md +68 -253
- data/auth0.gemspec +2 -4
- data/examples/ruby-api/Gemfile +3 -2
- data/examples/ruby-api/Gemfile.lock +33 -0
- data/examples/ruby-api/README.md +2 -2
- data/examples/ruby-on-rails-api/README.md +0 -2
- data/lib/auth0/api/authentication_endpoints.rb +70 -13
- data/lib/auth0/api/v2/clients.rb +42 -0
- data/lib/auth0/api/v2/jobs.rb +15 -4
- data/lib/auth0/api/v2/organizations.rb +1 -1
- data/lib/auth0/client_assertion.rb +45 -0
- data/lib/auth0/mixins/httpproxy.rb +11 -12
- data/lib/auth0/mixins/initializer.rb +2 -0
- data/lib/auth0/mixins/token_management.rb +2 -2
- data/lib/auth0/version.rb +1 -1
- data/opslevel.yml +5 -0
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_patch_client/should_update_the_client_with_the_correct_attributes.yml +2 -1
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_update_connection/should_update_the_connection.yml +1 -1
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_update_rule/should_update_the_disabled_rule_to_be_enabled.yml +1 -1
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_update_tenant_settings/should_revert_the_tenant_name.yml +1 -1
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_update_tenant_settings/should_update_the_tenant_settings_with_a_new_tenant_name.yml +1 -1
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_add_user_roles/should_add_a_Role_to_a_User_successfully.yml +1 -1
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_patch_user/should_patch_the_User_successfully.yml +1 -1
- data/spec/lib/auth0/api/authentication_endpoints_spec.rb +632 -0
- data/spec/lib/auth0/api/v2/clients_spec.rb +51 -0
- data/spec/lib/auth0/api/v2/jobs_spec.rb +18 -0
- data/spec/lib/auth0/mixins/httpproxy_spec.rb +53 -17
- data/spec/lib/auth0/mixins/initializer_spec.rb +79 -25
- data/spec/lib/auth0/mixins/token_management_spec.rb +47 -37
- data/spec/spec_helper.rb +4 -1
- data/spec/support/dummy_class_for_tokens.rb +2 -0
- metadata +15 -35
data/lib/auth0/api/v2/clients.rb
CHANGED
@@ -73,12 +73,54 @@ module Auth0
|
|
73
73
|
patch(path, options)
|
74
74
|
end
|
75
75
|
|
76
|
+
# Creates credentials for a client
|
77
|
+
# @param client_id [string] The Id of the client to update
|
78
|
+
# @param options [hash] The payload to send to the endpoint
|
79
|
+
def create_client_credentials(client_id, options)
|
80
|
+
raise Auth0::MissingClientId, 'Must specify a client id' if client_id.to_s.empty?
|
81
|
+
raise Auth0::MissingParameter, 'Must specify a valid body' if options.to_s.empty?
|
82
|
+
post(client_credentials_path(client_id), options)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Gets the credentials for a client
|
86
|
+
# @param client_id [string] The Id of the client
|
87
|
+
# @return [hash] The client credentials
|
88
|
+
def client_credentials(client_id)
|
89
|
+
raise Auth0::MissingClientId, 'Must specify a client id' if client_id.to_s.empty?
|
90
|
+
get(client_credentials_path(client_id))
|
91
|
+
end
|
92
|
+
alias get_client_credentials client_credentials
|
93
|
+
|
94
|
+
# Gets a client credential by ID
|
95
|
+
# @param client_id [string] The Id of the client
|
96
|
+
# @param credential_id [string] The Id of the credential to retrieve
|
97
|
+
# @return [hash] The credential
|
98
|
+
def client_credential(client_id, credential_id)
|
99
|
+
raise Auth0::MissingClientId, 'Must specify a client id' if client_id.to_s.empty?
|
100
|
+
raise Auth0::MissingParameter, 'Must specify a credential id' if credential_id.to_s.empty?
|
101
|
+
get("#{client_credentials_path(client_id)}/#{credential_id}")
|
102
|
+
end
|
103
|
+
alias get_client_credential client_credential
|
104
|
+
|
105
|
+
# Deletes a credential from the specified client
|
106
|
+
# @param client_id [string] The Id of the client
|
107
|
+
# @param credential_id [string] The Id of the credential to delete
|
108
|
+
def delete_client_credential(client_id, credential_id)
|
109
|
+
raise Auth0::MissingClientId, 'Must specify a client id' if client_id.to_s.empty?
|
110
|
+
raise Auth0::MissingParameter, 'Must specify a credential id' if credential_id.to_s.empty?
|
111
|
+
delete("#{client_credentials_path(client_id)}/#{credential_id}")
|
112
|
+
end
|
113
|
+
|
76
114
|
private
|
77
115
|
|
78
116
|
# Clients API path
|
79
117
|
def clients_path
|
80
118
|
@clients_path ||= '/api/v2/clients'
|
81
119
|
end
|
120
|
+
|
121
|
+
def client_credentials_path(client_id)
|
122
|
+
"#{clients_path}/#{client_id}/credentials"
|
123
|
+
end
|
82
124
|
end
|
83
125
|
end
|
84
126
|
end
|
data/lib/auth0/api/v2/jobs.rb
CHANGED
@@ -60,6 +60,9 @@ module Auth0
|
|
60
60
|
# :format [string] The format of the file. Valid values are: "json" and "csv".
|
61
61
|
# :limit [integer] Limit the number of users to export.
|
62
62
|
# :fields [array] A list of fields to be included in the CSV.
|
63
|
+
# This can either be an array of strings representing field names, or an object.
|
64
|
+
# If it's a string, it is mapped to the correct { name: '<field name>' } object required by the endpoint.
|
65
|
+
# If it's an object, it is passed through as-is to the endpoint.
|
63
66
|
# If omitted, a set of predefined fields will be exported.
|
64
67
|
#
|
65
68
|
# @return [json] Returns the job status and properties.
|
@@ -109,14 +112,22 @@ module Auth0
|
|
109
112
|
@jobs_path ||= '/api/v2/jobs'
|
110
113
|
end
|
111
114
|
|
112
|
-
# Map array of
|
113
|
-
# @param fields [array]
|
114
|
-
|
115
|
+
# Map array of fields for export to array of objects
|
116
|
+
# @param fields [array] Fields to be included in the export
|
117
|
+
# This can either be an array of strings representing field names, or an object.
|
118
|
+
# If it's a string, it is mapped to the correct { name: '<field name>' } object required by the endpoint.
|
119
|
+
# If it's an object, it is passed through as-is to the endpoint.
|
115
120
|
# @return [array] Returns the fields mapped as array of objects for the export_users endpoint
|
116
121
|
def fields_for_export(fields)
|
117
122
|
return nil if fields.to_s.empty?
|
118
123
|
|
119
|
-
fields.map { |field|
|
124
|
+
fields.map { |field|
|
125
|
+
if field.is_a? String
|
126
|
+
{ name: field }
|
127
|
+
else
|
128
|
+
field
|
129
|
+
end
|
130
|
+
}
|
120
131
|
end
|
121
132
|
end
|
122
133
|
end
|
@@ -9,7 +9,7 @@ module Auth0
|
|
9
9
|
|
10
10
|
# Get all organizations.
|
11
11
|
# @see https://auth0.com/docs/api/management/v2/#!/Organizations/get_organizations
|
12
|
-
# @param options [hash] The Hash options used to define the paging of
|
12
|
+
# @param options [hash] The Hash options used to define the paging of results
|
13
13
|
# * :per_page [integer] The amount of entries per page. Default: 50. Max value: 100.
|
14
14
|
# * :page [integer] The page number. Zero based.
|
15
15
|
# * :from [string] For checkpoint pagination, the ID from which to start selection from.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'jwt'
|
4
|
+
|
5
|
+
module Auth0
|
6
|
+
module ClientAssertion
|
7
|
+
CLIENT_ASSERTION_TYPE = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'.freeze
|
8
|
+
|
9
|
+
# Adds keys into the supplied hash for either the client secret, or client assertion. If `client_assertion_signing_key` is not nil,
|
10
|
+
# it takes precedence over `client_secret`.
|
11
|
+
# @param [hash] The hash to add the keys to
|
12
|
+
# @param client_id [string] The client ID
|
13
|
+
# @param client_secret [string] The client secret
|
14
|
+
# @param client_assertion_signing_key [PKey] The key used to sign the client assertion JWT
|
15
|
+
# @param client_assertion_signing_alg [string] The algorithm used when signing the client assertion JWT
|
16
|
+
def populate_client_assertion_or_secret(hash,
|
17
|
+
domain: @domain,
|
18
|
+
client_id: @client_id,
|
19
|
+
client_secret: @client_secret,
|
20
|
+
client_assertion_signing_key: @client_assertion_signing_key,
|
21
|
+
client_assertion_signing_alg: @client_assertion_signing_alg)
|
22
|
+
|
23
|
+
if !client_assertion_signing_key.nil?
|
24
|
+
# Create JWT
|
25
|
+
now = Time.now.to_i
|
26
|
+
|
27
|
+
payload = {
|
28
|
+
iss: client_id,
|
29
|
+
sub: client_id,
|
30
|
+
aud: "https://#{domain}/",
|
31
|
+
iat: now,
|
32
|
+
exp: now + 180,
|
33
|
+
jti: SecureRandom.uuid
|
34
|
+
}
|
35
|
+
|
36
|
+
jwt = JWT.encode payload, client_assertion_signing_key, client_assertion_signing_alg
|
37
|
+
|
38
|
+
hash[:client_assertion] = jwt
|
39
|
+
hash[:client_assertion_type] = Auth0::ClientAssertion::CLIENT_ASSERTION_TYPE
|
40
|
+
else
|
41
|
+
hash[:client_secret] = client_secret
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -8,11 +8,12 @@ module Auth0
|
|
8
8
|
# for now, if you want to feel free to use your own http client
|
9
9
|
module HTTPProxy
|
10
10
|
attr_accessor :headers, :base_uri, :timeout, :retry_count
|
11
|
-
|
11
|
+
DEFAULT_RETRIES = 3
|
12
12
|
MAX_ALLOWED_RETRIES = 10
|
13
13
|
MAX_REQUEST_RETRY_JITTER = 250
|
14
14
|
MAX_REQUEST_RETRY_DELAY = 1000
|
15
|
-
MIN_REQUEST_RETRY_DELAY =
|
15
|
+
MIN_REQUEST_RETRY_DELAY = 250
|
16
|
+
BASE_DELAY = 100
|
16
17
|
|
17
18
|
# proxying requests from instance methods to HTTP class methods
|
18
19
|
%i(get post post_file put patch delete delete_with_body).each do |method|
|
@@ -26,14 +27,14 @@ module Auth0
|
|
26
27
|
|
27
28
|
def retry_options
|
28
29
|
sleep_timer = lambda do |attempt|
|
29
|
-
wait =
|
30
|
-
wait += rand(wait..wait+MAX_REQUEST_RETRY_JITTER) # Add jitter to the delay window.
|
30
|
+
wait = BASE_DELAY * (2**attempt-1) # Exponential delay with each subsequent request attempt.
|
31
|
+
wait += rand(wait+1..wait+MAX_REQUEST_RETRY_JITTER) # Add jitter to the delay window.
|
31
32
|
wait = [MAX_REQUEST_RETRY_DELAY, wait].min # Cap delay at MAX_REQUEST_RETRY_DELAY.
|
32
33
|
wait = [MIN_REQUEST_RETRY_DELAY, wait].max # Ensure delay is no less than MIN_REQUEST_RETRY_DELAY.
|
33
34
|
wait / 1000.to_f.round(2) # convert ms to seconds
|
34
35
|
end
|
35
36
|
|
36
|
-
tries = 1 + [Integer(retry_count ||
|
37
|
+
tries = 1 + [Integer(retry_count || DEFAULT_RETRIES), MAX_ALLOWED_RETRIES].min # Cap retries at MAX_ALLOWED_RETRIES
|
37
38
|
|
38
39
|
{
|
39
40
|
tries: tries,
|
@@ -72,15 +73,13 @@ module Auth0
|
|
72
73
|
|
73
74
|
def request(method, uri, body = {}, extra_headers = {})
|
74
75
|
result = if method == :get
|
75
|
-
|
76
|
-
|
77
|
-
# Merge custom headers into existing ones for this req.
|
78
|
-
# This prevents future calls from using them.
|
79
|
-
get_headers = headers.merge extra_headers
|
80
|
-
# Make the call with extra_headers, if provided.
|
76
|
+
@headers ||= {}
|
77
|
+
get_headers = @headers.merge({params: body}).merge(extra_headers)
|
81
78
|
call(:get, encode_uri(uri), timeout, get_headers)
|
82
79
|
elsif method == :delete
|
83
|
-
|
80
|
+
@headers ||= {}
|
81
|
+
delete_headers = @headers.merge({ params: body })
|
82
|
+
call(:delete, encode_uri(uri), timeout, delete_headers)
|
84
83
|
elsif method == :delete_with_body
|
85
84
|
call(:delete, encode_uri(uri), timeout, headers, body.to_json)
|
86
85
|
elsif method == :post_file
|
@@ -16,6 +16,8 @@ module Auth0
|
|
16
16
|
@headers = client_headers
|
17
17
|
@timeout = options[:timeout] || 10
|
18
18
|
@retry_count = options[:retry_count]
|
19
|
+
@client_assertion_signing_key = options[:client_assertion_signing_key]
|
20
|
+
@client_assertion_signing_alg = options[:client_assertion_signing_alg] || 'RS256';
|
19
21
|
extend Auth0::Api::AuthenticationEndpoints
|
20
22
|
@client_id = options[:client_id]
|
21
23
|
@client_secret = options[:client_secret]
|
@@ -6,7 +6,6 @@ module Auth0
|
|
6
6
|
|
7
7
|
def initialize_token(options)
|
8
8
|
@token = options[:access_token] || options[:token]
|
9
|
-
|
10
9
|
# default expiry to an hour if a token was given but no expires_at
|
11
10
|
@token_expires_at = @token ? options[:token_expires_at] || Time.now.to_i + 3600 : nil
|
12
11
|
|
@@ -15,9 +14,10 @@ module Auth0
|
|
15
14
|
end
|
16
15
|
|
17
16
|
def get_token
|
17
|
+
# pp @token_expires_at
|
18
18
|
has_expired = @token && @token_expires_at ? @token_expires_at < (Time.now.to_i + 10) : false
|
19
19
|
|
20
|
-
if (@token.nil? || has_expired) && @client_id && @client_secret
|
20
|
+
if (@token.nil? || has_expired) && @client_id && (@client_secret || @client_assertion_signing_key)
|
21
21
|
response = api_token(audience: @audience)
|
22
22
|
@token = response.token
|
23
23
|
@token_expires_at = response.expires_in ? Time.now.to_i + response.expires_in : nil
|
data/lib/auth0/version.rb
CHANGED
data/opslevel.yml
ADDED
@@ -2,7 +2,7 @@
|
|
2
2
|
http_interactions:
|
3
3
|
- request:
|
4
4
|
method: patch
|
5
|
-
uri: https://auth0-sdk-tests.auth0.com/api/v2/clients/SftKo9ySyHnMPezQUFd0C70GBoNFM21F
|
5
|
+
uri: https://auth0-sdk-tests.auth0.com/api/v2/clients/SftKo9ySyHnMPezQUFd0C70GBoNFM21F
|
6
6
|
body:
|
7
7
|
encoding: UTF-8
|
8
8
|
string: '{"custom_login_page_on":false,"sso":true}'
|
@@ -12,6 +12,7 @@ http_interactions:
|
|
12
12
|
User-Agent:
|
13
13
|
- rest-client/2.1.0 (darwin19.6.0 x86_64) ruby/2.7.0p0
|
14
14
|
Content-Type:
|
15
|
+
|
15
16
|
- application/json
|
16
17
|
Auth0-Client:
|
17
18
|
- eyJuYW1lIjoicnVieS1hdXRoMCIsInZlcnNpb24iOiI1LjUuMCIsImVudiI6eyJydWJ5IjoiMi43LjAifX0=
|
@@ -2,7 +2,7 @@
|
|
2
2
|
http_interactions:
|
3
3
|
- request:
|
4
4
|
method: patch
|
5
|
-
uri: https://auth0-sdk-tests.auth0.com/api/v2/connections/con_WltM0fv20JCnxOuY
|
5
|
+
uri: https://auth0-sdk-tests.auth0.com/api/v2/connections/con_WltM0fv20JCnxOuY
|
6
6
|
body:
|
7
7
|
encoding: UTF-8
|
8
8
|
string: '{"options":{"mfa":{"active":true,"return_enroll_settings":true},"passwordPolicy":"excellent","strategy_version":2,"brute_force_protection":true}}'
|
@@ -2,7 +2,7 @@
|
|
2
2
|
http_interactions:
|
3
3
|
- request:
|
4
4
|
method: patch
|
5
|
-
uri: https://auth0-sdk-tests.auth0.com/api/v2/rules/rul_bsg64xEPZz4WOkXz
|
5
|
+
uri: https://auth0-sdk-tests.auth0.com/api/v2/rules/rul_bsg64xEPZz4WOkXz
|
6
6
|
body:
|
7
7
|
encoding: UTF-8
|
8
8
|
string: '{"enabled":true}'
|
@@ -2,7 +2,7 @@
|
|
2
2
|
http_interactions:
|
3
3
|
- request:
|
4
4
|
method: patch
|
5
|
-
uri: https://auth0-sdk-tests.auth0.com/api/v2/tenants/settings
|
5
|
+
uri: https://auth0-sdk-tests.auth0.com/api/v2/tenants/settings
|
6
6
|
body:
|
7
7
|
encoding: UTF-8
|
8
8
|
string: '{"friendly_name":"Auth0"}'
|
@@ -2,7 +2,7 @@
|
|
2
2
|
http_interactions:
|
3
3
|
- request:
|
4
4
|
method: patch
|
5
|
-
uri: https://auth0-sdk-tests.auth0.com/api/v2/tenants/settings
|
5
|
+
uri: https://auth0-sdk-tests.auth0.com/api/v2/tenants/settings
|
6
6
|
body:
|
7
7
|
encoding: UTF-8
|
8
8
|
string: '{"friendly_name":"Auth0-CHANGED"}'
|
@@ -2,7 +2,7 @@
|
|
2
2
|
http_interactions:
|
3
3
|
- request:
|
4
4
|
method: post
|
5
|
-
uri: https://auth0-sdk-tests.auth0.com/api/v2/users/auth0%7C613282adac819400692c0dd9/roles
|
5
|
+
uri: https://auth0-sdk-tests.auth0.com/api/v2/users/auth0%7C613282adac819400692c0dd9/roles
|
6
6
|
body:
|
7
7
|
encoding: UTF-8
|
8
8
|
string: '{"roles":["rol_2VZOCes8HgBar3Tp"]}'
|
@@ -2,7 +2,7 @@
|
|
2
2
|
http_interactions:
|
3
3
|
- request:
|
4
4
|
method: patch
|
5
|
-
uri: https://auth0-sdk-tests.auth0.com/api/v2/users/auth0%7C613282adac819400692c0dd9
|
5
|
+
uri: https://auth0-sdk-tests.auth0.com/api/v2/users/auth0%7C613282adac819400692c0dd9
|
6
6
|
body:
|
7
7
|
encoding: UTF-8
|
8
8
|
string: '{"email_verified":true,"user_metadata":{"addresses":{"home_address":"742
|