Package: aad-fastapi
Protecting your FAST API web API with Azure ADThis package allows you to protect easily your Web API, using Azure AD.It has been created specifically forFAST API, delivering a newmiddlewarein the pipeline toauthenticateandauthorizeany http requests, if needed.InstallationTo install withpip:>python-mpipinstallaad_fastapiUsageOnce configured in Azure AD (see sections below), just add anauthentication middlewarewith theAadBearerBackend:fromaad_fastapiimport(AadBearerBackend,AadUser,authorize,oauth2_scheme,AzureAdSettings)# App Registration settings for protecting all the APIs.api_options=AzureAdSettings()api_options.client_id=environ.get("API_CLIENT_ID")api_options.domain=environ.get("DOMAIN")api_options.scopes=environ.get("SCOPES")# App Registration setting for authentication SWAGGER WEB UI AUTHENTICATION.web_ui_client_id=environ.get("CLIENT_ID")# Client IDweb_ui_scopes=environ.get("SCOPES")# Client ID# pre fill client idswagger_ui_init_oauth={"usePkceWithAuthorizationCodeGrant":"true","clientId":web_ui_client_id,"appName":"B-ID","scopes":web_ui_scopes,}# Create a FasAPI instanceapp=FastAPI(swagger_ui_init_oauth=swagger_ui_init_oauth)# Add the bearer middleware, protected with Api App Registrationapp.add_middleware(AuthenticationMiddleware,backend=AadBearerBackend(api_options))Once configured, you can addauthentication dependency injectionto your routers:# These routers needs an authentication for all its routes using Web App Registrationapp.include_router(engines.router,dependencies=[Depends(oauth2_scheme(options=api_options))])Or directly to your web api route:@app.get("/user")asyncdefuser(request:Request,token=Depends(oauth2_scheme(options=api_options))):returnrequest.userif you are inspecting therequest.userobject, you will find all the user's property retrieved fromAzure AD.You can specifyscopesand / orroles, usingdecorators, to be checked before accessing your web api:@app.get("/user_with_scope")@authorize("user_impersonation")asyncdefuser_with_scope(request:Request,token=Depends(oauth2_scheme(options=api_options))):# code here@app.get("/user_with_scope_and_roles")@authorize("user_impersonation","admin-role")asyncdefuser_with_scope_and_roles(request:Request,token=Depends(oauth2_scheme(options=api_options))):# code hereRole Requirements and Multiple RolesThe@authorizedecorator is capable of specifying multiple roles as a list of string, which will be checked against the user's roles.
Ifallthe roles are found, the user is authorized.To require the user to haveat least oneof the specified roles, you can use therole_requirementparameter with the
valueRoleRequirement.ANY:@app.get("/user_with_scope_and_roles_any")@authorize("user_impersonation",roles=["admin","superuser"],role_requirement=RoleRequirement.ANY)asyncdefuser_with_scope_and_roles_any(request:Request,token=Depends(oauth2_scheme(options=api_options))):# code hereNOTE:RoleRequirement.ALLis the default behavior and does not need to be specified.Register your application within your Azure AD tenantThere are two applications to register:First one will protect the Web API. It will only allows bearer token to access with the correct scope.Second one will allow the user to authenticate himself and get a token to access the Web API, using the correct scope.Register the Web API applicationThe Web API application does not need to allow user to authenticate. The main purpose of this application is to protect our Web API.Navigate to the Microsoft identity platform for developersApp registrationspage.SelectNew registration.In theRegister an application pagethat appears, enter your application's registration information:In theNamesection, enter an application name, for examplepy-api.UnderSupported account types, selectAccounts in this organizational directory only (Microsoft only - Single tenant).SelectRegisterto create the application.In the app's registration screen, find and note theApplication (client) ID. You use this value in your app's configuration file(s) later in your code.SelectSaveto save your changes.In the app's registration screen, select theExpose an APIblade to the left to open the page where you can declare the parameters to expose this app as an API for which client applications can obtainaccess tokensfor.
The first thing that we need to do is to declare the uniqueresourceURI that the clients will be using to obtain access tokens for this API. To declare an resource URI, follow the following steps:ClickSetnext to theApplication ID URIto generate a URI that is unique for this app.For this sample, we are using the domain name and the client id as theApplication ID URI (https://{domain}.onmicrosoft.com/{clientId}) by selectingSave.All APIs have to publish a minimum of onescopefor the client's to obtain an access token successfully. To publish a scope, follow the following steps:SelectAdd a scopebutton open theAdd a scopescreen and Enter the values as indicated below:ForScope name, useuser_impersonation.SelectAdmins and usersoptions forWho can consent?KeepStateasEnabledClick on theAdd scopebutton on the bottom to save this scope.Register the Client applicationThe Client application will allow the user to authenticate, and will expose a scope to the Web Api application.Navigate to the Microsoft identity platform for developersApp registrationspage.SelectNew registration.In theRegister an application pagethat appears, enter your application's registration information:In theNamesection, enter an application name that will be displayed to users, for examplepy-web.UnderSupported account types, selectAccounts in this organizational directory only (Microsoft only - Single tenant).SelectRegisterto create the application.In the app's registration screen, find and note theApplication (client) ID. You use this value in your app's configuration file(s) later in your code.In the app's registration screen, selectAuthenticationin the menu.If you don't have a platform added, selectAdd a platformand select theWeboption.In theRedirect URIs|Suggested Redirect URIs for public clients (mobile, desktop)section, selecthttp://localhost:5000/auth/oauth2-redirectSelect againAdd a platformand select theSingle-page applicationoption.In theRedirect URIs|Suggested Redirect URIs for public clients (mobile, desktop)section, selecthttp://localhost:5000/docs/oauth2-redirectSelectSaveto save your changes.Do not activate the implicit flow, as we are using thenew Authorization Code Flow with PKCE(https://oauth.net/2/pkce/)In the app's registration screen, click on theCertificates & secretsblade in the left to open the page where we can generate secrets and upload certificates.In theClient secretssection, click onNew client secret:Type a key description (for instancesamplein our sample),Select one of the available key durations (In 1 year,In 2 years, orNever Expires) as per your security concerns.The generated key value will be displayed when you click theAddbutton. Copy the generated value for use in the steps later.You'll need this key later in your code's configuration files. This key value will not be displayed again, and is not retrievable by any other means, so make sure to noteIn the app's registration screen, click on theAPI permissionsblade in the left to open the page where we add access to the APIs that your application needs.Click theAdd a permissionbutton and then,Ensure that theMy APIstab is selected.In the list of APIs, select the APIpy-api.In theDelegated permissionssection, select theuser_impersonationin the list.Click on theAdd permissionsbutton at the bottom.Configure Known Client Applications in the Web API applicationFor a middle tier Web API to be able to call a downstream Web API, the middle tier app needs to be granted the required permissions as well.
However, since the middle tier cannot interact with the signed-in user, it needs to be explicitly bound to the client app in its Azure AD registration.
This binding merges the permissions required by both the client and the middle tier Web API and presents it to the end user in a single consent dialog. The user then consent to this combined set of permissions.To achieve this, you need to add theApplication Idof the client app (py-webin our sample), in the Manifest of the Web API in theknownClientApplicationsproperty. Here's how:In theAzure portal, navigate to yourpy-apiapp registration, and selectExpose an APIsection.In the textbox, fill the Client ID of thepy-webapplicationSelect the authorized scopeuser_impersonationClickAdd applicationConfigure the .devcontainerOpen the project in VS Code and configure correctly the.devcontainer/devcontainer.jsonfile:TENANT_ID={GUID}# The tenant id where you've created the application registrationsSUBSCRIPTION_ID={GUID}# Your subscription idDOMAIN={domain}.onmicrosoft.com# the domain nameAUTHORITY=https://login.microsoftonline.com/{tenant_id}# Authority used to login in Azure AD# App Registration information for Web AuthenticationCLIENT_ID={GUID}# This client id is the authentication client id used by the user (from `py-web` application registration)CLIENT_SECRET={PWD}# youSCOPES=https://{domain}.onmicrosoft.com/{client_id}/user_impersonation :# Scope exposed to the `py-web` applicationAPI_URL=http://localhost:8000VAULT_NAME={Vault Name}# Optional : Key vault used to store the secretVAULT_SECRET_KEY={Vault key}# Optional : Key vault secret's key# App Registration information for Api ProtectionAPI_CLIENT_ID={GUID}# Client id for the web api protection (from `py-api` application registration)Run the applicationThe solutions provides alaunch.jsonexample (in the/.vscodefolder) that you can use to launch the demo.In VS Code, select the Run and Debug blade on the left paneSelect theAPIsub menu item and click the green arrow (or hitF5)Navigate to the urlhttp://localhost:8000/docsand test the user authentication experienceYou don't need to fill the secret textbox when trying to authenticate your user, since we are using the PKCE method