Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Prepare for V4 release #465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 30 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9ef681a
Add support for private_key_jwt
adamjmcgrath Jan 9, 2023
262d483
Add examples/docs
adamjmcgrath Jan 10, 2023
a098af9
Update README
adamjmcgrath Jan 10, 2023
fd8acb6
Merge branch 'v4' into private_key_jwt
adamjmcgrath Jan 10, 2023
1fc57ee
remove py2 fix docs
adamjmcgrath Jan 10, 2023
8c6a269
Fix docs build
adamjmcgrath Jan 12, 2023
9995993
Ignore uncovered code
adamjmcgrath Jan 12, 2023
2d98e57
Apply suggestions from code review
adamjmcgrath Jan 17, 2023
bd8798b
Apply suggestions from code review
adamjmcgrath Jan 17, 2023
18f7fa9
Merge pull request #456 from auth0/private_key_jwt
adamjmcgrath Jan 17, 2023
ca72808
Add support for managing client credentials
adamjmcgrath Jan 17, 2023
71cd5a8
Apply suggestions from code review
adamjmcgrath Jan 17, 2023
0a2dc94
Merge pull request #459 from auth0/manage-client-credentials
adamjmcgrath Jan 17, 2023
010ec79
Update pyjwt, remove EOL py versions
adamjmcgrath Jan 18, 2023
8384f13
Skip async tests for 3.7
adamjmcgrath Jan 18, 2023
b9e2387
Remove deprecated methods
adamjmcgrath Jan 18, 2023
7be0630
Merge pull request #460 from auth0/update-pyjwt
adamjmcgrath Jan 19, 2023
8212562
Merge branch 'v4' into remove-ro
adamjmcgrath Jan 19, 2023
44de6d9
Merge pull request #461 from auth0/remove-ro
adamjmcgrath Jan 19, 2023
cc101dc
Remove v3 folder
adamjmcgrath Jan 19, 2023
c64772c
Fix migration guide
adamjmcgrath Jan 19, 2023
b0af352
Revert relative to absolute imports
adamjmcgrath Jan 19, 2023
cdf93be
fix install
adamjmcgrath Jan 19, 2023
1bb6443
fix docs
adamjmcgrath Jan 19, 2023
158ae05
Merge pull request #462 from auth0/remove-v3-folder
adamjmcgrath Jan 19, 2023
b92344b
Remove a couple of py2 references
adamjmcgrath Jan 19, 2023
0df83b2
Merge branch 'master' into v4
adamjmcgrath Jan 19, 2023
da2bd8c
Merge branch 'master' into v4
adamjmcgrath Jan 19, 2023
f3735c5
docs: Publish Python Support Schedule
evansims Jan 3, 2023
c2183c4
Merge pull request #454 from auth0/docs/publish-support-schedule
adamjmcgrath Jan 19, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 17 additions & 25 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,34 @@ orbs:
ship: auth0/[email protected]
codecov: codecov/codecov@3

executors:
python_3_10:
docker:
- image: cimg/python:3.10
python_2_7:
docker:
- image: cimg/python:2.7

jobs:
python_3:
executor: python_3_10
build_and_test:
parameters:
py_version:
type: string
default: "3.10"
docker:
- image: cimg/python:<< parameters.py_version >>
steps:
- checkout
- python/install-packages:
pkg-manager: pip
- run: pre-commit run --all-files
- run: coverage run -m unittest
- run: bash <(curl -s https://codecov.io/bash)
- run: make -C docs html

python_2:
executor: python_2_7
steps:
- checkout
- python/install-packages:
pkg-manager: pip-dist
path-args: ".[test]"
- run: coverage run -m unittest discover -s auth0/v3/test -t .
- codecov/upload
- when:
condition:
equal: [ "3.10", << parameters.py_version >> ]
steps:
- run: make -C docs html

workflows:
main:
jobs:
- python_3
- python_2
- build_and_test:
matrix:
parameters:
py_version: [ "3.7", "3.8", "3.9", "3.10", "3.11" ]
- ship/python-publish:
prefix-tag: false
context:
Expand All @@ -50,5 +43,4 @@ workflows:
only:
- master
requires:
- python_3
- python_2
- build_and_test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ bin/
*.egg
.pypirc
pyvenv.cfg
.python-version

# Installer logs
pip-log.txt
Expand Down
126 changes: 25 additions & 101 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

- [Authentication SDK](#authentication-sdk)
- [ID token validation](#id-token-validation)
- [Organizations](#organizations)
- [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)
Expand Down Expand Up @@ -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.v3.authentication.token_verifier import TokenVerifier, AsymmetricSignatureVerifier
from auth0.authentication import TokenVerifier, AsymmetricSignatureVerifier

domain = 'myaccount.auth0.com'
client_id = 'exampleid'
Expand All @@ -50,102 +50,26 @@ tv.verify(id_token)

If the token verification fails, a `TokenValidationError` will be raised. In that scenario, the ID token should be deemed invalid and its contents should not be trusted.



### Organizations

[Organizations](https://auth0.com/docs/organizations) is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications.

Note that Organizations is currently only available to customers on our Enterprise and Startup subscription plans.


#### Log in to an organization

Log in to an organization by specifying the ``organization`` property when calling ``authorize()``:

```python
from auth0.v3.authentication.authorize_client import AuthorizeClient

client = AuthorizeClient('my.domain.com')

client.authorize(client_id='client_id',
redirect_uri='http://localhost',
organization="org_abc")
```

When logging into an organization, it is important to ensure the `org_id` claim of the ID Token matches the expected organization value. The `TokenVerifier` can be be used to ensure the ID Token contains the expected `org_id` claim value:
### Authenticating with a application configured to use `private_key_jwt` token endpoint auth method

```python
from auth0.v3.authentication.token_verifier import TokenVerifier, AsymmetricSignatureVerifier

domain = 'myaccount.auth0.com'
client_id = 'exampleid'

# After authenticating
id_token = auth_result['id_token']

jwks_url = 'https://{}/.well-known/jwks.json'.format(domain)
issuer = 'https://{}/'.format(domain)

sv = AsymmetricSignatureVerifier(jwks_url) # Reusable instance
tv = TokenVerifier(signature_verifier=sv, issuer=issuer, audience=client_id)

# pass the expected organization the user logged in to:
tv.verify(id_token, organization='org_abc')

```

#### Accept user invitations

Accept a user invitation by specifying the `invitation` property when calling `authorize()`. Note that you must also specify the ``organization`` if providing an ``invitation``.
The ID of the invitation and organization are available as query parameters on the invitation URL, e.g., ``https://your-domain.auth0.com/login?invitation=invitation_id&organization=org_id&organization_name=org_name``

```python
from auth0.v3.authentication.authorize_client import AuthorizeClient

client = AuthorizeClient('my.domain.com')

client.authorize(client_id='client_id',
redirect_uri='http://localhost',
organization='org_abc',
invitation="invitation_123")
```

#### Authorizing users from an Organization

If an `org_id` claim is present in the Access Token, then the claim should be validated by the API to ensure that the value received is expected or known.

In particular:

- The issuer (`iss`) claim should be checked to ensure the token was issued by Auth0
- The organization ID (`org_id`) claim should be checked to ensure it is a value that is already known to the application. This could be validated against a known list of organization IDs, or perhaps checked in conjunction with the current request URL. e.g. the sub-domain may hint at what organization should be used to validate the Access Token.

Normally, validating the issuer would be enough to ensure that the token was issued by Auth0. In the case of organizations, additional checks should be made so that the organization within an Auth0 tenant is expected.

If the claim cannot be validated, then the application should deem the token invalid.

The snippet below attempts to illustrate how this verification could look like using the external [PyJWT](https://pyjwt.readthedocs.io/en/latest/usage.html#encoding-decoding-tokens-with-rs256-rsa) library. This dependency will take care of pulling the RS256 Public Key that was used by the server to sign the Access Token. It will also validate its signature, expiration, and the audience value. After the basic verification, get the `org_id` claim and check it against the expected value. The code assumes your application is configured to sign tokens using the RS256 algorithm. Check the [Validate JSON Web Tokens](https://auth0.com/docs/tokens/json-web-tokens/validate-json-web-tokens) article to learn more about this verification.

```python
import jwt # PyJWT
from jwt import PyJWKClient

access_token = # access token from the request
url = 'https://{YOUR AUTH0 DOMAIN}/.well-known/jwks.json'
jwks_client = PyJWKClient(url)
signing_key = jwks_client.get_signing_key_from_jwt(access_token)
data = jwt.decode(
access_token,
signing_key.key,
algorithms=['RS256'],
audience='{YOUR API AUDIENCE}'
from auth0.authentication import GetToken

private_key = """-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAwfUb0nUC0aKB3WiytFhnCIg455BYC+dR3MUGadWpIg7S6lbi
...
2tjIvH4GN9ZkIGwzxIOP61wkUGwGaIzacOTIWOvqRI0OaYr9U18Ep1trvgGR
-----END RSA PRIVATE KEY-----
"""

get_token = GetToken(
"my-domain.us.auth0.com",
"my-client-id",
client_assertion_signing_key=private_key,
)
token = get_token.client_credentials(
"https://my-domain.us.auth0.com/api/v2/"
)

organization = # expected organization ID
if data['org_id'] != organization:
raise Exception('Organization (org_id) claim mismatch')

# if this line is reached, validation is successful
```

## Management SDK
Expand Down Expand Up @@ -221,29 +145,29 @@ resets is exposed in the `reset_at` property. When the header is unset, this val

### 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 Python >=3.6 and the [aiohttp](https://docs.aiohttp.org/en/stable/) module installed.
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.

Then additional methods with the `_async` suffix will be added to modules created by the `management.Auth0` class or to classes that are passed to the `asyncify` method. For example:

```python
import asyncio
import aiohttp
from auth0.v3.asyncify import asyncify
from auth0.v3.management import Auth0, Users, Connections
from auth0.v3.authentication import Users as AuthUsers
from auth0.asyncify import asyncify
from auth0.management import Auth0, Users, Connections
from auth0.authentication import Users as AuthUsers

auth0 = Auth0('domain', 'mgmt_api_token')


async def main():
# users = auth0.users.all() <= sync
users = await auth0.users.all_async() # <= async
users = await auth0.users.all_async() # <= async

# To share a session amongst multiple calls to the same service
async with auth0.users as users:
data = await users.get_async(id)
users.update_async(id, data)


# To share a session amongst multiple calls to multiple services
async with Auth0('domain', 'mgmt_api_token') as auth0:
user = await auth0.users.get_async(user_id)
Expand Down
62 changes: 42 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ You can install the auth0 Python SDK using the following command.
pip install auth0-python
```

For python3, use the following command
```
pip3 install auth0-python
```
Python 3.2 and 3.3 have reached [EOL](https://en.wikipedia.org/wiki/CPython#Version_history) and support will be removed in the near future.
> Requires Python 3.7 or higher.

### Usage

Expand All @@ -36,53 +32,52 @@ The Authentication SDK is organized into components that mirror the structure of
For example:

```python
from auth0.v3.authentication import Social
from auth0.authentication import Social

social = Social('myaccount.auth0.com')
social = Social('my-domain.us.auth0.com', 'my-client-id')

social.login(client_id='...', access_token='...', connection='facebook')
social.login(access_token='...', connection='facebook')
```

If you need to sign up a user using their email and password, you can use the Database object.

```python
from auth0.v3.authentication import Database
from auth0.authentication import Database

database = Database('myaccount.auth0.com'')
database = Database('my-domain.us.auth0.com', 'my-client-id')

database.signup(client_id='...', email='[email protected]', password='secr3t', connection='Username-Password-Authentication')
database.signup(email='[email protected]', password='secr3t', connection='Username-Password-Authentication')
```

If you need to authenticate a user using their email and password, you can use the `GetToken` object, which enables making requests to the `/oauth/token` endpoint.

```python
from auth0.v3.authentication import GetToken
from auth0.authentication import GetToken

token = GetToken('myaccount.auth0.com')
token = GetToken('my-domain.us.auth0.com', 'my-client-id', client_secret='my-client-secret')

token.login(client_id='...', client_secret='...', username='[email protected]', password='secr3t', realm='Username-Password-Authentication')
token.login(username='[email protected]', password='secr3t', realm='Username-Password-Authentication')
```

#### Management SDK
To use the management library you will need to instantiate an Auth0 object with a domain and a [Management API v2 token](https://auth0.com/docs/api/management/v2/tokens). Please note that these token last 24 hours, so if you need it constantly you should ask for it programmatically using the client credentials grant with a [non interactive client](https://auth0.com/docs/api/management/v2/tokens#1-create-and-authorize-a-client) authorized to access the API. For example:

```python
from auth0.v3.authentication import GetToken
from auth0.authentication import GetToken

domain = 'myaccount.auth0.com'
non_interactive_client_id = 'exampleid'
non_interactive_client_secret = 'examplesecret'

get_token = GetToken(domain)
token = get_token.client_credentials(non_interactive_client_id,
non_interactive_client_secret, 'https://{}/api/v2/'.format(domain))
get_token = GetToken(domain, non_interactive_client_id, client_secret=non_interactive_client_secret)
token = get_token.client_credentials('https://{}/api/v2/'.format(domain))
mgmt_api_token = token['access_token']
```

Then use the token you've obtained as follows:

```python
from auth0.v3.management import Auth0
from auth0.management import Auth0

domain = 'myaccount.auth0.com'
mgmt_api_token = 'MGMT_API_TOKEN'
Expand All @@ -98,7 +93,6 @@ For more code samples on how to integrate the auth0-python SDK in your Python ap

### Authentication Endpoints

- API Authorization - Authorization Code Grant (`authentication.AuthorizeClient`)
- Database ( `authentication.Database` )
- Delegated ( `authentication.Delegated` )
- Enterprise ( `authentication.Enterprise` )
Expand All @@ -115,6 +109,7 @@ For more code samples on how to integrate the auth0-python SDK in your Python ap
- AttackProtection() (`Auth0().attack_protection`)
- Blacklists() ( `Auth0().blacklists` )
- Branding() ( `Auth0().branding` )
- ClientCredentials() ( `Auth0().client_credentials` )
- ClientGrants() ( `Auth0().client_grants` )
- Clients() ( `Auth0().clients` )
- Connections() ( `Auth0().connections` )
Expand All @@ -140,6 +135,33 @@ For more code samples on how to integrate the auth0-python SDK in your Python ap
- UserBlocks() (`Auth0().user_blocks` )
- UsersByEmail() ( `Auth0().users_by_email` )
- Users() ( `Auth0().users` )

## Support Policy

Our support lifecycle policy mirrors the [Python support schedule](https://devguide.python.org/versions/). We do not support running the SDK on unsupported versions of Python that have ceased to receive security updates. Please ensure your environment remains up to date and running the latest Python version possible.

| SDK Version | Python Version | Support Ends |
|-------------| -------------- | ------------ |
| 4.x | 3.11 | Oct 2027 |
| | 3.10 | Oct 2026 |
| | 3.9 | Oct 2025 |
| | 3.8 | Oct 2024 |
| | 3.7 | Oct 2023 |

> As `pip` [reliably avoids](https://packaging.python.org/en/latest/tutorials/packaging-projects/#configuring-metadata) installing package updates that target incompatible Python versions, we may opt to remove support for [end-of-life](https://en.wikipedia.org/wiki/CPython#Version_history) Python versions during minor SDK updates. These are not considered breaking changes by this SDK.

The following is a list of unsupported Python versions, and the last SDK version supporting them:

| Python Version | Last SDK Version Supporting |
| -------------- |-----------------------------|
| >= 2.0, <= 3.6 | 3.x |

You can determine what version of Python you have installed by running:

```
python --version
```

## Feedback

### Contributing
Expand Down
Loading