Easy and secure implementation of Azure AD for your FastAPI APIs 🔒 Single- and multi-tenant support.

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 we use FastAPI for both internal (single-tenant) and customer-facing (multi-tenant) APIs. This package enables our developers (and you 😊 ) to create features without worrying about authentication and authorization.

Also, we're hiring!

📚 Resources

The documentation contains a full tutorial on how to configure Azure AD and FastAPI for both single- and multi-tenant applications. It includes examples on how to lock down your APIs to certain scopes, tenants, roles etc. For first time users it's strongly advised to set up your application exactly how it's described there, and then alter it to your needs later.

MIT License | Documentation | GitHub

Setup

This is a tl;dr intended to give you an idea of what this package does and how to use it. For a more in-depth tutorial and settings reference you should read the documentation.

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,
    },
)

3. Setup CORS

Ensure you have CORS enabled for your local environment, such as http://localhost:8000.

4. Configure FastAPI-Azure-Auth

Configure either your SingleTenantAzureAuthorizationCodeBearer or MultiTenantAzureAuthorizationCodeBearer.

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

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',
    }
)

or for multi-tenant applications:

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

azure_scheme = MultiTenantAzureAuthorizationCodeBearer(
    app_client_id=settings.APP_CLIENT_ID,
    scopes={
        f'api://{settings.APP_CLIENT_ID}/user_impersonation': 'user_impersonation',
    },    
    validate_iss=False
)

To validate the iss, configure an iss_callable.

5. Configure dependencies

Add azure_scheme as a dependency for your views/routers, using either Security() or Depends().

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

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

6. Load config on startup

Optional but recommended.

# file: main.py
@app.on_event('startup')
async def load_config() -> None:
    """
    Load OpenID config on startup.
    """
    await azure_scheme.openid_config.load_config()

📄 Example OpenAPI documentation

Your OpenAPI documentation will get an Authorize button, which can be used to authenticate. authorize

The user can select which scopes to authenticate with, based on your configuration. scopes

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
Django Authetication with Twitch.

Django Twitch Auth Dependencies Install requests if not installed pip install requests Installation Install using pip pip install django_twitch_auth A

Leandro Lopes Bueno 1 Jan 02, 2022
Mock authentication API that acceccpts email and password and returns authentication result.

Mock authentication API that acceccpts email and password and returns authentication result.

Herman Shpryhau 1 Feb 11, 2022
This is a Token tool that gives you many options to harm the account.

Trabis-Token-Tool This is a Token tool that gives you many options to harm the account. Utilities With this tools you can do things as : ·Delete all t

Steven 2 Feb 13, 2022
Pingo provides a uniform API to program devices like the Raspberry Pi, BeagleBone Black, pcDuino etc.

Pingo provides a uniform API to program devices like the Raspberry Pi, BeagleBone Black, pcDuino etc. just like the Python DBAPI provides an uniform API for database programming in Python.

Garoa Hacker Clube 12 May 22, 2022
Authentication testing framework

What is this This is a framework designed to test authentication for web applications. While web proxies like ZAProxy and Burpsuite allow authenticate

DigeeX 140 Jul 06, 2022
OpenStack Keystone auth plugin for HTTPie

httpie-keystone-auth OpenStack Keystone auth plugin for HTTPie. Installation $ pip install --upgrade httpie-keystone-auth You should now see keystone

Pavlo Shchelokovskyy 1 Oct 20, 2021
Django CAS 1.0/2.0/3.0 client authentication library, support Django 2.0, 2.1, 2.2, 3.0 and Python 3.5+

django-cas-ng django-cas-ng is Django CAS (Central Authentication Service) 1.0/2.0/3.0 client library to support SSO (Single Sign On) and Single Logou

django-cas-ng 347 Dec 18, 2022
Strong, Simple, and Precise security for Flask APIs (using jwt)

flask-praetorian Strong, Simple, and Precise security for Flask APIs API security should be strong, simple, and precise like a Roman Legionary. This p

Tucker Beck 321 Dec 18, 2022
Simple extension that provides Basic, Digest and Token HTTP authentication for Flask routes

Flask-HTTPAuth Simple extension that provides Basic and Digest HTTP authentication for Flask routes. Installation The easiest way to install this is t

Miguel Grinberg 1.1k Jan 05, 2023
Includes Automation and Personal Projects

Python Models, and Connect Forclient & OpenCv projects Completed Automation** Alarm (S

tushar malhan 1 Jan 15, 2022
A module making it easier to manage Discord oAuth with Quart

quart_discord A module making it easier to manage Discord oAuth with Quart Install pip install git+https://github.com/xelA/ 5 Oct 27, 2022

Implements authentication and authorization as FastAPI dependencies

FastAPI Security Implements authentication and authorization as dependencies in FastAPI. Features Authentication via JWT-based OAuth 2 access tokens a

Jacob Magnusson 111 Jan 07, 2023
Simple yet powerful authorization / authentication client library for Python web applications.

Authomatic Authomatic is a framework agnostic library for Python web applications with a minimalistic but powerful interface which simplifies authenti

1k Dec 28, 2022
This Python based program checks your CC Stripe Auth 1$ Based Checker

CC-Checker This Python based program checks your CC Stripe Auth 1$ Based Checker About Author Coded by xBlackx Reach Me On Telegram @xBlackx_Coder jOI

xBlackxCoder 11 Nov 20, 2022
Extending the Django authentication system with a phone verification step.

Extending the Django authentication system with a phone verification step.

Miguel Grinberg 50 Dec 04, 2022
API with high performance to create a simple blog and Auth using OAuth2 ⛏

DogeAPI API with high performance built with FastAPI & SQLAlchemy, help to improve connection with your Backend Side to create a simple blog and Cruds

Yasser Tahiri 111 Jan 05, 2023
Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication.

Welcome to django-allauth! Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (soc

Raymond Penners 7.7k Jan 01, 2023
🔐 Login & Register System

🔐 Login & Register System This is a developable login and register system. Enter your username and password to register or login to account. Automati

Firdevs Akbayır 10 Dec 12, 2022
Automatizando a criação de DAGs usando Jinja e YAML

Automatizando a criação de DAGs no Airflow usando Jinja e YAML Arquitetura do Repo: Pastas por contexto de negócio (ex: Marketing, Analytics, HR, etc)

Arthur Henrique Dell' Antonia 5 Oct 19, 2021
Toolkit for Pyramid, a Pylons Project, to add Authentication and Authorization using Velruse (OAuth) and/or a local database, CSRF, ReCaptcha, Sessions, Flash messages and I18N

Apex Authentication, Form Library, I18N/L10N, Flash Message Template (not associated with Pyramid, a Pylons project) Uses alchemy Authentication Authe

95 Nov 28, 2022