Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/hvalfangst/azure-oauth2-auth-code-flow-fastapi

API programmed in Python with FastAPI framework secured by Oauth2 auth code flow
https://github.com/hvalfangst/azure-oauth2-auth-code-flow-fastapi

azure fastapi oauth2 oauth2-authorization-code-flow python

Last synced: 16 days ago
JSON representation

API programmed in Python with FastAPI framework secured by Oauth2 auth code flow

Awesome Lists containing this project

README

        

# Python FastAPI secured with OAuth2 Auth code flow on Azure

## Requirements

- **Platform**: x86-64, Linux/WSL
- **Programming Language**: [Python 3](https://www.python.org/downloads/)
- **Azure Account**: Access to [Azure Subscription](https://azure.microsoft.com/en-us/pricing/purchase-options/azure-account)

## Register API on Azure AD

### Create a new app registration

Navigate to the **App registrations** blade and click on **New registration** button in the top left tab

![screenshot](images/azuread_app_registrations.png)

Fill in the name of your application, whether it is single or multi-tenant and the redirect URI.

![screenshot](images/azuread_new_app_registration.png)

In our case the redirect URI is necessary and **MUST** be set to
http://localhost:8000/auth/callback as this is an actual [endpoint](app/routers/auth.py) in our auth router. Click on the **Register** button (omitted) to complete the app registration.

![screenshot](images/azuread_hvalfangst_app_registration.png)

When the registration has succeeded, one will be redirected to the associated newly created registration. Proceed to copy & store the **client** and **tenant ID** for future use.

### Generate client secret

Now that we have registered our API, we need to generate an associated client secret. Proceed to click on **New client secret**

![screenshot](images/client_secret.png)

Enter a description and an expiry date. For demonstration purposes I set the secret duration to 1 day. Click on the **Add** button on the bottom left.

![screenshot](images/add_secret.png)

Now that we have our secret it is important to copy and store it's associated value. It is this which is referred to as **client secret**. It is important not to mix this up with **Secret ID**, which is merely the ID of the resource.

![screenshot](images/hvalfangst_api_secret.png)

### Create scope

Now that we have our client secret we may proceed to register the actual scope available in the API. In order to do so one must navigate to the **Expose an API** blade. Click on **Add a scope**.

![screenshot](images/expose_api.png)

You will be prompted to set an application id uri. Keep the autogenerated one as is and click **Save and continue**.

![screenshot](images/application_id_uri.png)

After an application URI has been registered, you will be prompted to register a scope. Proceed to set the scope name of **Heroes.Read**. Note that one is free to
set any scope name that one so desires, but it is common practice utilizing the controller domain followed by some access rights categories, such as **READ**, **WRITE**, **EDIT** and **DELETE**. Thus,
our chosen scope grants the right to access the GET endpoints contained in the [heroes router](app/routers/heroes.py), which are utilized in order to list all heroes and view a specific one.
One could take inspiration from Azure's built-in scopes for certain resources, such as Key Vault, Blob Storage etc.

![screenshot](images/heroes_read_scope.png)

Copy the value associated with the newly created scope.

![screenshot](images/heroes_read_scope_created.png)

### Create environment file

In order for this application to work, one has to have a file named **.env_oauth** in the root folder.
This file is to contain variables utilized in order to communicate with the Azure Authorization server.

These variables are the azure **client and tenant id**, the **client secret**, the **api scope** and the **redirect uri**. Recall that you were instructed to copy and store
the associated values used to populate these variables in earlier sections.

The final file should look as follows:

![screenshot](images/oauth_env.png)

## Flow: callback

As mentioned earlier, we have a callback endpoint registered, whose URI matches the one specified in the registration.

![screenshot](images/callback_endpoint.png)

After the user logs in via Microsoft, they are redirected to this endpoint. The redirection includes an authorization code in the query params as such:

```http request
http://localhost:8000/auth/callback?code=AUTH_CODE
```

This code will in turn be exchanged for an access token in the [get_access_token](app/services/auth_service.py) function:

![screenshot](images/get_access_token.png)

As one may observe the token is used in conjunction with the client id and secret, hence the code being in a query param in the callback. If not it would be a major security vulnerability.
Note that for some applications such as mobile apps and SPA's (12) one should not operate with client secrets as storing them safely locally is impossible. For instance, a hacker may easily decompile
your beloved app and grab the client secret as it would be imprinted in the app itself.

## Running API
```bash
python -m uvicorn app.main:app --reload
```