auth0 4.11.0 → 5.20.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/.version +1 -0
- data/CHANGELOG.md +477 -19
- data/README.md +80 -129
- data/auth0.gemspec +10 -13
- data/lib/auth0/algorithm.rb +5 -0
- data/lib/auth0/api/authentication_endpoints.rb +189 -242
- data/lib/auth0/api/v2/actions.rb +209 -0
- data/lib/auth0/api/v2/attack_protection.rb +79 -0
- data/lib/auth0/api/v2/branding.rb +65 -0
- data/lib/auth0/api/v2/client_grants.rb +27 -2
- data/lib/auth0/api/v2/clients.rb +42 -0
- data/lib/auth0/api/v2/connections.rb +14 -5
- data/lib/auth0/api/v2/device_credentials.rb +12 -7
- data/lib/auth0/api/v2/grants.rb +49 -0
- data/lib/auth0/api/v2/jobs.rb +28 -5
- data/lib/auth0/api/v2/log_streams.rb +78 -0
- data/lib/auth0/api/v2/logs.rb +2 -2
- data/lib/auth0/api/v2/organizations.rb +407 -0
- data/lib/auth0/api/v2/prompts.rb +70 -0
- data/lib/auth0/api/v2/refresh_tokens.rb +34 -0
- data/lib/auth0/api/v2/roles.rb +7 -3
- data/lib/auth0/api/v2/sessions.rb +43 -0
- data/lib/auth0/api/v2/tickets.rb +25 -2
- data/lib/auth0/api/v2/users.rb +216 -14
- data/lib/auth0/api/v2.rb +21 -3
- data/lib/auth0/client_assertion.rb +45 -0
- data/lib/auth0/exception.rb +19 -8
- data/lib/auth0/mixins/access_token_struct.rb +2 -2
- data/lib/auth0/mixins/api_token_struct.rb +2 -3
- data/lib/auth0/mixins/httpproxy.rb +99 -35
- data/lib/auth0/mixins/initializer.rb +6 -9
- data/lib/auth0/mixins/permission_struct.rb +2 -2
- data/lib/auth0/mixins/token_management.rb +35 -0
- data/lib/auth0/mixins/validation.rb +335 -1
- data/lib/auth0/mixins.rb +2 -1
- data/lib/auth0/version.rb +1 -1
- data/lib/auth0.rb +1 -0
- metadata +71 -608
- data/.bundle/config +0 -4
- data/.circleci/config.yml +0 -23
- data/.env.example +0 -2
- data/.gemrelease +0 -2
- data/.github/CODEOWNERS +0 -1
- data/.github/ISSUE_TEMPLATE.md +0 -39
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -35
- data/.github/stale.yml +0 -20
- data/.gitignore +0 -14
- data/.rspec +0 -3
- data/.rubocop.yml +0 -10
- data/.rubocop_todo.yml +0 -5
- data/CODE_OF_CONDUCT.md +0 -3
- data/DEPLOYMENT.md +0 -61
- data/Dockerfile +0 -5
- data/Gemfile +0 -19
- data/Gemfile.lock +0 -224
- data/Guardfile +0 -37
- data/RUBYGEM.md +0 -9
- data/Rakefile +0 -53
- data/codecov.yml +0 -22
- data/deploy_documentation.sh +0 -29
- data/doc_config/templates/default/fulldoc/html/css/full_list.css +0 -79
- data/doc_config/templates/default/fulldoc/html/css/style.css +0 -546
- data/doc_config/templates/default/layout/html/breadcrumb.erb +0 -11
- data/doc_config/templates/default/layout/html/footer.erb +0 -115
- data/doc_config/templates/default/layout/html/headers.erb +0 -17
- data/doc_config/templates/default/layout/html/layout.erb +0 -27
- data/examples/ruby-api/.env.example +0 -2
- data/examples/ruby-api/.gitignore +0 -86
- data/examples/ruby-api/Gemfile +0 -8
- data/examples/ruby-api/README.md +0 -24
- data/examples/ruby-api/config.ru +0 -2
- data/examples/ruby-api/main.rb +0 -33
- data/examples/ruby-on-rails-api/.env.example +0 -2
- data/examples/ruby-on-rails-api/.gitignore +0 -18
- data/examples/ruby-on-rails-api/Gemfile +0 -48
- data/examples/ruby-on-rails-api/README.md +0 -27
- data/examples/ruby-on-rails-api/Rakefile +0 -6
- data/examples/ruby-on-rails-api/app/assets/images/.keep +0 -0
- data/examples/ruby-on-rails-api/app/assets/javascripts/application.js +0 -16
- data/examples/ruby-on-rails-api/app/assets/stylesheets/application.css +0 -15
- data/examples/ruby-on-rails-api/app/controllers/application_controller.rb +0 -8
- data/examples/ruby-on-rails-api/app/controllers/concerns/.keep +0 -0
- data/examples/ruby-on-rails-api/app/controllers/ping_controller.rb +0 -6
- data/examples/ruby-on-rails-api/app/controllers/secured_ping_controller.rb +0 -11
- data/examples/ruby-on-rails-api/app/helpers/application_helper.rb +0 -3
- data/examples/ruby-on-rails-api/app/mailers/.keep +0 -0
- data/examples/ruby-on-rails-api/app/models/.keep +0 -0
- data/examples/ruby-on-rails-api/app/models/User.rb +0 -5
- data/examples/ruby-on-rails-api/app/models/concerns/.keep +0 -0
- data/examples/ruby-on-rails-api/app/views/layouts/application.html.erb +0 -14
- data/examples/ruby-on-rails-api/bin/bundle +0 -3
- data/examples/ruby-on-rails-api/bin/rails +0 -4
- data/examples/ruby-on-rails-api/bin/rake +0 -4
- data/examples/ruby-on-rails-api/bin/setup +0 -29
- data/examples/ruby-on-rails-api/config/application.rb +0 -23
- data/examples/ruby-on-rails-api/config/boot.rb +0 -4
- data/examples/ruby-on-rails-api/config/database.yml +0 -27
- data/examples/ruby-on-rails-api/config/environment.rb +0 -5
- data/examples/ruby-on-rails-api/config/environments/development.rb +0 -37
- data/examples/ruby-on-rails-api/config/environments/production.rb +0 -83
- data/examples/ruby-on-rails-api/config/environments/test.rb +0 -41
- data/examples/ruby-on-rails-api/config/initializers/backtrace_silencers.rb +0 -7
- data/examples/ruby-on-rails-api/config/initializers/cookies_serializer.rb +0 -3
- data/examples/ruby-on-rails-api/config/initializers/dotenv.rb +0 -4
- data/examples/ruby-on-rails-api/config/initializers/filter_parameter_logging.rb +0 -4
- data/examples/ruby-on-rails-api/config/initializers/inflections.rb +0 -16
- data/examples/ruby-on-rails-api/config/initializers/knock.rb +0 -35
- data/examples/ruby-on-rails-api/config/initializers/mime_types.rb +0 -4
- data/examples/ruby-on-rails-api/config/initializers/session_store.rb +0 -3
- data/examples/ruby-on-rails-api/config/initializers/wrap_parameters.rb +0 -14
- data/examples/ruby-on-rails-api/config/locales/en.yml +0 -23
- data/examples/ruby-on-rails-api/config/routes.rb +0 -58
- data/examples/ruby-on-rails-api/config/secrets.yml +0 -28
- data/examples/ruby-on-rails-api/config.ru +0 -4
- data/examples/ruby-on-rails-api/db/schema.rb +0 -15
- data/examples/ruby-on-rails-api/db/seeds.rb +0 -7
- data/examples/ruby-on-rails-api/lib/assets/.keep +0 -0
- data/examples/ruby-on-rails-api/lib/tasks/.keep +0 -0
- data/examples/ruby-on-rails-api/log/.keep +0 -0
- data/examples/ruby-on-rails-api/public/404.html +0 -67
- data/examples/ruby-on-rails-api/public/422.html +0 -67
- data/examples/ruby-on-rails-api/public/500.html +0 -66
- data/examples/ruby-on-rails-api/public/favicon.ico +0 -0
- data/examples/ruby-on-rails-api/public/robots.txt +0 -5
- data/examples/ruby-on-rails-api/test/controllers/.keep +0 -0
- data/examples/ruby-on-rails-api/test/fixtures/.keep +0 -0
- data/examples/ruby-on-rails-api/test/helpers/.keep +0 -0
- data/examples/ruby-on-rails-api/test/integration/.keep +0 -0
- data/examples/ruby-on-rails-api/test/mailers/.keep +0 -0
- data/examples/ruby-on-rails-api/test/models/.keep +0 -0
- data/examples/ruby-on-rails-api/test/ping_controller_test.rb +0 -8
- data/examples/ruby-on-rails-api/test/secured_ping_controller_test.rb +0 -26
- data/examples/ruby-on-rails-api/test/test_helper.rb +0 -16
- data/lib/auth0/api/v1/clients.rb +0 -48
- data/lib/auth0/api/v1/connections.rb +0 -53
- data/lib/auth0/api/v1/logs.rb +0 -34
- data/lib/auth0/api/v1/rules.rb +0 -45
- data/lib/auth0/api/v1/users.rb +0 -164
- data/lib/auth0/api/v1.rb +0 -19
- data/publish_rubygem.sh +0 -10
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_change_password/should_trigger_a_password_reset.yml +0 -63
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_login_with_resource_owner/should_fail_with_an_incorrect_email.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_login_with_resource_owner/should_fail_with_an_incorrect_password.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_login_with_resource_owner/should_fail_with_an_invalid_audience.yml +0 -55
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_login_with_resource_owner/should_login_successfully_with_a_custom_audience.yml +0 -117
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_login_with_resource_owner/should_login_successfully_with_a_default_scope.yml +0 -119
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_saml_metadata/should_retrieve_SAML_metadata.yml +0 -57
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_userinfo/should_fail_as_not_authorized.yml +0 -55
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_userinfo/should_return_the_userinfo.yml +0 -118
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/_wsfed_metadata/should_retrieve_WSFED_metadata.yml +0 -55
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/create_test_user.yml +0 -58
- data/spec/fixtures/vcr_cassettes/Auth0_Api_AuthenticationEndpoints/delete_test_user.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Anomaly/_check_if_ip_is_blocked/should_return_200_response_code.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Anomaly/_remove_ip_block/should_remove_an_IP_successfully.yml +0 -60
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Blacklists/_add_token_to_blacklist/should_add_a_token_to_the_blacklist.yml +0 -56
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Blacklists/_blacklisted_tokens/should_get_the_added_token_from_the_blacklist.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_client_grants/should_return_at_least_1_result.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_client_grants/should_return_the_first_page_of_one_result.yml +0 -66
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_client_grants/should_return_the_test_client_grant.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_delete_client_grant/should_delete_the_test_client_grant.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/_patch_client_grant/should_update_the_test_client_grant.yml +0 -64
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/create_test_client.yml +0 -118
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/create_test_client_grant.yml +0 -64
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/delete_test_client.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ClientGrants/delete_test_client_grant.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_client/_filters/should_exclude_and_include_fields_properly.yml +0 -91
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_client/_filters/should_include_the_specified_fields.yml +0 -63
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_client/should_get_the_test_client.yml +0 -92
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_exclude_fields_not_specified.yml +0 -60
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_exclude_the_specified_fields.yml +0 -132
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_include_the_specified_fields.yml +0 -63
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/_filters/should_paginate_results.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_clients/should_get_at_least_one_client.yml +0 -132
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_delete_client/should_delete_the_test_client_without_an_error.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/_patch_client/should_update_the_client_with_the_correct_attributes.yml +0 -94
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Clients/create_test_client.yml +0 -118
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connection/_filters/should_exclude_the_fields_indicated.yml +0 -63
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connection/_filters/should_include_the_fields_indicated.yml +0 -61
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connection/should_find_the_correct_connection.yml +0 -63
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/_filters/should_include_previously-created_connection_when_filtered.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/_filters/should_should_exclude_the_fields_indicated_from_filtered_results.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/_filters/should_should_include_the_fields_indicated_from_filtered_results.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/should_include_the_previously_created_connection.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_connections/should_not_be_empty.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_delete_connection/should_delete_the_connection.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_delete_connection_user/should_delete_the_user_created.yml +0 -110
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/_update_connection/should_update_the_connection.yml +0 -66
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/create_test_connection.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Connections/create_test_user.yml +0 -68
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/_delete_device_credential/should_delete_the_test_credential_without_an_error.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/_device_credentials/_filter_by_type/should_exclude_the_test_credential.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/_device_credentials/should_have_at_least_1_entry.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/_device_credentials/should_include_the_test_credential.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/create_test_credential.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/create_test_user.yml +0 -68
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/delete_test_credential.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_DeviceCredentials/delete_test_user.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_configure_provider/should_configure_a_new_email_provider.yml +0 -63
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_delete_provider/should_delete_the_existing_email_provider_without_an_error.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_delete_provider/should_throw_an_error_trying_to_get_the_email_provider.yml +0 -51
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_get_provider/_filters/should_get_the_existing_email_provider_with_specific_fields.yml +0 -60
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_get_provider/_filters/should_get_the_existing_email_provider_without_specific_fields.yml +0 -61
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_get_provider/should_get_the_existing_email_provider.yml +0 -61
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/_update_provider/should_update_the_existing_email_provider.yml +0 -63
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Emails/delete_existing_provider.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_export_users_and_get_job/should_create_an_export_users_job_successfully.yml +0 -61
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_export_users_and_get_job/should_get_the_export_users_job.yml +0 -117
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_import_users_and_get_job/should_create_an_import_users_job_successfully.yml +0 -60
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_import_users_and_get_job/should_get_the_import_users_job.yml +0 -116
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_send_verification_email_and_get_job/should_create_a_new_verification_email_job.yml +0 -119
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_send_verification_email_and_get_job/should_get_the_completed_verification_email.yml +0 -175
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/_send_verification_email_and_get_job/should_reject_an_invalid_client_id.yml +0 -109
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/delete_imported_user.yml +0 -110
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Jobs/search_for_connection_id.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_log/should_match_the_created_log_entry.yml +0 -265
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_log/should_not_be_empty.yml +0 -265
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_exclude_fields_not_specified.yml +0 -61
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_exclude_the_specified_fields.yml +0 -75
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_have_one_log_entry.yml +0 -76
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_filters/should_include_the_specified_fields.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/_logs/_from/should_take_one_log_entry.yml +0 -258
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/create_test_user.yml +0 -68
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/delete_test_disabled_rule.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/delete_test_enabled_rule.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Logs/delete_test_user.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_delete_resource_server/should_delete_the_test_server_without_an_error.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_patch_resource_server/should_update_the_resource_server_with_the_correct_attributes.yml +0 -61
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_resource_server/should_get_the_test_server.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_resource_servers/should_get_the_test_server.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_resource_servers/should_return_at_least_1_result.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/_resource_servers/should_return_the_first_page_of_one_result.yml +0 -64
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/create_test_server.yml +0 -61
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_ResourceServers/delete_test_server.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_add_role_permissions/should_add_a_Permission_to_the_Role_successfully.yml +0 -69
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_add_role_users/should_add_a_User_to_the_Role_successfully.yml +0 -69
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_delete_role/should_delete_the_Role_successfully.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role/should_get_the_Role_successfully.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_permissions/should_get_exactly_1_Permission.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_permissions/should_get_the_added_Permission_from_the_Role_successfully.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_users/should_get_exactly_1_User.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_role_users/should_get_the_added_User_from_the_Role_successfully.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_get_roles/should_get_the_Role_successfully.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_remove_role_permissions/should_remove_a_Permission_from_the_Role_successfully.yml +0 -64
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/_update_role/should_update_the_Role_successfully.yml +0 -69
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/create_test_api.yml +0 -69
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/create_test_role.yml +0 -69
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/create_test_user.yml +0 -69
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/delete_test_api.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Roles/delete_test_user.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_delete_rule/should_delete_the_test_disabled_rule_without_an_error.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_delete_rule/should_delete_the_test_enabled_rule_without_an_error.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/_filters/should_exclude_the_fields_not_specified.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/_filters/should_exclude_the_specified_fields.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/_filters/should_include_the_specified_fields.yml +0 -61
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rule/should_get_a_specific_rule.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_exclude_fields_not_specified.yml +0 -60
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_include_the_specified_fields.yml +0 -61
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_return_at_least_1_disabled_rule.yml +0 -63
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_return_at_least_1_enabled_rule.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/_filters/should_return_paginated_results.yml +0 -128
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_rules/should_return_at_least_1_rule.yml +0 -64
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/_update_rule/should_update_the_disabled_rule_to_be_enabled.yml +0 -64
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/create_test_disabled_rule.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Rules/create_test_enabled_rule.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Stats/_active_users/should_have_at_least_one_active_user.yml +0 -59
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Stats/_daily_stats/should_have_at_least_one_stats_entry_for_the_timeframe.yml +0 -63
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_get_tenant_settings/should_get_the_tenant_settings.yml +0 -95
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_get_tenant_settings_with_specific_fields/should_exclude_a_field_not_requested.yml +0 -61
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_get_tenant_settings_with_specific_fields/should_include_the_field_requested.yml +0 -61
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_update_tenant_settings/should_revert_the_tenant_name.yml +0 -96
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tenants/_update_tenant_settings/should_update_the_tenant_settings_with_a_new_tenant_name.yml +0 -96
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/_post_email_verification/should_create_an_email_verification_ticket.yml +0 -63
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/_post_password_change/should_create_a_password_change_ticket.yml +0 -63
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/create_test_user.yml +0 -68
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Tickets/delete_test_user.yml +0 -54
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_add_user_permissions/should_add_a_Permissions_for_a_User_successfully.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_add_user_roles/should_add_a_Role_to_a_User_successfully.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_delete_user/should_delete_the_User_successfully.yml +0 -60
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_delete_user/should_delete_the_secondary_User_successfully.yml +0 -60
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_delete_user_provider/should_attempt_to_delete_the_MFA_provider_for_the_User.yml +0 -60
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_enrollments/should_get_Enrollments_for_a_User_successfully.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_user_permissions/should_get_exactly_1_Permission_for_a_User_successfully.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_user_permissions/should_get_the_correct_Permission_for_a_User_successfully.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_get_user_roles/should_get_Roles_for_a_User_successfully.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_invalidate_browsers/should_invalidate_MFA_browsers_for_the_User_successfully.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_link_user_account/should_link_two_Users_successfully.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_patch_user/should_patch_the_User_successfully.yml +0 -68
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_remove_user_permissions/should_remove_a_Permission_from_a_User_successfully.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_remove_user_roles/should_remove_a_Role_from_a_User_successfully.yml +0 -62
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_unlink_user_account/should_unlink_two_Users_successfully.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/_filters/should_exclude_fields_not_indicated.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/_filters/should_exclude_the_fields_indicated.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/_filters/should_include_the_fields_indicated.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user/should_retrieve_the_created_user.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_user_logs/should_get_Logs_for_a_User_successfully.yml +0 -69
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/is_expected_to_find_a_user_with_a_v2_search_engine_query.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/is_expected_to_find_a_user_with_a_v3_search_engine_query.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_exclude_the_indicated_fields_when_paginated.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_include_the_indicated_fields_when_paginated.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_not_include_other_fields_when_paginated.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/_filters/should_return_the_correct_number_of_results_when_paginated.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/_users/should_have_at_least_one_user.yml +0 -65
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_secondary_test_user.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_test_api.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_test_role.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/create_test_user.yml +0 -67
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/delete_test_api.yml +0 -60
- data/spec/fixtures/vcr_cassettes/Auth0_Api_V2_Users/delete_test_role.yml +0 -60
- data/spec/integration/lib/auth0/api/api_authentication_spec.rb +0 -120
- data/spec/integration/lib/auth0/api/v2/api_anomaly_spec.rb +0 -17
- data/spec/integration/lib/auth0/api/v2/api_blacklist_spec.rb +0 -27
- data/spec/integration/lib/auth0/api/v2/api_client_grants_spec.rb +0 -75
- data/spec/integration/lib/auth0/api/v2/api_clients_spec.rb +0 -166
- data/spec/integration/lib/auth0/api/v2/api_connections_spec.rb +0 -159
- data/spec/integration/lib/auth0/api/v2/api_device_credentials_spec.rb +0 -128
- data/spec/integration/lib/auth0/api/v2/api_email_spec.rb +0 -117
- data/spec/integration/lib/auth0/api/v2/api_jobs_spec.rb +0 -112
- data/spec/integration/lib/auth0/api/v2/api_logs_spec.rb +0 -91
- data/spec/integration/lib/auth0/api/v2/api_resource_servers_spec.rb +0 -130
- data/spec/integration/lib/auth0/api/v2/api_roles_spec.rb +0 -145
- data/spec/integration/lib/auth0/api/v2/api_rules_spec.rb +0 -177
- data/spec/integration/lib/auth0/api/v2/api_stats_spec.rb +0 -22
- data/spec/integration/lib/auth0/api/v2/api_tenants_spec.rb +0 -59
- data/spec/integration/lib/auth0/api/v2/api_tickets_spec.rb +0 -53
- data/spec/integration/lib/auth0/api/v2/api_user_blocks_spec.rb +0 -73
- data/spec/integration/lib/auth0/api/v2/api_users_spec.rb +0 -300
- data/spec/integration/lib/auth0/auth0_client_spec.rb +0 -90
- data/spec/lib/auth0/api/authentication_endpoints_spec.rb +0 -678
- data/spec/lib/auth0/api/v2/anomaly_spec.rb +0 -26
- data/spec/lib/auth0/api/v2/blacklists_spec.rb +0 -25
- data/spec/lib/auth0/api/v2/client_grants_spec.rb +0 -76
- data/spec/lib/auth0/api/v2/clients_spec.rb +0 -104
- data/spec/lib/auth0/api/v2/connections_spec.rb +0 -140
- data/spec/lib/auth0/api/v2/device_credentials_spec.rb +0 -73
- data/spec/lib/auth0/api/v2/emails_spec.rb +0 -47
- data/spec/lib/auth0/api/v2/guardian_spec.rb +0 -154
- data/spec/lib/auth0/api/v2/jobs_spec.rb +0 -111
- data/spec/lib/auth0/api/v2/logs_spec.rb +0 -48
- data/spec/lib/auth0/api/v2/resource_servers_spec.rb +0 -86
- data/spec/lib/auth0/api/v2/roles_spec.rb +0 -362
- data/spec/lib/auth0/api/v2/rules_spec.rb +0 -95
- data/spec/lib/auth0/api/v2/stats_spec.rb +0 -22
- data/spec/lib/auth0/api/v2/tenants_spec.rb +0 -26
- data/spec/lib/auth0/api/v2/tickets_spec.rb +0 -46
- data/spec/lib/auth0/api/v2/user_blocks_spec.rb +0 -52
- data/spec/lib/auth0/api/v2/users_by_email_spec.rb +0 -21
- data/spec/lib/auth0/api/v2/users_spec.rb +0 -525
- data/spec/lib/auth0/client_spec.rb +0 -153
- data/spec/lib/auth0/mixins/httpproxy_spec.rb +0 -304
- data/spec/lib/auth0/mixins/initializer_spec.rb +0 -30
- data/spec/spec_helper.rb +0 -62
- data/spec/support/credentials.rb +0 -30
- data/spec/support/dummy_class.rb +0 -18
- data/spec/support/dummy_class_for_proxy.rb +0 -5
- data/spec/support/dummy_class_for_restclient.rb +0 -2
- data/spec/support/import_users.json +0 -13
- data/spec/support/stub_response.rb +0 -1
|
@@ -1,44 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'addressable/uri'
|
|
4
|
+
require 'retryable'
|
|
5
|
+
require_relative '../exception'
|
|
6
|
+
|
|
1
7
|
module Auth0
|
|
2
8
|
module Mixins
|
|
3
9
|
# here's the proxy for Rest calls based on rest-client, we're building all request on that gem
|
|
4
10
|
# for now, if you want to feel free to use your own http client
|
|
5
11
|
module HTTPProxy
|
|
6
|
-
attr_accessor :headers, :base_uri, :timeout
|
|
12
|
+
attr_accessor :headers, :base_uri, :timeout, :retry_count
|
|
13
|
+
|
|
14
|
+
DEFAULT_RETRIES = 3
|
|
15
|
+
MAX_ALLOWED_RETRIES = 10
|
|
16
|
+
MAX_REQUEST_RETRY_JITTER = 250
|
|
17
|
+
MAX_REQUEST_RETRY_DELAY = 1000
|
|
18
|
+
MIN_REQUEST_RETRY_DELAY = 250
|
|
19
|
+
BASE_DELAY = 100
|
|
7
20
|
|
|
8
21
|
# proxying requests from instance methods to HTTP class methods
|
|
9
|
-
%i
|
|
10
|
-
define_method(method) do |
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
elsif method == :post_file
|
|
26
|
-
body.merge!(multipart: true)
|
|
27
|
-
call(:post, url(safe_path), timeout, headers, body)
|
|
28
|
-
else
|
|
29
|
-
call(method, url(safe_path), timeout, headers, body.to_json)
|
|
30
|
-
end
|
|
31
|
-
case result.code
|
|
32
|
-
when 200...226 then safe_parse_json(result.body)
|
|
33
|
-
when 400 then raise Auth0::BadRequest.new(result.body, code: result.code, headers: result.headers)
|
|
34
|
-
when 401 then raise Auth0::Unauthorized.new(result.body, code: result.code, headers: result.headers)
|
|
35
|
-
when 403 then raise Auth0::AccessDenied.new(result.body, code: result.code, headers: result.headers)
|
|
36
|
-
when 404 then raise Auth0::NotFound.new(result.body, code: result.code, headers: result.headers)
|
|
37
|
-
when 429 then raise Auth0::RateLimitEncountered.new(result.body, code: result.code, headers: result.headers)
|
|
38
|
-
when 500 then raise Auth0::ServerError.new(result.body, code: result.code, headers: result.headers)
|
|
39
|
-
else raise Auth0::Unsupported.new(result.body, code: result.code, headers: result.headers)
|
|
40
|
-
end
|
|
22
|
+
%i[get post post_file post_form put patch delete delete_with_body].each do |method|
|
|
23
|
+
define_method(method) do |uri, body = {}, extra_headers = {}|
|
|
24
|
+
body = safe_merge_body(body, extra_headers)
|
|
25
|
+
token = get_token
|
|
26
|
+
authorization_header(token) unless token.nil?
|
|
27
|
+
request_with_retry(method, uri, body, extra_headers)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def retry_options
|
|
32
|
+
sleep_timer = lambda do |attempt|
|
|
33
|
+
wait = BASE_DELAY * (2**attempt - 1) # Exponential delay with each subsequent request attempt.
|
|
34
|
+
wait += rand(wait + 1..wait + MAX_REQUEST_RETRY_JITTER) # Add jitter to the delay window.
|
|
35
|
+
wait = [MAX_REQUEST_RETRY_DELAY, wait].min # Cap delay at MAX_REQUEST_RETRY_DELAY.
|
|
36
|
+
wait = [MIN_REQUEST_RETRY_DELAY, wait].max # Ensure delay is no less than MIN_REQUEST_RETRY_DELAY.
|
|
37
|
+
wait / 1000.to_f.round(2) # convert ms to seconds
|
|
41
38
|
end
|
|
39
|
+
|
|
40
|
+
tries = 1 + [Integer(retry_count || DEFAULT_RETRIES), MAX_ALLOWED_RETRIES].min # Cap retries at MAX_ALLOWED_RETRIES
|
|
41
|
+
|
|
42
|
+
{
|
|
43
|
+
tries: tries,
|
|
44
|
+
sleep: sleep_timer,
|
|
45
|
+
on: Auth0::RateLimitEncountered
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def encode_uri(uri)
|
|
50
|
+
# if a base_uri is set then the uri can be encoded as a path
|
|
51
|
+
path = base_uri ? Addressable::URI.new(path: uri).normalized_path : Addressable::URI.escape(uri)
|
|
52
|
+
url(path)
|
|
42
53
|
end
|
|
43
54
|
|
|
44
55
|
def url(path)
|
|
@@ -47,6 +58,7 @@ module Auth0
|
|
|
47
58
|
|
|
48
59
|
def add_headers(h = {})
|
|
49
60
|
raise ArgumentError, 'Headers must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
|
|
61
|
+
|
|
50
62
|
@headers ||= {}
|
|
51
63
|
@headers.merge!(h.to_hash)
|
|
52
64
|
end
|
|
@@ -57,6 +69,50 @@ module Auth0
|
|
|
57
69
|
body
|
|
58
70
|
end
|
|
59
71
|
|
|
72
|
+
def request_with_retry(method, uri, body = {}, extra_headers = {})
|
|
73
|
+
Retryable.retryable(retry_options) do
|
|
74
|
+
request(method, uri, body, extra_headers)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def request(method, uri, body = {}, extra_headers = {})
|
|
79
|
+
result = case method
|
|
80
|
+
when :get
|
|
81
|
+
@headers ||= {}
|
|
82
|
+
get_headers = @headers.merge({ params: body }).merge(extra_headers)
|
|
83
|
+
call(:get, encode_uri(uri), timeout, get_headers)
|
|
84
|
+
when :delete
|
|
85
|
+
@headers ||= {}
|
|
86
|
+
delete_headers = @headers.merge({ params: body })
|
|
87
|
+
call(:delete, encode_uri(uri), timeout, delete_headers)
|
|
88
|
+
when :delete_with_body
|
|
89
|
+
call(:delete, encode_uri(uri), timeout, headers, body.to_json)
|
|
90
|
+
when :post_file
|
|
91
|
+
body.merge!(multipart: true)
|
|
92
|
+
# Ignore the default Content-Type headers and let the HTTP client define them
|
|
93
|
+
post_file_headers = headers.except('Content-Type') unless headers.nil?
|
|
94
|
+
# Actual call with the altered headers
|
|
95
|
+
call(:post, encode_uri(uri), timeout, post_file_headers, body)
|
|
96
|
+
when :post_form
|
|
97
|
+
form_post_headers = headers.except('Content-Type') unless headers.nil?
|
|
98
|
+
call(:post, encode_uri(uri), timeout, form_post_headers, body.compact)
|
|
99
|
+
else
|
|
100
|
+
call(method, encode_uri(uri), timeout, headers, body.to_json)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
case result.code
|
|
104
|
+
when 200...226 then safe_parse_json(result.body)
|
|
105
|
+
when 400 then raise Auth0::BadRequest.new(result.body, code: result.code, headers: result.headers)
|
|
106
|
+
when 401 then raise Auth0::Unauthorized.new(result.body, code: result.code, headers: result.headers)
|
|
107
|
+
when 403 then raise Auth0::AccessDenied.new(result.body, code: result.code, headers: result.headers)
|
|
108
|
+
when 404 then raise Auth0::NotFound.new(result.body, code: result.code, headers: result.headers)
|
|
109
|
+
when 429 then raise Auth0::RateLimitEncountered.new(result.body, code: result.code,
|
|
110
|
+
headers: result.headers)
|
|
111
|
+
when 500 then raise Auth0::ServerError.new(result.body, code: result.code, headers: result.headers)
|
|
112
|
+
else raise Auth0::Unsupported.new(result.body, code: result.code, headers: result.headers)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
60
116
|
def call(method, url, timeout, headers, body = nil)
|
|
61
117
|
RestClient::Request.execute(
|
|
62
118
|
method: method,
|
|
@@ -68,11 +124,19 @@ module Auth0
|
|
|
68
124
|
rescue RestClient::Exception => e
|
|
69
125
|
case e
|
|
70
126
|
when RestClient::RequestTimeout
|
|
71
|
-
raise Auth0::RequestTimeout
|
|
127
|
+
raise Auth0::RequestTimeout, e.message
|
|
72
128
|
else
|
|
73
|
-
|
|
129
|
+
e.response
|
|
74
130
|
end
|
|
75
131
|
end
|
|
132
|
+
|
|
133
|
+
private
|
|
134
|
+
|
|
135
|
+
def safe_merge_body(body, extra = {})
|
|
136
|
+
return body unless body.is_a?(Hash)
|
|
137
|
+
merged = extra.any? ? body.merge(extra) : body
|
|
138
|
+
merged.compact
|
|
139
|
+
end
|
|
76
140
|
end
|
|
77
141
|
end
|
|
78
142
|
end
|
|
@@ -15,9 +15,13 @@ module Auth0
|
|
|
15
15
|
@base_uri = base_url(options)
|
|
16
16
|
@headers = client_headers
|
|
17
17
|
@timeout = options[:timeout] || 10
|
|
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';
|
|
18
21
|
extend Auth0::Api::AuthenticationEndpoints
|
|
19
22
|
@client_id = options[:client_id]
|
|
20
23
|
@client_secret = options[:client_secret]
|
|
24
|
+
@organization = options[:organization]
|
|
21
25
|
initialize_api(options)
|
|
22
26
|
end
|
|
23
27
|
|
|
@@ -40,7 +44,7 @@ module Auth0
|
|
|
40
44
|
private
|
|
41
45
|
|
|
42
46
|
def initialize_api(options)
|
|
43
|
-
|
|
47
|
+
initialize_v2(options)
|
|
44
48
|
raise InvalidCredentials, 'Must supply a valid API token' if @token.nil?
|
|
45
49
|
if options.fetch(:authorization, nil) == 'Basic'
|
|
46
50
|
authorization_header_basic(options)
|
|
@@ -57,14 +61,7 @@ module Auth0
|
|
|
57
61
|
|
|
58
62
|
def initialize_v2(options)
|
|
59
63
|
extend Auth0::Api::V2
|
|
60
|
-
|
|
61
|
-
@token = api_token.token if @token.nil? && @client_id && @client_secret
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def initialize_v1
|
|
65
|
-
extend Auth0::Api::V1
|
|
66
|
-
raise InvalidCredentials, 'Invalid API v1 client_id and client_secret' if @client_id.nil? || @client_secret.nil?
|
|
67
|
-
@token = obtain_access_token
|
|
64
|
+
initialize_token(options)
|
|
68
65
|
end
|
|
69
66
|
|
|
70
67
|
def api_v2?(options)
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
Permission = Struct.new :permission_name, :resource_server_identifier do
|
|
1
|
+
Auth0::Permission = Struct.new :permission_name, :resource_server_identifier do
|
|
2
2
|
|
|
3
|
-
end
|
|
3
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Auth0
|
|
2
|
+
module Mixins
|
|
3
|
+
module TokenManagement
|
|
4
|
+
|
|
5
|
+
# Get the Client's api token (or generate a new one if it has expired).
|
|
6
|
+
#
|
|
7
|
+
# @note This method may perform a network request to refresh an expired token. It is not thread-safe.
|
|
8
|
+
# @return [String] the api token
|
|
9
|
+
def get_token
|
|
10
|
+
has_expired = @token && @token_expires_at ? @token_expires_at < (Time.now.to_i + 10) : false
|
|
11
|
+
|
|
12
|
+
if (@token.nil? || has_expired) && @client_id && (@client_secret || @client_assertion_signing_key)
|
|
13
|
+
response = api_token(audience: @audience)
|
|
14
|
+
@token = response.token
|
|
15
|
+
@token_expires_at = response.expires_in ? Time.now.to_i + response.expires_in : nil
|
|
16
|
+
|
|
17
|
+
@token
|
|
18
|
+
else
|
|
19
|
+
@token
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def initialize_token(options)
|
|
26
|
+
@token = options[:access_token] || options[:token]
|
|
27
|
+
# default expiry to an hour if a token was given but no expires_at
|
|
28
|
+
@token_expires_at = @token ? options[:token_expires_at] || Time.now.to_i + 3600 : nil
|
|
29
|
+
|
|
30
|
+
@audience = options[:api_identifier] || "https://#{@domain}/api/v2/"
|
|
31
|
+
get_token() if @token.nil?
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
require 'zache'
|
|
2
|
+
|
|
3
|
+
class Zache
|
|
4
|
+
def last(key)
|
|
5
|
+
@hash[key][:value] if @hash.key?(key)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
1
9
|
module Auth0
|
|
2
10
|
module Mixins
|
|
3
11
|
# Module to provide validation for specific data structures.
|
|
@@ -15,11 +23,337 @@ module Auth0
|
|
|
15
23
|
raise Auth0::InvalidParameter, 'Must supply an array of Permissions' unless permissions.kind_of?(Array)
|
|
16
24
|
raise Auth0::MissingParameter, 'Must supply an array of Permissions' if permissions.empty?
|
|
17
25
|
raise Auth0::InvalidParameter, 'All array elements must be Permissions' unless permissions.all? do |permission|
|
|
18
|
-
permission.kind_of? Permission
|
|
26
|
+
permission.kind_of? ::Auth0::Permission
|
|
19
27
|
end
|
|
20
28
|
permissions.map { |permission| permission.to_h }
|
|
21
29
|
end
|
|
22
30
|
|
|
31
|
+
# rubocop:disable Metrics/ClassLength
|
|
32
|
+
class IdTokenValidator
|
|
33
|
+
def initialize(context)
|
|
34
|
+
@context = context
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def validate(id_token)
|
|
38
|
+
decoding_error = 'ID token could not be decoded'
|
|
39
|
+
|
|
40
|
+
unless !id_token.to_s.empty? && id_token.split('.').count == 3
|
|
41
|
+
raise Auth0::InvalidIdToken, decoding_error
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
begin
|
|
45
|
+
header = JWT::JSON.parse(JWT::Base64.url_decode(id_token.split('.').first))
|
|
46
|
+
rescue
|
|
47
|
+
raise Auth0::InvalidIdToken, decoding_error
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
claims = decode_and_validate_signature(id_token, header)
|
|
51
|
+
validate_claims(claims)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
57
|
+
def decode_and_validate_signature(id_token, header)
|
|
58
|
+
algorithm = @context[:algorithm]
|
|
59
|
+
|
|
60
|
+
unless algorithm.is_a?(Auth0::Mixins::Validation::JWTAlgorithm)
|
|
61
|
+
raise Auth0::InvalidIdToken, "Signature algorithm of \"#{algorithm}\" is not supported"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# The expiration verification will be performed in the validate_claims method
|
|
65
|
+
options = { algorithms: [algorithm.name], verify_expiration: false, verify_not_before: false }
|
|
66
|
+
secret = nil
|
|
67
|
+
|
|
68
|
+
case algorithm
|
|
69
|
+
when Auth0::Algorithm::RS256
|
|
70
|
+
kid = header['kid']
|
|
71
|
+
jwks = JSON.parse(JSON[algorithm.jwks], symbolize_names: true)
|
|
72
|
+
|
|
73
|
+
if !jwks[:keys].find { |key| key[:kid] == kid } && !algorithm.fetched_jwks?
|
|
74
|
+
jwks = JSON.parse(JSON[algorithm.jwks(force: true)], symbolize_names: true)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
options[:jwks] = jwks
|
|
78
|
+
when Auth0::Algorithm::HS256
|
|
79
|
+
secret = algorithm.secret
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
begin
|
|
83
|
+
result = JWT.decode(id_token, secret, true, options)
|
|
84
|
+
result.first
|
|
85
|
+
rescue JWT::VerificationError
|
|
86
|
+
raise Auth0::InvalidIdToken, 'Invalid ID token signature'
|
|
87
|
+
rescue JWT::IncorrectAlgorithm
|
|
88
|
+
alg = header['alg']
|
|
89
|
+
raise Auth0::InvalidIdToken, "Signature algorithm of \"#{alg}\" is not supported. Expected the ID token"\
|
|
90
|
+
" to be signed with \"#{algorithm.name}\""
|
|
91
|
+
rescue JWT::DecodeError
|
|
92
|
+
raise Auth0::InvalidIdToken, "Could not find a public key for Key ID (kid) \"#{kid}\""
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
|
97
|
+
def validate_claims(claims)
|
|
98
|
+
leeway = @context[:leeway]
|
|
99
|
+
nonce = @context[:nonce]
|
|
100
|
+
issuer = @context[:issuer]
|
|
101
|
+
audience = @context[:audience]
|
|
102
|
+
max_age = @context[:max_age]
|
|
103
|
+
org = @context[:organization]
|
|
104
|
+
|
|
105
|
+
raise Auth0::InvalidParameter, 'Must supply a valid leeway' unless leeway.is_a?(Integer) && leeway >= 0
|
|
106
|
+
raise Auth0::InvalidParameter, 'Must supply a valid nonce' unless nonce.nil? || !nonce.to_s.empty?
|
|
107
|
+
raise Auth0::InvalidParameter, 'Must supply a valid issuer' unless issuer.nil? || !issuer.to_s.empty?
|
|
108
|
+
raise Auth0::InvalidParameter, 'Must supply a valid audience' unless audience.nil? || !audience.to_s.empty?
|
|
109
|
+
raise Auth0::InvalidParameter, 'Must supply a valid organization' unless org.nil? || !org.to_s.empty?
|
|
110
|
+
|
|
111
|
+
unless max_age.nil? || (max_age.is_a?(Integer) && max_age >= 0)
|
|
112
|
+
raise Auth0::InvalidParameter, 'Must supply a valid max_age'
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
validate_iss(claims, issuer)
|
|
116
|
+
validate_sub(claims)
|
|
117
|
+
validate_aud(claims, audience)
|
|
118
|
+
validate_exp(claims, leeway)
|
|
119
|
+
validate_iat(claims, leeway)
|
|
120
|
+
validate_nonce(claims, nonce) if nonce
|
|
121
|
+
validate_azp(claims, audience) if claims['aud'].is_a?(Array) && claims['aud'].count > 1
|
|
122
|
+
validate_auth_time(claims, max_age, leeway) if max_age
|
|
123
|
+
validate_org(claims, org) if org
|
|
124
|
+
end
|
|
125
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
126
|
+
|
|
127
|
+
def validate_iss(claims, expected)
|
|
128
|
+
unless claims.key?('iss') && claims['iss'].is_a?(String)
|
|
129
|
+
raise Auth0::InvalidIdToken, 'Issuer (iss) claim must be a string present in the ID token'
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
unless expected == claims['iss']
|
|
133
|
+
raise Auth0::InvalidIdToken, "Issuer (iss) claim mismatch in the ID token; expected \"#{expected}\","\
|
|
134
|
+
" found \"#{claims['iss']}\""
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def validate_sub(claims)
|
|
139
|
+
unless claims.key?('sub') && claims['sub'].is_a?(String)
|
|
140
|
+
raise Auth0::InvalidIdToken, 'Subject (sub) claim must be a string present in the ID token'
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def validate_aud(claims, expected)
|
|
145
|
+
unless claims.key?('aud') && (claims['aud'].is_a?(String) || claims['aud'].is_a?(Array))
|
|
146
|
+
raise Auth0::InvalidIdToken, 'Audience (aud) claim must be a string or array of strings present'\
|
|
147
|
+
' in the ID token'
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
if claims['aud'].is_a?(String) && expected != claims['aud']
|
|
151
|
+
raise Auth0::InvalidIdToken, "Audience (aud) claim mismatch in the ID token; expected \"#{expected}\","\
|
|
152
|
+
" found \"#{claims['aud']}\""
|
|
153
|
+
elsif claims['aud'].is_a?(Array) && !claims['aud'].include?(expected)
|
|
154
|
+
raise Auth0::InvalidIdToken, "Audience (aud) claim mismatch in the ID token; expected \"#{expected}\""\
|
|
155
|
+
" but was not one of \"#{claims['aud'].join ', '}\""
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def validate_exp(claims, leeway)
|
|
160
|
+
unless claims.key?('exp') && claims['exp'].is_a?(Integer)
|
|
161
|
+
raise Auth0::InvalidIdToken, 'Expiration Time (exp) claim must be a number present in the ID token'
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
now = @context[:clock] || Time.now.to_i
|
|
165
|
+
exp_time = claims['exp'] + leeway
|
|
166
|
+
|
|
167
|
+
unless now < exp_time
|
|
168
|
+
raise Auth0::InvalidIdToken, 'Expiration Time (exp) claim mismatch in the ID token; current time'\
|
|
169
|
+
" \"#{now}\" is after expiration time \"#{exp_time}\""
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def validate_iat(claims, leeway)
|
|
174
|
+
unless claims.key?('iat') && claims['iat'].is_a?(Integer)
|
|
175
|
+
raise Auth0::InvalidIdToken, 'Issued At (iat) claim must be a number present in the ID token'
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def validate_nonce(claims, expected)
|
|
180
|
+
unless claims.key?('nonce') && claims['nonce'].is_a?(String)
|
|
181
|
+
raise Auth0::InvalidIdToken, 'Nonce (nonce) claim must be a string present in the ID token'
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
unless expected == claims['nonce']
|
|
185
|
+
raise Auth0::InvalidIdToken, "Nonce (nonce) claim mismatch in the ID token; expected \"#{expected}\","\
|
|
186
|
+
" found \"#{claims['nonce']}\""
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def validate_org(claims, expected)
|
|
191
|
+
validate_as_id = expected.start_with? 'org_'
|
|
192
|
+
|
|
193
|
+
if validate_as_id
|
|
194
|
+
unless claims.key?('org_id') && claims['org_id'].is_a?(String)
|
|
195
|
+
raise Auth0::InvalidIdToken, 'Organization Id (org_id) claim must be a string present in the ID token'
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
unless expected == claims['org_id']
|
|
199
|
+
raise Auth0::InvalidIdToken, "Organization Id (org_id) claim value mismatch in the ID token; expected \"#{expected}\","\
|
|
200
|
+
" found \"#{claims['org_id']}\""
|
|
201
|
+
end
|
|
202
|
+
else
|
|
203
|
+
unless claims.key?('org_name') && claims['org_name'].is_a?(String)
|
|
204
|
+
raise Auth0::InvalidIdToken, 'Organization Name (org_name) claim must be a string present in the ID token'
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
unless expected.downcase == claims['org_name']
|
|
208
|
+
raise Auth0::InvalidIdToken, "Organization Name (org_name) claim value mismatch in the ID token; expected \"#{expected}\","\
|
|
209
|
+
" found \"#{claims['org_name']}\""
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def validate_azp(claims, expected)
|
|
215
|
+
unless claims.key?('azp') && claims['azp'].is_a?(String)
|
|
216
|
+
raise Auth0::InvalidIdToken, 'Authorized Party (azp) claim must be a string present in the ID token'
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
unless expected == claims['azp']
|
|
220
|
+
raise Auth0::InvalidIdToken, 'Authorized Party (azp) claim mismatch in the ID token; expected'\
|
|
221
|
+
" \"#{expected}\", found \"#{claims['azp']}\""
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def validate_auth_time(claims, max_age, leeway)
|
|
226
|
+
unless claims.key?('auth_time') && claims['auth_time'].is_a?(Integer)
|
|
227
|
+
raise Auth0::InvalidIdToken, 'Authentication Time (auth_time) claim must be a number present in the ID'\
|
|
228
|
+
' token when Max Age (max_age) is specified'
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
now = @context[:clock] || Time.now.to_i
|
|
232
|
+
auth_valid_until = claims['auth_time'] + max_age + leeway
|
|
233
|
+
|
|
234
|
+
unless now < auth_valid_until
|
|
235
|
+
raise Auth0::InvalidIdToken, 'Authentication Time (auth_time) claim in the ID token indicates that too'\
|
|
236
|
+
' much time has passed since the last end-user authentication. Current time'\
|
|
237
|
+
" \"#{now}\" is after last auth at \"#{auth_valid_until}\""
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
# rubocop:enable Metrics/ClassLength
|
|
242
|
+
|
|
243
|
+
class JWTAlgorithm
|
|
244
|
+
private_class_method :new
|
|
245
|
+
|
|
246
|
+
def name
|
|
247
|
+
raise RuntimeError, 'Must be overriden by the subclasses'
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
module Algorithm
|
|
252
|
+
# Represents the HS256 algorithm, which rely on shared secrets.
|
|
253
|
+
# @see https://auth0.com/docs/tokens/concepts/signing-algorithms
|
|
254
|
+
class HS256 < JWTAlgorithm
|
|
255
|
+
class << self
|
|
256
|
+
private :new
|
|
257
|
+
|
|
258
|
+
# Create a new instance passing the shared secret.
|
|
259
|
+
# @param secret [string] The HMAC shared secret.
|
|
260
|
+
# @return [HS256] A new instance.
|
|
261
|
+
def secret(secret)
|
|
262
|
+
new secret
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
attr_accessor :secret
|
|
267
|
+
|
|
268
|
+
def initialize(secret)
|
|
269
|
+
raise Auth0::InvalidParameter, 'Must supply a valid secret' if secret.to_s.empty?
|
|
270
|
+
|
|
271
|
+
@secret = secret
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# Returns the algorithm name.
|
|
275
|
+
# @return [string] The algorithm name.
|
|
276
|
+
def name
|
|
277
|
+
'HS256'
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Represents the RS256 algorithm, which rely on public key certificates.
|
|
282
|
+
# @see https://auth0.com/docs/tokens/concepts/signing-algorithms
|
|
283
|
+
class RS256 < JWTAlgorithm
|
|
284
|
+
include Auth0::Mixins::HTTPProxy
|
|
285
|
+
|
|
286
|
+
@@cache = Zache.new.freeze
|
|
287
|
+
|
|
288
|
+
class << self
|
|
289
|
+
private :new
|
|
290
|
+
|
|
291
|
+
# Create a new instance passing the JWK set url.
|
|
292
|
+
# @param url [string] The url where the JWK set is located.
|
|
293
|
+
# @param lifetime [integer] The lifetime of the JWK set in-memory cache in seconds.
|
|
294
|
+
# Must be a non-negative value. Defaults to *600 seconds* (10 minutes).
|
|
295
|
+
# @return [RS256] A new instance.
|
|
296
|
+
def jwks_url(url, lifetime: 10 * 60)
|
|
297
|
+
new url, lifetime
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Clear the JWK set cache.
|
|
301
|
+
def remove_jwks
|
|
302
|
+
@@cache.remove_by { true }
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def initialize(jwks_url, lifetime)
|
|
307
|
+
raise Auth0::InvalidParameter, 'Must supply a valid jwks_url' if jwks_url.to_s.empty?
|
|
308
|
+
raise Auth0::InvalidParameter, 'Must supply a valid lifetime' unless lifetime.is_a?(Integer) && lifetime >= 0
|
|
309
|
+
|
|
310
|
+
@lifetime = lifetime
|
|
311
|
+
@jwks_url = jwks_url
|
|
312
|
+
@did_fetch_jwks = false
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
# Returns the algorithm name.
|
|
316
|
+
# @return [string] The algorithm name.
|
|
317
|
+
def name
|
|
318
|
+
'RS256'
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Fetches the JWK set from the in-memory cache or from the url.
|
|
322
|
+
# @return [hash] A JWK set.
|
|
323
|
+
def jwks(force: false)
|
|
324
|
+
result = fetch_jwks if force
|
|
325
|
+
|
|
326
|
+
if result
|
|
327
|
+
@@cache.put(@jwks_url, result, lifetime: @lifetime)
|
|
328
|
+
return result
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
previous_value = @@cache.last(@jwks_url)
|
|
332
|
+
|
|
333
|
+
@@cache.get(@jwks_url, lifetime: @lifetime, dirty: true) do
|
|
334
|
+
new_value = fetch_jwks
|
|
335
|
+
|
|
336
|
+
raise Auth0::InvalidIdToken, 'Could not fetch the JWK set' unless new_value || previous_value
|
|
337
|
+
|
|
338
|
+
new_value || previous_value
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# Returns whether or not the JWK set was fetched from the url.
|
|
343
|
+
# @return [boolean] +true+ if a request to the JWK set url was made, +false+ otherwise.
|
|
344
|
+
def fetched_jwks?
|
|
345
|
+
@did_fetch_jwks
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
private
|
|
349
|
+
|
|
350
|
+
def fetch_jwks
|
|
351
|
+
result = request_with_retry(:get, @jwks_url, {}, {})
|
|
352
|
+
@did_fetch_jwks = result.is_a?(Hash) && result.key?('keys')
|
|
353
|
+
result if @did_fetch_jwks
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
end
|
|
23
357
|
end
|
|
24
358
|
end
|
|
25
359
|
end
|
data/lib/auth0/mixins.rb
CHANGED
|
@@ -9,15 +9,16 @@ require 'auth0/mixins/httpproxy'
|
|
|
9
9
|
require 'auth0/mixins/initializer'
|
|
10
10
|
require 'auth0/mixins/permission_struct'
|
|
11
11
|
require 'auth0/mixins/validation'
|
|
12
|
+
require 'auth0/mixins/token_management'
|
|
12
13
|
|
|
13
14
|
require 'auth0/api/authentication_endpoints'
|
|
14
|
-
require 'auth0/api/v1'
|
|
15
15
|
require 'auth0/api/v2'
|
|
16
16
|
|
|
17
17
|
module Auth0
|
|
18
18
|
# Collecting dependencies here
|
|
19
19
|
module Mixins
|
|
20
20
|
include Auth0::Mixins::Headers
|
|
21
|
+
include Auth0::Mixins::TokenManagement
|
|
21
22
|
include Auth0::Mixins::HTTPProxy
|
|
22
23
|
include Auth0::Mixins::Initializer
|
|
23
24
|
end
|
data/lib/auth0/version.rb
CHANGED