Easy and secure implementation of Azure AD for your FastAPI APIs 🔒

Overview


FastAPI-Azure-auth

Azure AD Authentication for FastAPI apps made easy.

Python version FastAPI Version Package version

Codecov Pre-commit Black mypy isort

🚀 Description

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python, based on standard Python type hints.

At Intility, FastAPI is a popular framework among its developers, with customer-facing and internal services developed entirely on a FastAPI backend.

This package enables our developers (and you 😊 ) to create features without worrying about authentication and authorization.

Also, we're hiring!

⚡️ Quick start

Azure

Azure docs will be available when create-fastapi-app is developed. In the meantime please use the .NET documentation.

FastAPI

1. Install this library:

pip install fastapi-azure-auth
# or
poetry add fastapi-azure-auth

2. Configure your FastAPI app

Include swagger_ui_oauth2_redirect_url and swagger_ui_init_oauth in your FastAPI app initialization:

# file: main.py
app = FastAPI(
    ...
    swagger_ui_oauth2_redirect_url='/oauth2-redirect',
    swagger_ui_init_oauth={
        'usePkceWithAuthorizationCodeGrant': True, 
        'clientId': settings.OPENAPI_CLIENT_ID  # SPA app with grants to your app
    },
)

3. Setup CORS

Ensure you have CORS enabled for your local environment, such as http://localhost:8000. See main.py and the BACKEND_CORS_ORIGINS in config.py

4. Configure the AzureAuthorizationCodeBearer

You can do this in main.py, but it's recommended to put it in your dependencies.py file instead, as this will avoid circular imports later. See the demo project and read the official documentation on bigger applications

# file: demoproj/api/dependencies.py
from fastapi_azure_auth.auth import AzureAuthorizationCodeBearer

azure_scheme = AzureAuthorizationCodeBearer(
    app=app,
    app_client_id=settings.APP_CLIENT_ID,  # Web app
    scopes={
        f'api://{settings.APP_CLIENT_ID}/user_impersonation': 'User Impersonation',
    },
)

5. Configure dependencies

Set your intility_scheme as a dependency for your wanted views/routers:

# file: main.py
from demoproj.api.dependencies import azure_scheme

app.include_router(api_router, prefix=settings.API_V1_STR, dependencies=[Depends(azure_scheme)])

6. Load config on startup

This is optional but recommended. This will ensure the app crashes if something is misconfigured on startup (instead of when someone tries to do a request), and ensures the first request don't have to wait for the provider config to load.

# file: main.py
from fastapi_azure_auth.provider_config import provider_config

@app.on_event('startup')
async def load_config() -> None:
    """
    Load config on startup.
    """
    await provider_config.load_config()

⚙️ Configuration

For those using a non-Intility tenant, you also need to make changes to the provider_config to match your tenant ID. You can do this in your previously created load_config() function.

# file: main.py
from fastapi_azure_auth.provider_config import provider_config

@app.on_event('startup')
async def load_config() -> None:
    provider_config.tenant_id = 'my-own-tenant-id'
    await provider_config.load_config()

If you want, you can deny guest users to access your API by passing the allow_guest_users=False to AzureAuthorizationCodeBearer:

# file: demoproj/api/dependencies.py
azure_scheme = AzureAuthorizationCodeBearer(
    ...
    allow_guest_users=False
)

💡 Nice to knows

User object

A User object is attached to the request state if the token is valid. Unparsed claims can be accessed at request.state.user.claims.

# file: demoproj/api/api_v1/endpoints/hello_world.py
from fastapi_azure_auth.user import User
from fastapi import Request

@router.get(...)
async def world(request: Request) -> dict:
    user: User = request.state.user
    return {'user': user}

Permission checking

You often want to check that a user has a role or using a specific scope. This can be done by creating your own dependency, which depends on azure_scheme. The azure_scheme dependency returns a fastapi_azure_auth.user.User object.

Create your new dependency, which checks that the user has the correct role (in this case the AdminUser-role):

# file: demoproj/api/dependencies.py
from fastapi import Depends
from fastapi_azure_auth.auth import InvalidAuth
from fastapi_azure_auth.user import User

async def validate_is_admin_user(user: User = Depends(azure_scheme)) -> None:
    """
    Validated that a user is in the `AdminUser` role in order to access the API.
    Raises a 401 authentication error if not.
    """
    if 'AdminUser' not in user.roles:
        raise InvalidAuth('User is not an AdminUser')

Add the new dependency on either your route or on the API, as we've done in our demo project.

Comments
  • Feature/b2c support

    Feature/b2c support

    Added support for tokens without x5c fields, and added optional openid_config_url override, this would close #46

    Not all tests are working yet, not sure if that is due to the code itself or due to the test config

    opened by robteeuwen 18
  • B2C token does not contain `tid` in the token

    B2C token does not contain `tid` in the token

    I've managed to set up B2C, but it doesn't seem to return tid in the token. Everything else is working.

    I'm not sure how to confirm if everything is working well (I might have to contact microsoft), but if B2C doesn't return tid, would it make sense to make it optional in the User model?

    question 
    opened by marcinplatek 17
  • [BUG] TypeError at library import (Python 3.9.1)

    [BUG] TypeError at library import (Python 3.9.1)

    Describe the bug I'm new to Python/FastAPI, so it is very well possible that it's just me doing something wrong, but my code fails to compile as soon as I add the line to import either SingleTenantAzureAuthorizationCodeBearer or MultiTenantAzureAuthorizationCodeBearer and I'm getting this error: TypeError: unhashable type: 'list'

    First I thought it's related to my already written code, so I've started a clean project and followed the tutorial in the documentation, but that also fails as soon as I add the import line. So I'm completely lost here.

    I'm using Python 3.9.1 and FastAPI 0.74.1

    To Reproduce Add code line: from fastapi_azure_auth import SingleTenantAzureAuthorizationCodeBearer

    Stack trace

    Traceback (most recent call last):
      File "c:\program files\python39\lib\runpy.py", line 197, in _run_module_as_main
        return _run_code(code, main_globals, None,
      File "c:\program files\python39\lib\runpy.py", line 87, in _run_code
        exec(code, run_globals)
      File "C:\Users\...\AppData\Roaming\Python\Python39\Scripts\uvicorn.exe\__main__.py", line 7, in <module>
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\click\core.py", line 1137, in __call__
        return self.main(*args, **kwargs)
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\click\core.py", line 1062, in main
        rv = self.invoke(ctx)
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\click\core.py", line 1404, in invoke
        return ctx.invoke(self.callback, **ctx.params)
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\click\core.py", line 763, in invoke
        return __callback(*args, **kwargs)
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\uvicorn\main.py", line 435, in main
        run(app, **kwargs)
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\uvicorn\main.py", line 461, in run
        server.run()
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\uvicorn\server.py", line 60, in run
        return asyncio.run(self.serve(sockets=sockets))
      File "c:\program files\python39\lib\asyncio\runners.py", line 44, in run
        return loop.run_until_complete(main)
      File "c:\program files\python39\lib\asyncio\base_events.py", line 642, in run_until_complete
        return future.result()
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\uvicorn\server.py", line 67, in serve
        config.load()
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\uvicorn\config.py", line 458, in load
        self.loaded_app = import_from_string(self.app)
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\uvicorn\importer.py", line 21, in import_from_string
        module = importlib.import_module(module_str)
      File "c:\program files\python39\lib\importlib\__init__.py", line 127, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
      File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
      File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
      File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
      File "<frozen importlib._bootstrap_external>", line 790, in exec_module
      File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
      File ".\main.py", line 7, in <module>
        from fastapi_azure_auth import SingleTenantAzureAuthorizationCodeBearer
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\fastapi_azure_auth\__init__.py", line 1, in <module>
        from fastapi_azure_auth.auth import (  # noqa: F401
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\fastapi_azure_auth\auth.py", line 20, in <module>
        class AzureAuthorizationCodeBearerBase(SecurityBase):
      File "C:\Users\...\AppData\Roaming\Python\Python39\site-packages\fastapi_azure_auth\auth.py", line 29, in AzureAuthorizationCodeBearerBase
        iss_callable: Optional[Callable[[str], Awaitable[str]]] = None,
      File "c:\program files\python39\lib\typing.py", line 262, in inner
        return func(*args, **kwds)
      File "c:\program files\python39\lib\typing.py", line 339, in __getitem__
        return self._getitem(self, parameters)
      File "c:\program files\python39\lib\typing.py", line 463, in Optional
        return Union[arg, type(None)]
      File "c:\program files\python39\lib\typing.py", line 262, in inner
        return func(*args, **kwds)
      File "c:\program files\python39\lib\typing.py", line 339, in __getitem__
        return self._getitem(self, parameters)
      File "c:\program files\python39\lib\typing.py", line 451, in Union
        parameters = _remove_dups_flatten(parameters)
      File "c:\program files\python39\lib\typing.py", line 231, in _remove_dups_flatten
        return tuple(_deduplicate(params))
      File "c:\program files\python39\lib\typing.py", line 205, in _deduplicate
        all_params = set(params)
    TypeError: unhashable type: 'list'
    

    Your configuration Exactly the same as the tutorial here: https://intility.github.io/fastapi-azure-auth/single-tenant/fastapi_configuration

    bug 
    opened by ravaszf 17
  • [BUG/Question] Cross-origin token redemption is permitted only for the 'Single-Page Application' client-type.

    [BUG/Question] Cross-origin token redemption is permitted only for the 'Single-Page Application' client-type.

    Describe the bug

    Auth error
    Error: Bad Request,
    error: invalid_request,
    description: AADSTS9002326: Cross-origin token redemption is permitted only for the 'Single-Page Application' client-type.
    

    To Reproduce

    This is the minimal FastAPI app:

    from pydantic import AnyHttpUrl, BaseSettings, Field
    from fastapi.middleware.cors import CORSMiddleware
    from typing import Union
    
    class Settings(BaseSettings):
        SECRET_KEY: str = Field('my super secret key', env='SECRET_KEY')
        BACKEND_CORS_ORIGINS: list[Union[str, AnyHttpUrl]] = ['http://localhost:8000']
        OPENAPI_CLIENT_ID: str = Field(default='', env='OPENAPI_CLIENT_ID')
        APP_CLIENT_ID: str = Field(default='', env='APP_CLIENT_ID')
        TENANT_ID: str = Field(default='', env='TENANT_ID')
    
        class Config:
            env_file = '.env'
            env_file_encoding = 'utf-8'
            case_sensitive = True
    
    from fastapi import FastAPI
    
    settings = Settings()
    app = FastAPI()
    
    settings = Settings()
    if settings.BACKEND_CORS_ORIGINS:
        app.add_middleware(
            CORSMiddleware,
            allow_origins=[str(origin) for origin in settings.BACKEND_CORS_ORIGINS],
            allow_credentials=True,
            allow_methods=['*'],
            allow_headers=['*'],
        )
    
    app = FastAPI(
        swagger_ui_oauth2_redirect_url='/oauth2-redirect',
        swagger_ui_init_oauth={
            'usePkceWithAuthorizationCodeGrant': True,
            'clientId': settings.OPENAPI_CLIENT_ID,
        })
    
    from fastapi_azure_auth import SingleTenantAzureAuthorizationCodeBearer
    
    azure_scheme = SingleTenantAzureAuthorizationCodeBearer(
        app_client_id=settings.APP_CLIENT_ID,
        tenant_id=settings.TENANT_ID,
        scopes={
            #"User.ReadBasic.All": 'read'
            'https://graph.microsoft.com/.default': 'default'
            #AADSTS70011
            #f'api://{settings.APP_CLIENT_ID}/user_impersonation': 'user_impersonation',
        })
    
    @app.on_event('startup')
    async def load_config() -> None:
        """    Load OpenID config on startup.    """
        await azure_scheme.openid_config.load_config()
    
    from fastapi import Security, responses
    
    @app.get("/", dependencies=[Security(azure_scheme, scopes=["default"])])
    def read_root():
        """
        Redirects to /docs
        """
        return "It works."
    

    Please, set the following envars:

    export TENANT_ID=<your-tenant_id>
    export OPENAPI_CLIENT_ID=<your-client_id>
    export APP_CLIENT_ID="https://login.microsoftonline.com/$TENANT_ID"
    export SECRET_KEY=<your-secret>
    

    Steps to reproduce the behavior:

    1. Go to http://localhost:8000/docs
    2. Click in 'Autorize'
    3. Leave client_secret blank, and select scopes
    4. Click in 'Autorize', the page will return the error

    Configuration

    I believe this bug is related to my Azure AD set up, so may provide the Manifest from AD. Sensitive information is hidden and the <CENSORED> is put in place.

    {
    	"id": "<CENSORED>",
    	"acceptMappedClaims": null,
    	"accessTokenAcceptedVersion": 2,
    	"addIns": [],
    	"allowPublicClient": false,
    	"appId": "<CENSORED>",
    	"appRoles": [],
    	"oauth2AllowUrlPathMatching": false,
    	"createdDateTime": "2022-01-11T19:43:15Z",
    	"description": null,
    	"certification": null,
    	"disabledByMicrosoftStatus": null,
    	"groupMembershipClaims": null,
    	"identifierUris": [],
    	"informationalUrls": {
    		"termsOfService": null,
    		"support": null,
    		"privacy": null,
    		"marketing": null
    	},
    	"keyCredentials": [],
    	"knownClientApplications": [],
    	"logoUrl": null,
    	"logoutUrl": "https://localhost:8000/oauth2-redirect",
    	"name": "backoffice",
    	"notes": null,
    	"oauth2AllowIdTokenImplicitFlow": true,
    	"oauth2AllowImplicitFlow": true,
    	"oauth2Permissions": [],
    	"oauth2RequirePostResponse": false,
    	"optionalClaims": null,
    	"orgRestrictions": [],
    	"parentalControlSettings": {
    		"countriesBlockedForMinors": [],
    		"legalAgeGroupRule": "Allow"
    	},
    	"passwordCredentials": [
    		{
    			"customKeyIdentifier": null,
    			"endDate": "2022-04-21T17:02:20.006Z",
    			"keyId": "<CENSORED>",
    			"startDate": "2022-01-21T17:02:20.006Z",
    			"value": null,
    			"createdOn": "2022-01-21T17:02:31.8956842Z",
    			"hint": ".F7",
    			"displayName": "API-Test"
    		}
    	],
    	"preAuthorizedApplications": [],
    	"publisherDomain": "<CENSORED>",
    	"replyUrlsWithType": [
    		{
    			"url": "http://localhost:8000/",
    			"type": "Web"
    		},
    		{
    			"url": "http://localhost:8000/oauth2-redirect",
    			"type": "Web"
    		},
    	],
    	"requiredResourceAccess": [
    		{
    			"resourceAppId": "00000003-0000-0000-c000-000000000000",
    			"resourceAccess": [
    				{
    					"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
    					"type": "Scope"
    				},
    				{
    					"id": "14dad69e-099b-42c9-810b-d002981feec1",
    					"type": "Scope"
    				}
    			]
    		}
    	],
    	"samlMetadataUrl": null,
    	"serviceManagementReference": null,
    	"signInUrl": null,
    	"signInAudience": "AzureADMyOrg",
    	"tags": [],
    	"tokenEncryptionKeyId": null
    }
    
    question 
    opened by Vido 17
  • [Question] Login integration

    [Question] Login integration

    First, thank you for the library it's great!

    Would be nice to see a very basic integration between the library and a logging endpoint in order to understand the integration with the library in that process.

    I can logging with the Fastapi docs but not from my app. I feel I'm reinventing the wheel trying to do the authentication steps. I'm ending creating my own functions try to follow the oath2 flow.

    Thanks!

    question 
    opened by productoptimization 12
  • Update the _types module to primitives types

    Update the _types module to primitives types

    This is a change in the way the hazmat section of the cryptography module is organized. This fixes the error received when using the most up to date version of cryptography (at the date of writing).

    Close #25

    opened by bmoore 9
  • Support Python 3.8

    Support Python 3.8

    Following is the summary of changes done -

    1. Using type hints from typing library instead of built-in type hints introduced in python 3.9.

    2. Using older way to concatenate 2 dictionaries instead of newer one.

    Example of older way to concatenate 2 dictionaries -> dmerged = {**d1,**d2}, here d1 and d2 are 2 dictionaries, merged into 1 as dmerged

    Close #74

    opened by manupatel007 8
  • [Documentation]: Suggested update in walkthrough

    [Documentation]: Suggested update in walkthrough

    Describe the issue (https://intility.github.io/fastapi-azure-auth/single-tenant/azure_setup#step-4---allow-openapi-to-talk-to-the-backend)

    There should be one final step on this walk through. Azure has added another section under "Exposing an API" called "Authorized client applications". If you do not link the OpenAPI back to the original application, the end-user will be prompted to request consent from an administrator.

    To Reproduce Manually go through the Single Tenant walkthrough (https://intility.github.io/fastapi-azure-auth/single-tenant/). Once fully complete, any attempt to log into Azure via OpenAPI will send the end-user to a page, as described below:

    Selection_030

    Fix This is so the end-user doesn't see this prompt. 1.) Go to "Expose an API" under your Sample application (not the OpenAPI). 2.) Under "Authorized client applications" click "Add a client application"

    Selection_029

    3.) Copy the Application Id from your 'Sample - OpenAPI' into the 'Client ID' field. 4.) Select the exposed 'api://*' check box 5.) Click "Add Application"

    Now when you click "Authorize"/"Login" via SwaggerUI, the end user will no longer require Admin consent.

    I hope this helps, -Brian

    documentation good first issue 
    opened by bkmetzler 8
  • [BUG] AttributeError: partially initialized module 'anyio._backends._asyncio' has no attribute 'Event'

    [BUG] AttributeError: partially initialized module 'anyio._backends._asyncio' has no attribute 'Event'

    Describe the bug

    We are seeing this error reported in our sentry for a FastApi Azure function based on https://github.com/ecerami/fastapi_azure and fastapi-azure-auth

    partially initialized module 'anyio._backends._asyncio' has no attribute 'Event' (most likely due to a circular import)

    see https://github.com/Intility/fastapi-azure-auth/blob/main/fastapi_azure_auth/openid_config.py#L55

    To Reproduce

    Not sure how to reproduce, it only happens occasionally. Our app is still in early phase and does not see real traffic.

    Stack trace

    AttributeError: partially initialized module 'anyio._backends._asyncio' has no attribute 'Event' (most likely due to a circular import)
      File "fastapi_azure_auth/openid_config.py", line 79, in _load_openid_config
        openid_response = await client.get(config_url)
      File "httpx/_client.py", line 1729, in get
        return await self.request(
      File "httpx/_client.py", line 1506, in request
        return await self.send(request, auth=auth, follow_redirects=follow_redirects)
      File "httpx/_client.py", line 1593, in send
        response = await self._send_handling_auth(
      File "httpx/_client.py", line 1621, in _send_handling_auth
        response = await self._send_handling_redirects(
      File "httpx/_client.py", line 1658, in _send_handling_redirects
        response = await self._send_single_request(request)
      File "httpx/_client.py", line 1695, in _send_single_request
        response = await transport.handle_async_request(request)
      File "httpx/_transports/default.py", line 353, in handle_async_request
        resp = await self._pool.handle_async_request(req)
      File "httpcore/_async/connection_pool.py", line 216, in handle_async_request
        status = RequestStatus(request)
      File "httpcore/_async/connection_pool.py", line 19, in __init__
        self._connection_acquired = AsyncEvent()
      File "httpcore/_synchronization.py", line 29, in __init__
        self._event = anyio.Event()
      File "anyio/_core/_synchronization.py", line 77, in __new__
        return get_asynclib().Event()
    
    AttributeError: partially initialized module 'anyio._backends._asyncio' has no attribute 'checkpoint_if_cancelled' (most likely due to a circular import)
      File "fastapi_azure_auth/openid_config.py", line 42, in load_config
        await self._load_openid_config()
      File "fastapi_azure_auth/openid_config.py", line 91, in _load_openid_config
        self._load_keys(jwks_response.json()['keys'])
      File "httpx/_client.py", line 1975, in __aexit__
        await self._transport.__aexit__(exc_type, exc_value, traceback)
      File "httpx/_transports/default.py", line 332, in __aexit__
        await self._pool.__aexit__(exc_type, exc_value, traceback)
      File "httpcore/_async/connection_pool.py", line 326, in __aexit__
        await self.aclose()
      File "httpcore/_async/connection_pool.py", line 303, in aclose
        async with self._pool_lock:
      File "httpcore/_synchronization.py", line 15, in __aenter__
        await self._lock.acquire()
      File "anyio/_core/_synchronization.py", line 117, in acquire
        await checkpoint_if_cancelled()
      File "anyio/lowlevel.py", line 42, in checkpoint_if_cancelled
        await get_asynclib().checkpoint_if_cancelled()
    
    RuntimeError: Unable to fetch provider information. partially initialized module 'anyio._backends._asyncio' has no attribute 'checkpoint_if_cancelled' (most likely due to a circular import)
      File "starlette/exceptions.py", line 93, in __call__
        raise exc
      File "starlette/exceptions.py", line 82, in __call__
        await self.app(scope, receive, sender)
      File "fastapi/middleware/asyncexitstack.py", line 21, in __call__
        raise e
      File "fastapi/middleware/asyncexitstack.py", line 18, in __call__
        await self.app(scope, receive, send)
      File "starlette/routing.py", line 670, in __call__
        await route.handle(scope, receive, send)
      File "starlette/routing.py", line 418, in handle
        await self.app(scope, receive, send)
      File "fastapi/applications.py", line 269, in __call__
        await super().__call__(scope, receive, send)
      File "starlette/applications.py", line 124, in __call__
        await self.middleware_stack(scope, receive, send)
      File "starlette/middleware/errors.py", line 184, in __call__
        raise exc
      File "starlette/middleware/errors.py", line 162, in __call__
        await self.app(scope, receive, _send)
      File "starlette/exceptions.py", line 93, in __call__
        raise exc
      File "starlette/exceptions.py", line 82, in __call__
        await self.app(scope, receive, sender)
      File "fastapi/middleware/asyncexitstack.py", line 21, in __call__
        raise e
      File "fastapi/middleware/asyncexitstack.py", line 18, in __call__
        await self.app(scope, receive, send)
      File "starlette/routing.py", line 670, in __call__
        await route.handle(scope, receive, send)
      File "starlette/routing.py", line 266, in handle
        await self.app(scope, receive, send)
      File "starlette/routing.py", line 65, in app
        response = await func(request)
      File "fastapi/routing.py", line 217, in app
        solved_result = await solve_dependencies(
      File "fastapi/dependencies/utils.py", line 524, in solve_dependencies
        solved = await call(**sub_values)
      File "fastapi_azure_auth/auth.py", line 151, in __call__
        await self.openid_config.load_config()
      File "fastapi_azure_auth/openid_config.py", line 55, in load_config
        raise RuntimeError(f'Unable to fetch provider information. {error}') from error
    

    Your configuration

    class AuthSettings(BaseSettings):
        SECRET_KEY: str = Field("secret key", env="SECRET_KEY")
        BACKEND_CORS_ORIGINS: list[Union[str, AnyHttpUrl]] = [
            "http://localhost:7071",
            "http://localhost:8000",
            "https://foo.azurewebsites.net",
        ]
        OPENAPI_CLIENT_ID: str = Field(default="", env="OPENAPI_CLIENT_ID")
        APP_CLIENT_ID: str = Field(default="", env="APP_CLIENT_ID")
        TENANT_ID: str = Field(default="", env="TENANT_ID")
    
        class Config:
            env_file = "settings.env"
            env_file_encoding = "utf-8"
            case_sensitive = True
    
    
    auth_settings = AuthSettings()
    
    
    class FastAPISettings(BaseSettings):
        debug: bool = Field(default=False, env="DEBUG")
        title: str = "Foo"
        description: str = (
            "..."
        )
        version: str = "0.0.1"
        contact: dict = {
            "name": "Foo",
        }
        swagger_ui_oauth2_redirect_url: str = "/oauth2-redirect"
        swagger_ui_init_oauth: dict = {
            "usePkceWithAuthorizationCodeGrant": True,
            "clientId": auth_settings.OPENAPI_CLIENT_ID,
        }
    
        class Config:
            env_file = "settings.env"
    
    
    azure_scheme = SingleTenantAzureAuthorizationCodeBearer(
        app_client_id=auth_settings.APP_CLIENT_ID,
        tenant_id=auth_settings.TENANT_ID,
        scopes={
            f"api://{auth_settings.APP_CLIENT_ID}/user_impersonation": "user_impersonation",
        },
    )
    
    
    question 
    opened by martin-greentrax 7
  • Working Solution for B2C MultiTenant

    Working Solution for B2C MultiTenant

    This is a working copy for B2C Multitenant. It's still not perfect but this is not a bad start to push this project forward! Love it! Thanks @JonasKs !

    Have to add a couple of more tests in future PRs.

    Hope you like it.

    opened by kristiqntashev 6
  • Auth with React

    Auth with React

    Describe the bug

    Hey all, Thanks for a great library! I have with success implemented the auth workflow with FastAPI and OpenAPI following your documentation I have a React frontend that needs to talk to the FastAPI backend and I have trouble getting it to work. I use the "@azure/msal-browser" package to get the access token in React, but when I send it in the header to FastAPI I get the following error:

    Traceback (most recent call last):
       File "/app/.local/lib/python3.9/site-packages/fastapi_azure_auth/auth.py", line 183, in __call__
         token = jwt.decode(
       File "/app/.local/lib/python3.9/site-packages/jose/jwt.py", line 144, in decode
         raise JWTError(e)
     jose.exceptions.JWTError: Signature verification failed.
     INFO:     127.0.0.1:36092 - "GET /api/project/a833b3ff30 HTTP/1.1" 401 Unauthorized
    

    I have followed the same steps as for OpenAPI to setup my React SPA in Azure.

    To Reproduce

    1. Go to React UI
    2. Login to Azure
    3. Catch the token from the callback
    4. Set the token in the header
    5. Call FastAPI

    Stack trace

    [backend] INFO:     127.0.0.1:36088 - "OPTIONS /api/project/a833b3ff30 HTTP/1.1" 200 OK
    [backend] 2022-04-21 12:40:18,023 WARNING fastapi_azure_auth __call__() Malformed token received. null. Error: Error decoding token headers.
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 176, in _load
    [backend]     signing_input, crypto_segment = jwt.rsplit(b".", 1)
    [backend] ValueError: not enough values to unpack (expected 2, got 1)
    [backend] 
    [backend] During handling of the above exception, another exception occurred:
    [backend] 
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jwt.py", line 183, in get_unverified_header
    [backend]     headers = jws.get_unverified_headers(token)
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 109, in get_unverified_headers
    [backend]     return get_unverified_header(token)
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 90, in get_unverified_header
    [backend]     header, claims, signing_input, signature = _load(token)
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 180, in _load
    [backend]     raise JWSError("Not enough segments")
    [backend] jose.exceptions.JWSError: Not enough segments
    [backend] 
    [backend] During handling of the above exception, another exception occurred:
    [backend] 
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/fastapi_azure_auth/auth.py", line 136, in __call__
    [backend]     header: dict[str, str] = jwt.get_unverified_header(token=access_token) or {}
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jwt.py", line 185, in get_unverified_header
    [backend]     raise JWTError("Error decoding token headers.")
    [backend] jose.exceptions.JWTError: Error decoding token headers.
    [backend] INFO:     127.0.0.1:36088 - "GET /api/project/a833b3ff30 HTTP/1.1" 401 Unauthorized
    [backend] 2022-04-21 12:40:18,150 WARNING fastapi_azure_auth __call__() Invalid token. Error: Signature verification failed.
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 262, in _verify_signature
    [backend]     raise JWSSignatureError()
    [backend] jose.exceptions.JWSSignatureError
    [backend] 
    [backend] During handling of the above exception, another exception occurred:
    [backend] 
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jwt.py", line 142, in decode
    [backend]     payload = jws.verify(token, key, algorithms, verify=verify_signature)
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 73, in verify
    [backend]     _verify_signature(signing_input, header, signature, key, algorithms)
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 264, in _verify_signature
    [backend]     raise JWSError("Signature verification failed.")
    [backend] jose.exceptions.JWSError: Signature verification failed.
    [backend] 
    [backend] During handling of the above exception, another exception occurred:
    [backend] 
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/fastapi_azure_auth/auth.py", line 183, in __call__
    [backend]     token = jwt.decode(
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jwt.py", line 144, in decode
    [backend]     raise JWTError(e)
    [backend] jose.exceptions.JWTError: Signature verification failed.
    [backend] INFO:     127.0.0.1:36088 - "GET /api/project/a833b3ff30 HTTP/1.1" 401 Unauthorized
    [backend] 2022-04-21 12:43:06,084 WARNING fastapi_azure_auth __call__() Malformed token received. null. Error: Error decoding token headers.
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 176, in _load
    [backend]     signing_input, crypto_segment = jwt.rsplit(b".", 1)
    [backend] ValueError: not enough values to unpack (expected 2, got 1)
    [backend] 
    [backend] During handling of the above exception, another exception occurred:
    [backend] 
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jwt.py", line 183, in get_unverified_header
    [backend]     headers = jws.get_unverified_headers(token)
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 109, in get_unverified_headers
    [backend]     return get_unverified_header(token)
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 90, in get_unverified_header
    [backend]     header, claims, signing_input, signature = _load(token)
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 180, in _load
    [backend]     raise JWSError("Not enough segments")
    [backend] jose.exceptions.JWSError: Not enough segments
    [backend] 
    [backend] During handling of the above exception, another exception occurred:
    [backend] 
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/fastapi_azure_auth/auth.py", line 136, in __call__
    [backend]     header: dict[str, str] = jwt.get_unverified_header(token=access_token) or {}
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jwt.py", line 185, in get_unverified_header
    [backend]     raise JWTError("Error decoding token headers.")
    [backend] jose.exceptions.JWTError: Error decoding token headers.
    [backend] INFO:     127.0.0.1:36092 - "GET /api/project/a833b3ff30 HTTP/1.1" 401 Unauthorized
    [backend] 2022-04-21 12:43:06,334 WARNING fastapi_azure_auth __call__() Invalid token. Error: Signature verification failed.
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 262, in _verify_signature
    [backend]     raise JWSSignatureError()
    [backend] jose.exceptions.JWSSignatureError
    [backend] 
    [backend] During handling of the above exception, another exception occurred:
    [backend] 
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jwt.py", line 142, in decode
    [backend]     payload = jws.verify(token, key, algorithms, verify=verify_signature)
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 73, in verify
    [backend]     _verify_signature(signing_input, header, signature, key, algorithms)
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jws.py", line 264, in _verify_signature
    [backend]     raise JWSError("Signature verification failed.")
    [backend] jose.exceptions.JWSError: Signature verification failed.
    [backend] 
    [backend] During handling of the above exception, another exception occurred:
    [backend] 
    [backend] Traceback (most recent call last):
    [backend]   File "/app/.local/lib/python3.9/site-packages/fastapi_azure_auth/auth.py", line 183, in __call__
    [backend]     token = jwt.decode(
    [backend]   File "/app/.local/lib/python3.9/site-packages/jose/jwt.py", line 144, in decode
    [backend]     raise JWTError(e)
    [backend] jose.exceptions.JWTError: Signature verification failed.
    [backend] INFO:     127.0.0.1:36092 - "GET /api/project/a833b3ff30 HTTP/1.1" 401 Unauthorized
    
    
    question 
    opened by ocni-dtu 6
  • Scopes missing in /docs at each endpoint padlock

    Scopes missing in /docs at each endpoint padlock

    Describe the bug Scopes are missing if we select padlock symbol next to each api endpoint while trying to authorize. they do appear when we select authorize button at the top.

    To Reproduce use below azure scheme

    azure_scheme = SingleTenantAzureAuthorizationCodeBearer(
        app_client_id=settings.APP_CLIENT_ID,
        tenant_id=settings.TENANT_ID,
        scopes={
            f'api://{settings.APP_CLIENT_ID}/user_impersonation': 'user_impersonation',
        }
    )
    

    use this scheme as a dependency to your endpoint

    app.include_router(api_router, prefix=settings.API_V1_STR, dependencies=[Security(azure_scheme, scopes=['user_impersonation'])])
    

    go to /docs image

    you can see scopes when you click authorize button

    image

    if you click on padlock below scopes are missing

    image image

    and unable to authorize as I am getting below error..

    image

    waiting 
    opened by Pkumar-1988 5
  • Add OBO middleware [Feature request]

    Add OBO middleware [Feature request]

    Describe the feature you'd like It would be nice to have the framework allow more than one API scope. The case where this is needed, is if you have multiple business applications that need access to the same API. (For example like how both Teams and Outlook has access to your calendar). Features like this is supported in .NET frameworks by making a list of valid isuers and audiences, instead of enforcing just one (see this StackOverflow example for how the .NET AddJwtBearer middleware works)

    The "correct way" of dealing with these cases is to add middleware implementing the OBO ("On-Behalf-Of") flow. Usually this is handled by the client, but for third party applications and/or plugins, we cannot initiate OBO client-side.

    Additional context If I supply an access token with an audience that I've added to the my application's knownClientApplications list, the token validation should pass.

    enhancement 
    opened by lassebass 7
  • Improve tests

    Improve tests

    This PR is regarding only improving the UnitTests(adding some parametrized tests). Keep in mind behavior and the number of the tests are the same. Just removing not needed noise in the code.

    Directly reject it if doesn't look reasonable to you.

    opened by kristiqntashev 10
  • [Docs] Recipe to mock a logged-in user/Active Directory roles for testing

    [Docs] Recipe to mock a logged-in user/Active Directory roles for testing

    We are using this to keep the unit tests small and simple and I thought it may be helpful for others. Based on the username and the assigned ActiveDirectory role users have different permissions in the system. For a convenient way of testing this we can now mock any logged in user per-request:

    Example test:

    def test_readonly_user_may_not_write(client):
        with mockuser(user_name="[email protected]", roles=["foo.read"]):
            response = client.post("/somemodel", json={})
        assert response.status_code == 403
    
    

    The setup:

    in the routes:

    def prepare_user(request: Request, db: Session = Depends(get_db)):
        """
        On each request the azure authenticated user is used for local user lookup.
        When not found it will be created. The db user object is then stored in `request.state` for easy access.
        """
        if not hasattr(request.state, "user"):
            raise HTTPException(403, detail="No user information found in request object.")
        email: EmailStr = request.state.user.claims["preferred_username"]  # logged in azure user
        request.state.user_obj = UserRepo.get_or_create(db, email)
    
    router = APIRouter(dependencies=[Security(azure_scheme), Depends(prepare_user)])
    

    conftest.py

    class mockuser(ContextDecorator):
        """
        Mock any username and role(s) for api requests as if they would come directly from the real
        Azure Auth integration.
        """
    
        def __init__(self, user_name="[email protected]", roles=["Bar.readonly"]):
            self.user_name = user_name
            self.roles = roles
    
        def __enter__(self):
            def mock_prepare_user(request: fastapi.Request, db: Session = fastapi.Depends(get_db)):
                request.state.user = User(
                    claims={"preferred_username": self.user_name}, roles=self.roles,
                    aud="aud", tid="tid", access_token="123"
                )
                return prepare_user(request, db)
    
            fastapi_app.dependency_overrides[prepare_user] = mock_prepare_user
            fastapi_app_internal.dependency_overrides[prepare_user] = mock_prepare_user
    
        def __exit__(self, type, value, traceback):
            del fastapi_app.dependency_overrides[prepare_user]
            del fastapi_app_internal.dependency_overrides[prepare_user]
    
    
    class staffuser(mockuser):
        """Mock a staff user sending an api request."""
        def __init__(self):
            super().__init__(user_name="[email protected] roles=["yourcompany.superuser"])
    
    
    documentation enhancement 
    opened by martin-greentrax 2
  • [Feature request] oauth2-redirect outside local development

    [Feature request] oauth2-redirect outside local development

    The documentation is sufficient for building an API that runs in a local development environment - but I suppose that setting oauth2-redirect to a real domain instead of localhost is a common use case outside local development. Suppose the API is hosted somewhere (kubernetes, Azure Container Instances, Virtual Machine) - how should the oauth2-redirect URI now be changed - and what are some options on how to treat TLS in such a setting (as Azure App Registration will only allow https links as redirects). Maybe a section on production maturing would be helpful or maybe simply just clarifying that oauth2-redirect should be changed in a realistic production/TLS setting.

    documentation enhancement 
    opened by Christian-Schultz 9
Releases(3.5.1)
  • 3.5.1(Nov 10, 2022)

    Changes

    • Fixes README example scopes usage by @infomiho in https://github.com/Intility/fastapi-azure-auth/pull/102
    • chore: support python3.11 by @JonasKs in https://github.com/Intility/fastapi-azure-auth/pull/107

    New Contributors

    • @infomiho made their first contribution in https://github.com/Intility/fastapi-azure-auth/pull/102

    Full Changelog: https://github.com/Intility/fastapi-azure-auth/compare/3.5.0...3.5.1

    Source code(tar.gz)
    Source code(zip)
  • 3.5.0(Jul 8, 2022)

    Features:

    • B2CMultiTenantAuthorizationCodeBearer class which simplifies a multi-tenant B2C setup. ( #93 @kristiqntashev )

    Fix:

    • Make tid optional in the User model to support tokens sent from a B2C single-tenant ( #96 @marcinplatek )

    Github actions:

    • Fix caching ( @jonasks )
    Source code(tar.gz)
    Source code(zip)
  • 3.4.0(Apr 28, 2022)

  • 3.3.0(Mar 12, 2022)

    Features

    • Add setting to specify openid_config_url in AzureAuthorizationCodeBearerBase to add support for B2C tenants. ( #48 @robteeuwen and @JonasKs )
    • Use python-jose to load JWK, instead of x5c-keys loaded with cryptography. This add support for B2C tenants ( #48 @robteeuwen and @JonasKs )

    Other

    • Rewrite tests and clean up code ( #48 @JonasKs )
    Source code(tar.gz)
    Source code(zip)
  • 3.2.2(Mar 7, 2022)

    Fixes

    • Loosen cryptography version requirement, adding support for cryptography version 36, and future major bumps. ( @JonasKs, 63868904e9c7c2f3da31cdeefebec4884da402b4)
    Source code(tar.gz)
    Source code(zip)
  • 3.2.1(Mar 7, 2022)

    Bugfix

    • Python3.9.0 and Python3.9.1 has a bug with collections.abc.Callable, so this typing import has been changed to typing.Callable ( @ravaszf and @JonasKs #50 )
    Source code(tar.gz)
    Source code(zip)
  • 3.2.0(Jan 15, 2022)

    Features

    • auto_error flag/setting. When set to False an invalid token will return None instead of raising exception. ( @bkmetzler and @JonasKs #44 )
      • This flag allows end users to configure multiple authentication paths, and reflects authentication classes shipped by FastAPI.
    Source code(tar.gz)
    Source code(zip)
  • 3.1.0(Oct 24, 2021)

  • 3.0.3(Oct 13, 2021)

  • 3.0.2(Oct 10, 2021)

    Fixes

    • Loosen FastAPI version requirement, allowing installation of this module on FastAPI 0.70.0+ ( @bmoore #28 )
      • Add Python3.10 and FastAPI==0.70.0 to pipeline matrix ( @jonasks #28 )
    Source code(tar.gz)
    Source code(zip)
  • 3.0.1(Oct 1, 2021)

    Fixes

    • Multi-tenant schema documentation ( #20 @sondrelg )
    • Multiple errors in the documentation ( #22 @daniwk )
    • Update cryptography requirement to ^35.0.0 and fix imports ( #26 @bmoore )
    Source code(tar.gz)
    Source code(zip)
  • 3.0.0(Sep 10, 2021)

    This release contains breaking changes for how to setup your application, but also a bunch of new features.

    The new documentation contains a full tutorial on how to configure Azure AD and FastAPI for both single- and multi-tenant applications.

    Features

    • Add v2 token support (and default) for single-tenant applications.
    • Full multi-tenant support
      • Option to provide a callable which returns valid iss(issuers), for those who has multi-tenant applications, but only for specific tenants

    Other

    • User object is reworked, now also contain access_token for easier Azure Graph implementation
    • Add support for denying requests with wrong scopes, when Securiy() is used (an alternativ to Depends())
    • Moved InvalidAuth to exceptions.py
    • Documentation for everything from role checks, guest users, locking down tenants etc.
    • No longer inheriting OAuth2AuthorizationCodeBearer, solving mypy errors.
    • Rename provider_config.py to openid_config.py and ProviderConfig() to OpenIdConfig()
    • Removal of pre-instance of provider_config due to OpenAPI authorization URL issues. This is now instanced on SingleTenantAzureAuthorizationCodeBearer or MultiTenantAzureAuthorizationCodeBearer.

    Features implemented in #16 ( @JonasKs )

    Source code(tar.gz)
    Source code(zip)
  • 3.0.0-rc1(Sep 1, 2021)

  • 2.0.1(Aug 18, 2021)

  • 2.0.0(Aug 18, 2021)

    Breaking changes

    • Removal of app parameter from AzureAuthorizationCodeBearer
    • AzureAuthorizationCodeBearer now returns a User object instead of a dictionary with claims

    Other

    • Documentation on how to create your own dependencies for checking roles, scp or similar
    • Add docs on how to load provider config on startup, it is no longer auto-loaded by AzureAuthorizationCodeBearer

    Related MR: #11 by @JonasKs


    Upgrade guide from v1 to v2 I strongly suggest reading the entire README.md again, as it's a bit more verbose compared to before.
    With that said, these are the steps you have to do in order to bump from v1 to v2:

    1. Remove app=app from your AzureAuthorizationCodeBearer() in main.py.
    2. If you have a dependencies.py file or similar, move the azure_scheme = AzureAuthorizationCodeBearer( ... ) to that file. 2.1. In your main.py, import azure_scheme from dependencies.py
    3. In your main.py file, load the provider config on startup:
    @app.on_event('startup')
    async def load_config() -> None:
        """
        Load config on startup.
        """
        await provider_config.load_config()
    
    1. If you've overwritten the default tenant_id, you can also add that to load_config()
    @app.on_event('startup')
    async def load_config() -> None:
        """
        Load config on startup.
        """
    +   provider_config.tenant_id = 'my-tenant-id' 
        await provider_config.load_config()
    
    Source code(tar.gz)
    Source code(zip)
  • 1.1.1(Aug 17, 2021)

    Features

    • Improve how key to validate token is chosen. It's now based on kid, instead of trying all keys ( #10 @JonasKs )

    Other/Improvements

    • More test cases for validating tokens ( #10 @JonasKs )
    • Test case for refreshing of provider config ( #10 @JonasKs )
    • More comments describing patterns and choices in the code ( #10 @JonasKs )
    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Aug 15, 2021)

    Features

    • User attached to the request state ( #6 @JonasKs )

    Improvements

    • py.typed added ( #6 @JonasKs )
    • codecov.yaml added for codecov updated in PRs ( #6 @JonasKs )
    • Better exception handling ( 49f0adbd19e8901025eea9d7c786bb8a3fc64dcc & 48bc86c0a51a61a4222f7db581c7ed037ee843d7 @JonasKs )
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Aug 13, 2021)

Owner
Intility
Intility is a fully managed platform service that covers all areas of your business. From your managed computer to the server hosting your applications.
Intility
:rocket: CLI tool for FastAPI. Generating new FastAPI projects & boilerplates made easy.

Project generator and manager for FastAPI. Source Code: View it on Github Features ?? Creates customizable project boilerplate. Creates customizable a

Yagiz Degirmenci 1k Jan 2, 2023
The template for building scalable web APIs based on FastAPI, Tortoise ORM and other.

FastAPI and Tortoise ORM. Powerful but simple template for web APIs w/ FastAPI (as web framework) and Tortoise-ORM (for working via database without h

prostomarkeloff 95 Jan 8, 2023
CLI and Streamlit applications to create APIs from Excel data files within seconds, using FastAPI

FastAPI-Wrapper CLI & APIness Streamlit App Arvindra Sehmi, Oxford Economics Ltd. | Website | LinkedIn (Updated: 21 April, 2021) fastapi-wrapper is mo

Arvindra 49 Dec 3, 2022
FastAPI-Amis-Admin is a high-performance, efficient and easily extensible FastAPI admin framework. Inspired by django-admin, and has as many powerful functions as django-admin.

简体中文 | English 项目介绍 FastAPI-Amis-Admin fastapi-amis-admin是一个拥有高性能,高效率,易拓展的fastapi管理后台框架. 启发自Django-Admin,并且拥有不逊色于Django-Admin的强大功能. 源码 · 在线演示 · 文档 · 文

AmisAdmin 318 Dec 31, 2022
fastapi-admin2 is an upgraded fastapi-admin, that supports ORM dialects, true Dependency Injection and extendability

FastAPI2 Admin Introduction fastapi-admin2 is an upgraded fastapi-admin, that supports ORM dialects, true Dependency Injection and extendability. Now

Glib 14 Dec 5, 2022
Simple FastAPI Example : Blog API using FastAPI : Beginner Friendly

fastapi_blog FastAPI : Simple Blog API with CRUD operation Steps to run the project: git clone https://github.com/mrAvi07/fastapi_blog.git cd fastapi-

Avinash Alanjkar 1 Oct 8, 2022
Пример использования GraphQL Ariadne с FastAPI и сравнение его с GraphQL Graphene FastAPI

FastAPI Ariadne Example Пример использования GraphQL Ariadne с FastAPI и сравнение его с GraphQL Graphene FastAPI - GitHub ###Запуск на локальном окру

ZeBrains Team 9 Nov 10, 2022
Sample-fastapi - A sample app using Fastapi that you can deploy on App Platform

Getting Started We provide a sample app using Fastapi that you can deploy on App

Erhan BÜTE 2 Jan 17, 2022
Flask-vs-FastAPI - Understanding Flask vs FastAPI Web Framework. A comparison of two different RestAPI frameworks.

Flask-vs-FastAPI Understanding Flask vs FastAPI Web Framework. A comparison of two different RestAPI frameworks. IntroductionIn Flask is a popular mic

Mithlesh Navlakhe 1 Jan 1, 2022
FastAPI Server Session is a dependency-based extension for FastAPI that adds support for server-sided session management

FastAPI Server-sided Session FastAPI Server Session is a dependency-based extension for FastAPI that adds support for server-sided session management.

DevGuyAhnaf 5 Dec 23, 2022
Code Specialist 27 Oct 16, 2022
Fastapi-ml-template - Fastapi ml template with python

FastAPI ML Template Run Web API Local $ sh run.sh # poetry run uvicorn app.mai

Yuki Okuda 29 Nov 20, 2022
Cookiecutter API for creating Custom Skills for Azure Search using Python and Docker

cookiecutter-spacy-fastapi Python cookiecutter API for quick deployments of spaCy models with FastAPI Azure Search The API interface is compatible wit

Microsoft 379 Jan 3, 2023
FastAPI native extension, easy and simple JWT auth

fastapi-jwt FastAPI native extension, easy and simple JWT auth

Konstantin Chernyshev 19 Dec 12, 2022
A dynamic FastAPI router that automatically creates CRUD routes for your models

⚡ Create CRUD routes with lighting speed ⚡ A dynamic FastAPI router that automatically creates CRUD routes for your models

Adam Watkins 950 Jan 8, 2023
Easily integrate socket.io with your FastAPI app 🚀

fastapi-socketio Easly integrate socket.io with your FastAPI app. Installation Install this plugin using pip: $ pip install fastapi-socketio Usage To

Srdjan Stankovic 210 Dec 23, 2022
A dynamic FastAPI router that automatically creates CRUD routes for your models

⚡ Create CRUD routes with lighting speed ⚡ A dynamic FastAPI router that automatically creates CRUD routes for your models Documentation: https://fast

Adam Watkins 943 Jan 1, 2023
Instrument your FastAPI app

Prometheus FastAPI Instrumentator A configurable and modular Prometheus Instrumentator for your FastAPI. Install prometheus-fastapi-instrumentator fro

Tim Schwenke 441 Jan 5, 2023
A dynamic FastAPI router that automatically creates CRUD routes for your models

⚡ Create CRUD routes with lighting speed ⚡ A dynamic FastAPI router that automatically creates CRUD routes for your models Documentation: https://fast

Adam Watkins 130 Feb 13, 2021