diff --git a/CHANGELOG.md b/CHANGELOG.md index 350eab80..8fee1960 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## [4.1.1](https://github.com/auth0/auth0-python/tree/4.1.1) (2023-04-13) +[Full Changelog](https://github.com/auth0/auth0-python/compare/4.1.0...4.1.1) + +**Fixed** +- Make pw realm params optional [\#484](https://github.com/auth0/auth0-python/pull/484) ([adamjmcgrath](https://github.com/adamjmcgrath)) +- Fix intellisense on Auth0 class [\#486](https://github.com/auth0/auth0-python/pull/486) ([adamjmcgrath](https://github.com/adamjmcgrath)) + ## [4.1.0](https://github.com/auth0/auth0-python/tree/4.1.0) (2023-03-14) [Full Changelog](https://github.com/auth0/auth0-python/compare/4.0.0...4.1.0) diff --git a/EXAMPLES.md b/EXAMPLES.md index bbe39e73..a1695a78 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -5,8 +5,8 @@ - [Authenticating with a application configured to use `private_key_jwt` token endpoint auth method](#authenticating-with-a-application-configured-to-use-private-key-jwt-token-endpoint-auth-method) - [Management SDK](#management-sdk) - [Connections](#connections) - - [Error handling](#error-handling) - - [Asynchronous environments](#asynchronous-environments) +- [Error handling](#error-handling) +- [Asynchronous environments](#asynchronous-environments) ## Authentication SDK @@ -32,7 +32,7 @@ For symmetric algorithms like HS256, use the `SymmetricSignatureVerifier` class, The following example demonstrates the verification of an ID token signed with the RS256 signing algorithm: ```python -from auth0.authentication import TokenVerifier, AsymmetricSignatureVerifier +from auth0.authentication.token_verifier import TokenVerifier, AsymmetricSignatureVerifier domain = 'myaccount.auth0.com' client_id = 'exampleid' @@ -135,7 +135,7 @@ Success! All endpoints follow a similar structure to `connections`, and try to follow as closely as possible the [API documentation](https://auth0.com/docs/api/v2). -### Error handling +## Error handling When consuming methods from the API clients, the requests could fail for a number of reasons: - Invalid data sent as part of the request: An `Auth0Error` is raised with the error code and description. @@ -143,7 +143,7 @@ When consuming methods from the API clients, the requests could fail for a numbe resets is exposed in the `reset_at` property. When the header is unset, this value will be `-1`. - Network timeouts: Adjustable by passing a `timeout` argument to the client. See the [rate limit docs](https://auth0.com/docs/policies/rate-limits) for details. -### Asynchronous environments +## Asynchronous environments This SDK provides async methods built on top of [asyncio](https://docs.python.org/3/library/asyncio.html). To make them available you must have the [aiohttp](https://docs.aiohttp.org/en/stable/) module installed. @@ -194,4 +194,4 @@ async def main(): asyncio.run(main()) -``` \ No newline at end of file +``` diff --git a/auth0/__init__.py b/auth0/__init__.py index dc09a987..5134db61 100644 --- a/auth0/__init__.py +++ b/auth0/__init__.py @@ -1,4 +1,4 @@ -__version__ = "4.1.0" +__version__ = "4.1.1" from auth0.exceptions import Auth0Error, RateLimitError, TokenValidationError diff --git a/auth0/authentication/get_token.py b/auth0/authentication/get_token.py index bb697a2f..4986e55b 100644 --- a/auth0/authentication/get_token.py +++ b/auth0/authentication/get_token.py @@ -118,9 +118,9 @@ def login( self, username, password, - scope, - realm, - audience, + scope=None, + realm=None, + audience=None, grant_type="http://auth0.com/oauth/grant-type/password-realm", ): """Calls /oauth/token endpoint with password-realm grant type @@ -134,18 +134,18 @@ def login( this information. Args: - audience (str): The unique identifier of the target API you want to access. - username (str): Resource owner's identifier password (str): resource owner's Secret - scope(str): String value of the different scopes the client is asking for. + scope(str, optional): String value of the different scopes the client is asking for. Multiple scopes are separated with whitespace. - realm (str): String value of the realm the user belongs. + realm (str, optional): String value of the realm the user belongs. Set this if you want to add realm support at this grant. + audience (str, optional): The unique identifier of the target API you want to access. + grant_type (str, optional): Denotes the flow you're using. For password realm use http://auth0.com/oauth/grant-type/password-realm diff --git a/auth0/management/async_auth0.py b/auth0/management/async_auth0.py index 241c47f6..a0971512 100644 --- a/auth0/management/async_auth0.py +++ b/auth0/management/async_auth0.py @@ -1,7 +1,7 @@ import aiohttp from ..asyncify import asyncify -from .auth0 import modules +from .auth0 import Auth0 class AsyncAuth0: @@ -20,8 +20,8 @@ class AsyncAuth0: def __init__(self, domain, token, rest_options=None): self._services = [] - for name, cls in modules.items(): - cls = asyncify(cls) + for name, attr in vars(Auth0(domain, token, rest_options=rest_options)).items(): + cls = asyncify(attr.__class__) service = cls(domain=domain, token=token, rest_options=rest_options) self._services.append(service) setattr( diff --git a/auth0/management/auth0.py b/auth0/management/auth0.py index 9b1f3502..9e36ce96 100644 --- a/auth0/management/auth0.py +++ b/auth0/management/auth0.py @@ -1,4 +1,3 @@ -from ..utils import is_async_available from .actions import Actions from .attack_protection import AttackProtection from .blacklists import Blacklists @@ -30,39 +29,6 @@ from .users import Users from .users_by_email import UsersByEmail -modules = { - "actions": Actions, - "attack_protection": AttackProtection, - "blacklists": Blacklists, - "branding": Branding, - "client_credentials": ClientCredentials, - "client_grants": ClientGrants, - "clients": Clients, - "connections": Connections, - "custom_domains": CustomDomains, - "device_credentials": DeviceCredentials, - "email_templates": EmailTemplates, - "emails": Emails, - "grants": Grants, - "guardian": Guardian, - "hooks": Hooks, - "jobs": Jobs, - "log_streams": LogStreams, - "logs": Logs, - "organizations": Organizations, - "prompts": Prompts, - "resource_servers": ResourceServers, - "roles": Roles, - "rules_configs": RulesConfigs, - "rules": Rules, - "stats": Stats, - "tenants": Tenants, - "tickets": Tickets, - "user_blocks": UserBlocks, - "users_by_email": UsersByEmail, - "users": Users, -} - class Auth0: """Provides easy access to all endpoint classes @@ -79,9 +45,41 @@ class Auth0: """ def __init__(self, domain, token, rest_options=None): - for name, cls in modules.items(): - setattr( - self, - name, - cls(domain=domain, token=token, rest_options=rest_options), - ) + self.actions = Actions(domain, token, rest_options=rest_options) + self.attack_protection = AttackProtection( + domain, token, rest_options=rest_options + ) + self.blacklists = Blacklists(domain, token, rest_options=rest_options) + self.branding = Branding(domain, token, rest_options=rest_options) + self.client_credentials = ClientCredentials( + domain, token, rest_options=rest_options + ) + self.client_grants = ClientGrants(domain, token, rest_options=rest_options) + self.clients = Clients(domain, token, rest_options=rest_options) + self.connections = Connections(domain, token, rest_options=rest_options) + self.custom_domains = CustomDomains(domain, token, rest_options=rest_options) + self.device_credentials = DeviceCredentials( + domain, token, rest_options=rest_options + ) + self.email_templates = EmailTemplates(domain, token, rest_options=rest_options) + self.emails = Emails(domain, token, rest_options=rest_options) + self.grants = Grants(domain, token, rest_options=rest_options) + self.guardian = Guardian(domain, token, rest_options=rest_options) + self.hooks = Hooks(domain, token, rest_options=rest_options) + self.jobs = Jobs(domain, token, rest_options=rest_options) + self.log_streams = LogStreams(domain, token, rest_options=rest_options) + self.logs = Logs(domain, token, rest_options=rest_options) + self.organizations = Organizations(domain, token, rest_options=rest_options) + self.prompts = Prompts(domain, token, rest_options=rest_options) + self.resource_servers = ResourceServers( + domain, token, rest_options=rest_options + ) + self.roles = Roles(domain, token, rest_options=rest_options) + self.rules_configs = RulesConfigs(domain, token, rest_options=rest_options) + self.rules = Rules(domain, token, rest_options=rest_options) + self.stats = Stats(domain, token, rest_options=rest_options) + self.tenants = Tenants(domain, token, rest_options=rest_options) + self.tickets = Tickets(domain, token, rest_options=rest_options) + self.user_blocks = UserBlocks(domain, token, rest_options=rest_options) + self.users_by_email = UsersByEmail(domain, token, rest_options=rest_options) + self.users = Users(domain, token, rest_options=rest_options) diff --git a/auth0/test/authentication/test_get_token.py b/auth0/test/authentication/test_get_token.py index 7dd9f492..f2c0b34c 100644 --- a/auth0/test/authentication/test_get_token.py +++ b/auth0/test/authentication/test_get_token.py @@ -163,6 +163,32 @@ def test_login(self, mock_post): }, ) + @mock.patch("auth0.rest.RestClient.post") + def test_login_simple(self, mock_post): + g = GetToken("my.domain.com", "cid", client_secret="clsec") + + g.login( + username="usrnm", + password="pswd", + ) + + args, kwargs = mock_post.call_args + + self.assertEqual(args[0], "https://my.domain.com/oauth/token") + self.assertEqual( + kwargs["data"], + { + "client_id": "cid", + "client_secret": "clsec", + "username": "usrnm", + "password": "pswd", + "realm": None, + "scope": None, + "audience": None, + "grant_type": "http://auth0.com/oauth/grant-type/password-realm", + }, + ) + @mock.patch("auth0.rest.RestClient.post") def test_refresh_token(self, mock_post): g = GetToken("my.domain.com", "cid", client_secret="clsec")