Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/codeql-analysis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:

- uses: actions/setup-python@v5
with:
python-version: "3.11"
python-version: "3.12"

- name: Install poetry
uses: snok/install-poetry@v1
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11.0"
python-version: "3.12"
- name: Install poetry
uses: snok/install-poetry@v1
with:
Expand All @@ -24,7 +24,7 @@ jobs:
uses: actions/[email protected]
with:
path: .venv
key: venv-${{ runner.os }}-3.11.0-${{ hashFiles('**/poetry.lock') }}-0
key: venv-${{ runner.os }}-3.12-${{ hashFiles('**/poetry.lock') }}-0
- name: Install dependencies
run: poetry install
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish_to_pypi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: 3.11
python-version: 3.12
- uses: snok/install-poetry@v1
- name: Publish to pypi
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/testing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.10", "3.11", "3.12", "3.13" ]
fastapi-version: [ "0.103.2", "0.111.1"]
steps:
- name: Check out repository
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<p align="center">
<!-- Line 1 -->
<a href="https://python.org">
<img src="https://img.shields.io/badge/python-v3.8+-blue.svg?logo=python&logoColor=white&label=python" alt="Python version">
<img src="https://img.shields.io/badge/python-v3.10+-blue.svg?logo=python&logoColor=white&label=python" alt="Python version">
</a>
<a href="https://fastapi.tiangolo.com/">
<img src="https://img.shields.io/badge/FastAPI-0.68.0+%20-blue.svg?logo=fastapi&logoColor=white&label=fastapi" alt="FastAPI Version">
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ poetry add fastapi-azure-auth
```

:::info
Only Python 3.8 and above is currently supported. If you can't install the package, check your Python version.
Only Python 3.10 and above is currently supported. If you can't install the package, check your Python version.
:::

Now that it's installed, jump on over to the relevant section:
Expand Down
63 changes: 0 additions & 63 deletions docs/docs/usage-and-faq/accessing_the_user.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ You can access your user object in two ways, either with `Depends(<schema name>)

### `Depends(<schema name>)`

<Tabs groupId="python-version">
<TabItem value="Python 3.9 or above">

```python title="depends_api_example.py"
from fastapi import APIRouter, Depends
Expand All @@ -33,40 +31,10 @@ async def hello_user(user: User = Depends(azure_scheme)) -> dict[str, bool]:
"""
return user.dict()
```
</TabItem>

<TabItem value="Python 3.8">

```python title="depends_api_example.py"
from fastapi import APIRouter, Depends
from typing import Dict

from demo_project.api.dependencies import azure_scheme
from fastapi_azure_auth.user import User

router = APIRouter()


@router.get(
'/hello-user',
response_model=User,
operation_id='helloWorldApiKey',
)
async def hello_user(user: User = Depends(azure_scheme)) -> Dict[str, bool]:
"""
Wonder how this auth is done?
"""
return user.dict()
```
</TabItem>

</Tabs>


### `request.state.user`

<Tabs groupId="python-version">
<TabItem value="Python 3.9 or above">

```python title="request_state_user_api_example.py"
from fastapi import APIRouter, Depends, Request
Expand All @@ -89,34 +57,3 @@ async def hello_user(request: Request) -> dict[str, bool]:
"""
return request.state.user.dict()
```

</TabItem>

<TabItem value="Python 3.8">

```python title="request_state_user_api_example.py"
from fastapi import APIRouter, Depends, Request
from typing import Dict

from demo_project.api.dependencies import azure_scheme
from fastapi_azure_auth.user import User

router = APIRouter()


@router.get(
'/hello-user',
response_model=User,
operation_id='helloWorldApiKey',
dependencies=[Depends(azure_scheme)]
)
async def hello_user(request: Request) -> Dict[str, bool]:
"""
Wonder how this auth is done?
"""
return request.state.user.dict()
```

</TabItem>

</Tabs>
40 changes: 22 additions & 18 deletions fastapi_azure_auth/openid_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from asyncio import Lock
from datetime import datetime, timedelta
from typing import TYPE_CHECKING, Any, Dict, List, Optional

Expand Down Expand Up @@ -31,28 +32,31 @@ def __init__(
self.token_endpoint: str
self.issuer: str

self._refresh_lock: Lock = Lock()

async def load_config(self) -> None:
"""
Loads config from the Intility openid-config endpoint if it's over 24 hours old (or don't exist)
"""
refresh_time = datetime.now() - timedelta(hours=24)
if not self._config_timestamp or self._config_timestamp < refresh_time:
try:
log.debug('Loading Azure Entra ID OpenID configuration.')
await self._load_openid_config()
self._config_timestamp = datetime.now()
except Exception as error:
log.exception('Unable to fetch OpenID configuration from Azure Entra ID. Error: %s', error)
# We can't fetch an up to date openid-config, so authentication will not work.
if self._config_timestamp:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail='Connection to Azure Entra ID is down. Unable to fetch provider configuration',
headers={'WWW-Authenticate': 'Bearer'},
) from error

else:
raise RuntimeError(f'Unable to fetch provider information. {error}') from error
async with self._refresh_lock:
refresh_time = datetime.now() - timedelta(hours=24)
if not self._config_timestamp or self._config_timestamp < refresh_time:
try:
log.debug('Loading Azure Entra ID OpenID configuration.')
await self._load_openid_config()
self._config_timestamp = datetime.now()
except Exception as error:
log.exception('Unable to fetch OpenID configuration from Azure Entra ID. Error: %s', error)
# We can't fetch an up to date openid-config, so authentication will not work.
if self._config_timestamp:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail='Connection to Azure Entra ID is down. Unable to fetch provider configuration',
headers={'WWW-Authenticate': 'Bearer'},
) from error

else:
raise RuntimeError(f'Unable to fetch provider information. {error}') from error

log.info('fastapi-azure-auth loaded settings from Azure Entra ID.')
log.info('authorization endpoint: %s', self.authorization_endpoint)
Expand Down
2 changes: 1 addition & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Global options
[mypy]
python_version = 3.11
python_version = 3.12
# flake8-mypy expects the two following for sensible formatting
show_column_numbers = True
show_error_context = False
Expand Down
Loading
Loading