fastapi-zitadel-auth


Namefastapi-zitadel-auth JSON
Version 0.1.1 PyPI version JSON
download
home_pageNone
SummaryZitadel authentication for FastAPI
upload_time2024-12-05 15:48:30
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseNone
keywords async asyncio authentication fastapi oauth oidc zitadel
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # FastAPI Zitadel Auth

Simplify OAuth2 authentication in FastAPI apps using [**Zitadel**](https://zitadel.com/) as the identity service, 
including token validation, role-based access control, and Swagger UI integration.


<a href="https://github.com/cleanenergyexchange/fastapi-zitadel-auth/actions/workflows/test.yml" target="_blank">
    <img src="https://github.com/cleanenergyexchange/fastapi-zitadel-auth/actions/workflows/test.yml/badge.svg" alt="Test status">
</a>
<a href="https://codecov.io/gh/cleanenergyexchange/fastapi-zitadel-auth">
    <img src="https://codecov.io/gh/cleanenergyexchange/fastapi-zitadel-auth/graph/badge.svg?token=A3TSXDVLQT" alt="Code coverage"/> 
</a>
<a href="https://pypi.org/pypi/fastapi-zitadel-auth">
    <img src="https://img.shields.io/pypi/v/fastapi-zitadel-auth.svg?logo=pypi&logoColor=white&label=pypi" alt="Package version">
</a>
<a href="https://python.org">
    <img src="https://img.shields.io/badge/python-v3.10+-blue.svg?logo=python&logoColor=white&label=python" alt="Python versions">
</a>
<a href="https://github.com/cleanenergyexchange/fastapi-zitadel-auth/blob/main/LICENSE">
    <img src="https://badgen.net/github/license/cleanenergyexchange/fastapi-zitadel-auth/" alt="License"/>
</a>


## Features

* Authorization Code flow with PKCE
* JWT validation using Zitadel JWKS
* Role-based access control using Zitadel roles
* Service user authentication (JWT Profile)
* Swagger UI integration
* Type-safe token validation


> [!NOTE]
> This library implements JWT, locally validated using JWKS, as it prioritizes performance, 
> see [Zitadel docs on Opaque tokens vs JWT](https://zitadel.com/docs/concepts/knowledge/opaque-tokens#use-cases-and-trade-offs).
> If you need to validate opaque tokens using Introspection, please open an issue – PRs are welcome!


## Installation and quick start

```bash
pip install fastapi-zitadel-auth
```

```python
from fastapi import FastAPI, Security
from fastapi_zitadel_auth import ZitadelAuth, AuthConfig

auth = ZitadelAuth(AuthConfig(
    client_id="your-client-id",
    project_id="your-project-id",
    zitadel_host="https://your-instance.zitadel.cloud"
))

app = FastAPI(
    swagger_ui_init_oauth={
        "usePkceWithAuthorizationCodeGrant": True,
        "clientId": 'your-client-id',
        "scopes": "openid profile email urn:zitadel:iam:org:project:id:zitadel:aud urn:zitadel:iam:org:projects:roles"
    }
)


@app.get("/protected", dependencies=[Security(auth)])
def protected_route():
    return {"message": "Access granted!"}
```

See the [Usage](#usage) section for more details.

## Usage

### Configuration

#### Zitadel

Set up a project in Zitadel according to [docs/ZITADEL_SETUP.md](docs/ZITADEL_SETUP.md).

#### FastAPI

```python
from fastapi import FastAPI, Request, Security
from fastapi_zitadel_auth import ZitadelAuth, AuthConfig

# Your Zitadel configuration
CLIENT_ID = 'your-zitadel-client-id'
PROJECT_ID = 'your-zitadel-project-id'
BASE_URL = 'https://your-instance-xyz.zitadel.cloud'

# Create an AuthConfig object with your Zitadel configuration
config = AuthConfig(
    client_id=CLIENT_ID,
    project_id=PROJECT_ID,
    zitadel_host=BASE_URL,
    scopes={
        "openid": "OpenID Connect",
        "email": "Email",
        "profile": "Profile",
        "urn:zitadel:iam:org:project:id:zitadel:aud": "Audience",
        "urn:zitadel:iam:org:projects:roles": "Roles",
    },
)

# Create a ZitadelAuth object with the AuthConfig usable as a FastAPI dependency
auth = ZitadelAuth(config)

# Create a FastAPI app and configure Swagger UI
app = FastAPI(
    title="fastapi-zitadel-auth demo",
    swagger_ui_oauth2_redirect_url="/oauth2-redirect",
    swagger_ui_init_oauth={
        "usePkceWithAuthorizationCodeGrant": True,
        "clientId": CLIENT_ID,
        "scopes": " ".join(
            [
                "openid",
                "email",
                "profile",
                "urn:zitadel:iam:org:project:id:zitadel:aud",
                "urn:zitadel:iam:org:projects:roles",
            ]
        ),
    },
)


# Create an endpoint and protect it with the ZitadelAuth dependency
@app.get(
    "/api/private",
    summary="Private endpoint, requiring a valid token with `system` scope",
    dependencies=[Security(auth, scopes=["system"])],
)
def private(request: Request):
    return {
        "message": f"Hello, protected world! Here is Zitadel user {request.state.user.user_id}"
    }

```

## Demo app

See `demo_project` for a complete example, including service user login. To run the demo app:

```bash
uv run demo_project/server.py
```

Then navigate to `http://localhost:8001/docs` to see the Swagger UI.


### Service user

Service users are "machine users" in Zitadel.

To log in as a service user, change the config in `demo_project/service_user.py`, then

```bash
uv run demo_project/service_user.py
```

Make sure you have a running server at `http://localhost:8001`.

## Development

See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for development instructions.
            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "fastapi-zitadel-auth",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "async, asyncio, authentication, fastapi, oauth, oidc, zitadel",
    "author": null,
    "author_email": "Clean Energy Exchange <info@ceex.ch>",
    "download_url": "https://files.pythonhosted.org/packages/ef/d3/daca50aa1c99d4931c89f11397fd8305ff0e4c1ceef4e6db9853fc5cdaee/fastapi_zitadel_auth-0.1.1.tar.gz",
    "platform": null,
    "description": "# FastAPI Zitadel Auth\n\nSimplify OAuth2 authentication in FastAPI apps using [**Zitadel**](https://zitadel.com/) as the identity service, \nincluding token validation, role-based access control, and Swagger UI integration.\n\n\n<a href=\"https://github.com/cleanenergyexchange/fastapi-zitadel-auth/actions/workflows/test.yml\" target=\"_blank\">\n    <img src=\"https://github.com/cleanenergyexchange/fastapi-zitadel-auth/actions/workflows/test.yml/badge.svg\" alt=\"Test status\">\n</a>\n<a href=\"https://codecov.io/gh/cleanenergyexchange/fastapi-zitadel-auth\">\n    <img src=\"https://codecov.io/gh/cleanenergyexchange/fastapi-zitadel-auth/graph/badge.svg?token=A3TSXDVLQT\" alt=\"Code coverage\"/> \n</a>\n<a href=\"https://pypi.org/pypi/fastapi-zitadel-auth\">\n    <img src=\"https://img.shields.io/pypi/v/fastapi-zitadel-auth.svg?logo=pypi&logoColor=white&label=pypi\" alt=\"Package version\">\n</a>\n<a href=\"https://python.org\">\n    <img src=\"https://img.shields.io/badge/python-v3.10+-blue.svg?logo=python&logoColor=white&label=python\" alt=\"Python versions\">\n</a>\n<a href=\"https://github.com/cleanenergyexchange/fastapi-zitadel-auth/blob/main/LICENSE\">\n    <img src=\"https://badgen.net/github/license/cleanenergyexchange/fastapi-zitadel-auth/\" alt=\"License\"/>\n</a>\n\n\n## Features\n\n* Authorization Code flow with PKCE\n* JWT validation using Zitadel JWKS\n* Role-based access control using Zitadel roles\n* Service user authentication (JWT Profile)\n* Swagger UI integration\n* Type-safe token validation\n\n\n> [!NOTE]\n> This library implements JWT, locally validated using JWKS, as it prioritizes performance, \n> see [Zitadel docs on Opaque tokens vs JWT](https://zitadel.com/docs/concepts/knowledge/opaque-tokens#use-cases-and-trade-offs).\n> If you need to validate opaque tokens using Introspection, please open an issue \u2013 PRs are welcome!\n\n\n## Installation and quick start\n\n```bash\npip install fastapi-zitadel-auth\n```\n\n```python\nfrom fastapi import FastAPI, Security\nfrom fastapi_zitadel_auth import ZitadelAuth, AuthConfig\n\nauth = ZitadelAuth(AuthConfig(\n    client_id=\"your-client-id\",\n    project_id=\"your-project-id\",\n    zitadel_host=\"https://your-instance.zitadel.cloud\"\n))\n\napp = FastAPI(\n    swagger_ui_init_oauth={\n        \"usePkceWithAuthorizationCodeGrant\": True,\n        \"clientId\": 'your-client-id',\n        \"scopes\": \"openid profile email urn:zitadel:iam:org:project:id:zitadel:aud urn:zitadel:iam:org:projects:roles\"\n    }\n)\n\n\n@app.get(\"/protected\", dependencies=[Security(auth)])\ndef protected_route():\n    return {\"message\": \"Access granted!\"}\n```\n\nSee the [Usage](#usage) section for more details.\n\n## Usage\n\n### Configuration\n\n#### Zitadel\n\nSet up a project in Zitadel according to [docs/ZITADEL_SETUP.md](docs/ZITADEL_SETUP.md).\n\n#### FastAPI\n\n```python\nfrom fastapi import FastAPI, Request, Security\nfrom fastapi_zitadel_auth import ZitadelAuth, AuthConfig\n\n# Your Zitadel configuration\nCLIENT_ID = 'your-zitadel-client-id'\nPROJECT_ID = 'your-zitadel-project-id'\nBASE_URL = 'https://your-instance-xyz.zitadel.cloud'\n\n# Create an AuthConfig object with your Zitadel configuration\nconfig = AuthConfig(\n    client_id=CLIENT_ID,\n    project_id=PROJECT_ID,\n    zitadel_host=BASE_URL,\n    scopes={\n        \"openid\": \"OpenID Connect\",\n        \"email\": \"Email\",\n        \"profile\": \"Profile\",\n        \"urn:zitadel:iam:org:project:id:zitadel:aud\": \"Audience\",\n        \"urn:zitadel:iam:org:projects:roles\": \"Roles\",\n    },\n)\n\n# Create a ZitadelAuth object with the AuthConfig usable as a FastAPI dependency\nauth = ZitadelAuth(config)\n\n# Create a FastAPI app and configure Swagger UI\napp = FastAPI(\n    title=\"fastapi-zitadel-auth demo\",\n    swagger_ui_oauth2_redirect_url=\"/oauth2-redirect\",\n    swagger_ui_init_oauth={\n        \"usePkceWithAuthorizationCodeGrant\": True,\n        \"clientId\": CLIENT_ID,\n        \"scopes\": \" \".join(\n            [\n                \"openid\",\n                \"email\",\n                \"profile\",\n                \"urn:zitadel:iam:org:project:id:zitadel:aud\",\n                \"urn:zitadel:iam:org:projects:roles\",\n            ]\n        ),\n    },\n)\n\n\n# Create an endpoint and protect it with the ZitadelAuth dependency\n@app.get(\n    \"/api/private\",\n    summary=\"Private endpoint, requiring a valid token with `system` scope\",\n    dependencies=[Security(auth, scopes=[\"system\"])],\n)\ndef private(request: Request):\n    return {\n        \"message\": f\"Hello, protected world! Here is Zitadel user {request.state.user.user_id}\"\n    }\n\n```\n\n## Demo app\n\nSee `demo_project` for a complete example, including service user login. To run the demo app:\n\n```bash\nuv run demo_project/server.py\n```\n\nThen navigate to `http://localhost:8001/docs` to see the Swagger UI.\n\n\n### Service user\n\nService users are \"machine users\" in Zitadel.\n\nTo log in as a service user, change the config in `demo_project/service_user.py`, then\n\n```bash\nuv run demo_project/service_user.py\n```\n\nMake sure you have a running server at `http://localhost:8001`.\n\n## Development\n\nSee [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for development instructions.",
    "bugtrack_url": null,
    "license": null,
    "summary": "Zitadel authentication for FastAPI",
    "version": "0.1.1",
    "project_urls": null,
    "split_keywords": [
        "async",
        " asyncio",
        " authentication",
        " fastapi",
        " oauth",
        " oidc",
        " zitadel"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "9095d10813faed0658e20c62d7d416b6725553f7a4e2a13e5a462679ea7f9a7a",
                "md5": "17c09d0731ef5ece04bd4b95de52148b",
                "sha256": "f651acd270cdf5937bcf111c81fbeace1327f96c22aee305f67cb409eea7e2c9"
            },
            "downloads": -1,
            "filename": "fastapi_zitadel_auth-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "17c09d0731ef5ece04bd4b95de52148b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 9604,
            "upload_time": "2024-12-05T15:48:29",
            "upload_time_iso_8601": "2024-12-05T15:48:29.193669Z",
            "url": "https://files.pythonhosted.org/packages/90/95/d10813faed0658e20c62d7d416b6725553f7a4e2a13e5a462679ea7f9a7a/fastapi_zitadel_auth-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "efd3daca50aa1c99d4931c89f11397fd8305ff0e4c1ceef4e6db9853fc5cdaee",
                "md5": "1f33aef0e5ffe8fb69c8d0d175c6fdc2",
                "sha256": "2920d1d2af6a10fcba9b84edc91ff5592e07b7d0f1cef1989d22326dca23f0ef"
            },
            "downloads": -1,
            "filename": "fastapi_zitadel_auth-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "1f33aef0e5ffe8fb69c8d0d175c6fdc2",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 57226,
            "upload_time": "2024-12-05T15:48:30",
            "upload_time_iso_8601": "2024-12-05T15:48:30.220231Z",
            "url": "https://files.pythonhosted.org/packages/ef/d3/daca50aa1c99d4931c89f11397fd8305ff0e4c1ceef4e6db9853fc5cdaee/fastapi_zitadel_auth-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-12-05 15:48:30",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "fastapi-zitadel-auth"
}
        
Elapsed time: 0.39490s