# py-identity-model
![Build](https://github.com/jamescrowley321/py-identity-model/workflows/Build/badge.svg)
![License](https://img.shields.io/pypi/l/py-identity-model)
OIDC helper library. This project is very limited in functionality, but it has been used in production for years as the foundation of Flask/FastAPI middleware implementations.
Does not currently support opaque tokens.
Inspired By:
* [IdentityModel](https://github.com/IdentityModel/IdentityModel)
* [cognitojwt](https://github.com/borisrozumnuk/cognitojwt)
## Examples
### Discovery
Only a subset of fields is currently mapped.
```python
import os
from py_identity_model import DiscoveryDocumentRequest, get_discovery_document
DISCO_ADDRESS = os.environ["DISCO_ADDRESS"]
disco_doc_request = DiscoveryDocumentRequest(address=DISCO_ADDRESS)
disco_doc_response = get_discovery_document(disco_doc_request)
print(disco_doc_response)
```
### JWKs
```python
import os
from py_identity_model import (
DiscoveryDocumentRequest,
get_discovery_document,
JwksRequest,
get_jwks,
)
DISCO_ADDRESS = os.environ["DISCO_ADDRESS"]
disco_doc_request = DiscoveryDocumentRequest(address=DISCO_ADDRESS)
disco_doc_response = get_discovery_document(disco_doc_request)
jwks_request = JwksRequest(address=disco_doc_response.jwks_uri)
jwks_response = get_jwks(jwks_request)
print(jwks_response)
```
### Basic Token Validation
Token validation validates the signature of a JWT against the values provided from an OIDC discovery document. The function will throw an exception if the token is expired or signature validation fails.
Token validation is simply a wrapper on top of the [jose.jwt.decode](https://python-jose.readthedocs.io/en/latest/jwt/api.html#jose.jwt.decode). The configuration object is mapped to the input parameters of `jose.jwt.decode`.
```python
@dataclass
class TokenValidationConfig:
perform_disco: bool
key: Optional[dict] = None
audience: Optional[str] = None
algorithms: Optional[List[str]] = None
issuer: Optional[List[str]] = None
subject: Optional[str] = None
options: Optional[dict] = None
```
```python
import os
from py_identity_model import PyIdentityModelException, validate_token
DISCO_ADDRESS = os.environ["DISCO_ADDRESS"]
token = get_token() # Get the token in the manner best suited to your application
validation_options = {
"verify_signature": True,
"verify_aud": True,
"verify_iat": True,
"verify_exp": True,
"verify_nbf": True,
"verify_iss": True,
"verify_sub": True,
"verify_jti": True,
"verify_at_hash": True,
"require_aud": False,
"require_iat": False,
"require_exp": False,
"require_nbf": False,
"require_iss": False,
"require_sub": False,
"require_jti": False,
"require_at_hash": False,
"leeway": 0,
}
validation_config = TokenValidationConfig(
perform_disco=True,
audience=TEST_AUDIENCE,
options=validation_options
)
claims = validate_token(jwt=token, disco_doc_address=DISCO_ADDRESS)
print(claims)
```
### Token Generation
The only current supported flow is the `client_credentials` flow. Load configuration parameters in the method your application supports. Environment variables are used here for demonstration purposes.
Example:
```python
import os
from py_identity_model import (
ClientCredentialsTokenRequest,
request_client_credentials_token,
get_discovery_document,
DiscoveryDocumentRequest,
)
DISCO_ADDRESS = os.environ["DISCO_ADDRESS"]
CLIENT_ID = os.environ["CLIENT_ID"]
CLIENT_SECRET = os.environ["CLIENT_SECRET"]
SCOPE = os.environ["SCOPE"]
disco_doc_response = get_discovery_document(
DiscoveryDocumentRequest(address=DISCO_ADDRESS)
)
client_creds_req = ClientCredentialsTokenRequest(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
address=disco_doc_response.token_endpoint,
scope=SCOPE,
)
client_creds_token = request_client_credentials_token(client_creds_req)
print(client_creds_token)
```
## Roadmap
These are in no particular order of importance. I am working on this project to bring a library as capable as IdentityModel to the Python ecosystem and will most likely focus on the needful and most used features first.
* Protocol abstractions and constants
* Discovery Endpoint
* Token Endpoint
* Token Introspection Endpoint
* Token Revocation Endpoint
* UserInfo Endpoint
* Dynamic Client Registration
* Device Authorization Endpoint
* Token Validation
* Example integrations with popular providers
* Example middleware implementations for Flask and FastApi
* async Support
* Setup documentation
* Opaque tokens
Raw data
{
"_id": null,
"home_page": "https://github.com/jamescrowley321/py-oidc",
"name": "py-identity-model",
"maintainer": "",
"docs_url": null,
"requires_python": "",
"maintainer_email": "",
"keywords": "OpenID jwt",
"author": "James Crowley",
"author_email": "jamescrowley151@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/cd/dd/7faa930be6dca0bd83ffd540d0ac76cb7bf19a0847ea764c8e78bc371865/py_identity_model-0.11.2.tar.gz",
"platform": "Any",
"description": "# py-identity-model\n![Build](https://github.com/jamescrowley321/py-identity-model/workflows/Build/badge.svg)\n![License](https://img.shields.io/pypi/l/py-identity-model)\n\nOIDC helper library. This project is very limited in functionality, but it has been used in production for years as the foundation of Flask/FastAPI middleware implementations.\n\nDoes not currently support opaque tokens.\n\nInspired By:\n\n* [IdentityModel](https://github.com/IdentityModel/IdentityModel)\n* [cognitojwt](https://github.com/borisrozumnuk/cognitojwt)\n\n## Examples\n\n### Discovery\n\nOnly a subset of fields is currently mapped.\n\n```python\nimport os\n\nfrom py_identity_model import DiscoveryDocumentRequest, get_discovery_document\n\nDISCO_ADDRESS = os.environ[\"DISCO_ADDRESS\"]\n \ndisco_doc_request = DiscoveryDocumentRequest(address=DISCO_ADDRESS)\ndisco_doc_response = get_discovery_document(disco_doc_request) \nprint(disco_doc_response)\n```\n\n### JWKs\n\n```python\nimport os\n\nfrom py_identity_model import (\n DiscoveryDocumentRequest, \n get_discovery_document,\n JwksRequest, \n get_jwks,\n)\n\nDISCO_ADDRESS = os.environ[\"DISCO_ADDRESS\"]\n \ndisco_doc_request = DiscoveryDocumentRequest(address=DISCO_ADDRESS)\ndisco_doc_response = get_discovery_document(disco_doc_request) \n\njwks_request = JwksRequest(address=disco_doc_response.jwks_uri)\njwks_response = get_jwks(jwks_request)\nprint(jwks_response)\n```\n\n### Basic Token Validation\n\nToken validation validates the signature of a JWT against the values provided from an OIDC discovery document. The function will throw an exception if the token is expired or signature validation fails.\n\nToken validation is simply a wrapper on top of the [jose.jwt.decode](https://python-jose.readthedocs.io/en/latest/jwt/api.html#jose.jwt.decode). The configuration object is mapped to the input parameters of `jose.jwt.decode`. \n\n```python\n@dataclass\nclass TokenValidationConfig:\n perform_disco: bool\n key: Optional[dict] = None\n audience: Optional[str] = None\n algorithms: Optional[List[str]] = None\n issuer: Optional[List[str]] = None\n subject: Optional[str] = None\n options: Optional[dict] = None\n```\n\n\n\n```python\nimport os\n\nfrom py_identity_model import PyIdentityModelException, validate_token\n\nDISCO_ADDRESS = os.environ[\"DISCO_ADDRESS\"]\n\ntoken = get_token() # Get the token in the manner best suited to your application\n\nvalidation_options = {\n \"verify_signature\": True,\n \"verify_aud\": True,\n \"verify_iat\": True,\n \"verify_exp\": True,\n \"verify_nbf\": True,\n \"verify_iss\": True,\n \"verify_sub\": True,\n \"verify_jti\": True,\n \"verify_at_hash\": True,\n \"require_aud\": False,\n \"require_iat\": False,\n \"require_exp\": False,\n \"require_nbf\": False,\n \"require_iss\": False,\n \"require_sub\": False,\n \"require_jti\": False,\n \"require_at_hash\": False,\n \"leeway\": 0,\n}\n\nvalidation_config = TokenValidationConfig(\n perform_disco=True,\n audience=TEST_AUDIENCE,\n options=validation_options\n)\n\nclaims = validate_token(jwt=token, disco_doc_address=DISCO_ADDRESS)\nprint(claims)\n```\n\n### Token Generation\n\nThe only current supported flow is the `client_credentials` flow. Load configuration parameters in the method your application supports. Environment variables are used here for demonstration purposes.\n\nExample:\n\n```python\nimport os\n\nfrom py_identity_model import (\n ClientCredentialsTokenRequest,\n request_client_credentials_token,\n get_discovery_document,\n DiscoveryDocumentRequest,\n)\n\nDISCO_ADDRESS = os.environ[\"DISCO_ADDRESS\"]\nCLIENT_ID = os.environ[\"CLIENT_ID\"]\nCLIENT_SECRET = os.environ[\"CLIENT_SECRET\"]\nSCOPE = os.environ[\"SCOPE\"]\n\ndisco_doc_response = get_discovery_document(\n DiscoveryDocumentRequest(address=DISCO_ADDRESS)\n)\n\nclient_creds_req = ClientCredentialsTokenRequest(\n\tclient_id=CLIENT_ID,\n client_secret=CLIENT_SECRET,\n address=disco_doc_response.token_endpoint,\n scope=SCOPE,\n)\nclient_creds_token = request_client_credentials_token(client_creds_req)\nprint(client_creds_token)\n```\n\n## Roadmap\nThese are in no particular order of importance. I am working on this project to bring a library as capable as IdentityModel to the Python ecosystem and will most likely focus on the needful and most used features first.\n* Protocol abstractions and constants\n* Discovery Endpoint\n* Token Endpoint\n* Token Introspection Endpoint\n* Token Revocation Endpoint\n* UserInfo Endpoint\n* Dynamic Client Registration\n* Device Authorization Endpoint\n* Token Validation\n* Example integrations with popular providers\n* Example middleware implementations for Flask and FastApi\n* async Support\n* Setup documentation\n* Opaque tokens\n",
"bugtrack_url": null,
"license": "Apache 2.0",
"summary": "OAuth2.0 and OpenID Connect Client Library",
"version": "0.11.2",
"project_urls": {
"Homepage": "https://github.com/jamescrowley321/py-oidc"
},
"split_keywords": [
"openid",
"jwt"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "cddd7faa930be6dca0bd83ffd540d0ac76cb7bf19a0847ea764c8e78bc371865",
"md5": "574db73794aa586fbd46f2674a729c67",
"sha256": "14d198826eb4692b9bd15af879042f6ffa64478365eb2f502c202bffc2df9263"
},
"downloads": -1,
"filename": "py_identity_model-0.11.2.tar.gz",
"has_sig": false,
"md5_digest": "574db73794aa586fbd46f2674a729c67",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 10973,
"upload_time": "2024-02-24T17:32:55",
"upload_time_iso_8601": "2024-02-24T17:32:55.620257Z",
"url": "https://files.pythonhosted.org/packages/cd/dd/7faa930be6dca0bd83ffd540d0ac76cb7bf19a0847ea764c8e78bc371865/py_identity_model-0.11.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-02-24 17:32:55",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "jamescrowley321",
"github_project": "py-oidc",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "py-identity-model"
}