Package: fastapi-ms-id
FastAPI authentication with Microsoft IdentityThe Microsoft Identity library for Python's FastAPI providesAzure Active Directorytoken authentication and authorization through a set of convenience functions. It enables any FastAPI applications to authenticate with Azure AD to validate JWT tokens and API permissionsInstall the packageInstall the Microsoft Identity for FastAPI library withpip:pip install fastapi-microsoft-identityPrerequisitesAn Azure Active DirectoryGet one FREEOr an Azure Active Directory B2C, through a FREE Azure subscriptionGet your Free subPython 3.6 or laterUsage1. Azure AD AuthenticationThe library can now support both Azure AD and Azure AD B2C authentication for FastAPI applications1.1 Azure AD App Registration ConfigurationFirst create an Azure Active DirectoryApplication Registrationin the Azure AD portal using the following steps:Sign in to your Azure AD Tenant (link)Navigate toApp Registrations->New Registration.Enter a name for your application.Leave everything else as default.ClickRegister.Copy theClient IDandTenant IDfrom theApplication RegistrationOverviewpage.Navigate to theExpose APItab.ClickSetnext to theApplication ID URIfield.ClickAdd a scopeGive the scope a name likeaccess_as_user.SelectAdmin and Userfor consentProvide meaningful descriptions for the admin and user consentsEnsureStateis set toEnabledClientAdd scopeThe scope should look like this:api://279cfdb1-0000-0000-0000-291dcd4b561a/access_as_user1.2 Using the Microsoft Identity for FastAPI libraryIn your FastAPI application, you need to initialize the authentication library using theClient IDandTenant IDvalues from theApplication RegistrationOverviewpage.initialize(tenant_id, client_id)You can now decorate any API endpoint with therequires_authdecorator as per the example belowfrom fastapi_microsoft_identity import requires_auth, validate_scope, AuthError

expected_scope = "<your expected scope e.g access_as_user>"

@router.get('/api/weather/{city}')
@requires_auth
async def weather(request: Request, loc: Location = Depends(), units: Optional[str] = 'metric'):
    try:
        validate_scope(expected_scope, request)
        return await openweather_service.get_report_async(loc.city, loc.state, loc.country, units)
    except AuthError as ae:
        return fastapi.Response(content=ae.error_msg, status_code=ae.status_code)
    except ValidationError as ve:
        return fastapi.Response(content=ve.error_msg, status_code=ve.status_code)
    except Exception as x:
        return fastapi.Response(content=str(x), status_code=500)Therequires_authdecorator will check if the JWT Access Token in the request is a valid token and then raise anAuthError(HTTP 401) if the token is invalid (expired, not right audience etc).The library also provides a helper function:validate_scopethat can be used to validate the scope of the JWT token.validate_scope(expected_scope, request)Thevalidate_scopemethod will throw anAuthError(HTTP 403) if the token doesn't contain the right scope / api permission.1.3 Accessing the token claimsBased on user feedback, the library now provides a helper function to access the token claims.token_claims = authservice.get_token_claims(request)
# do something with the claims2. Azure AD B2C Authentication2.1 Create your Azure AD B2C Application RegistrationFirst create an Azure AD B2CApp Registrationin the B2C portal using the following steps:Sign in to your Azure portal, search for your B2C tenant and navigate to the B2C portalNavigate toApp Registrations->New registration.Enter a name for your application.UnderSupported account typeschooseAccounts in any identity provider or organizational directory(for authenticating user with user flows).Make sure theGrant admin consent to openid and offline_accessis checked. underPermissionsClickRegister.Copy theClient IDandTenant IDfrom theApp RegistrationOverviewpage.Navigate to theExpose APItab.ClickSetnext to theApplication ID URIfield.ClickAdd a scopeGive the scope a name likeaccess_as_user.Provide meaningful descriptions for the admin consent name and descriptionEnsureStateis set toEnabledClientAdd scopeFrom the B2C overview pane, copy the domaain name like this<your-tenant>ignoring the.onmicrosoft.com.. eg. cmatb2cdev2.2 Using the Microsoft Identity for FastAPI library with Azure AD B2CIn your FastAPI application, you need to initialize the authentication library using the following values:Client IDTenant IDDomain NameSign up & Sign In User FlowYou need to make sure that both your Fast API and the API clients use the same B2C User flow to authenticate and acquire tokens.You can read more about Azure AD User Flows and Policieshereinitialize(tenant_id, client_id, b2c_policy_name, b2c_domain_name)You can now decorate any API endpoint with therequires_authdecorator as per the example belowfrom fastapi_microsoft_identity import requires_auth, validate_scope, AuthError

expected_scope = "<your expected scope e.g access_as_user>"

@router.get('/api/weather/{city}')
@requires_b2c_auth
async def weather(request: Request, loc: Location = Depends(), units: Optional[str] = 'metric'):
    try:
        validate_scope(expected_scope, request)
        return await openweather_service.get_report_async(loc.city, loc.state, loc.country, units)
    except AuthError as ae:
        return fastapi.Response(content=ae.error_msg, status_code=ae.status_code)
    except ValidationError as ve:
        return fastapi.Response(content=ve.error_msg, status_code=ve.status_code)
    except Exception as x:
        return fastapi.Response(content=str(x), status_code=500)Therequires_authdecorator will check if the JWT Access Token in the request is a valid token and then raise anAuthError(HTTP 401) if the token is invalid (expired, not right audience etc).The library also provides a helper function:validate_scopethat can be used to validate the scope of the JWT token.validate_scope(expected_scope, request)Thevalidate_scopemethod takes 2 parameters:expected_scope: The scope that the token should have (this can also be an app permission).request: The FastAPI Request object.The method works out wether the access token contain an app permission (role) or a scope and then validate the claim.
If neither is present, the method throws anAuthError(HTTP 403) for the following reasons:norolesorscpclaim was present in the tokenthe token doesn't contain the right scope / api permissionCompatibilityRequires Python 3.xLicenceMITProvide feedbackIf you encounter bugs or have suggestions, please open an issue.ContributingThis project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visithttps://cla.microsoft.com.This project has adopted theMicrosoft Open Source Code of Conduct. For more information, see theCode of Conduct FAQor contactopencode@microsoft.comwith any additional questions or comments.AuthorsThefastapi_microsoft_identitywas written byChristos Matskas <christos.matskas@microsoft.com>.The changes published asfastapi_ms_idwere done bySantiago Forero Molano <santiago.forero.molano@gmail.com>.