Skip to content

Commit

Permalink
Add bearer token endpoint example to project. Updated configs and rea…
Browse files Browse the repository at this point in the history
…dme for oidc provider.
  • Loading branch information
jbouder committed Oct 13, 2023
1 parent 548615e commit 3a218ed
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pip install -r requirements.txt

```
DATABASE_URL=[SOME_URL] # Ex: 'sqlite:///./db.sqlite3'
OIDC_CONFIG_URL=[SOME_URL] # Ex: 'https://token.actions.githubusercontent.com/.well-known/openid-configuration'
```

4. To start the app, run the following:
Expand Down
Empty file added app/admin/__init__.py
Empty file.
21 changes: 21 additions & 0 deletions app/admin/router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from typing import Annotated

from fastapi import APIRouter, Depends
from fastapi.security import HTTPBearer
from starlette import status

from app.auth import validate_jwt

router = APIRouter(
prefix="/api",
tags=["Admin"],
)


@router.get(
"/current-user",
dependencies=[Depends(HTTPBearer())],
status_code=status.HTTP_200_OK,
)
async def get_current_user(current_user: Annotated[dict, Depends(validate_jwt)]):
return {"user": current_user}
40 changes: 40 additions & 0 deletions app/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import requests
from fastapi import Depends, HTTPException
from jose.backends import RSAKey
from jose.jwt import decode, get_unverified_header

from app.config import settings


def get_keycloak_jwks():
keycloak_well_known_url = settings.OIDC_CONFIG_URL
response = requests.get(keycloak_well_known_url)
well_known_config = response.json()
jwks_url = well_known_config["jwks_uri"]
jwks_response = requests.get(jwks_url)
jwks = jwks_response.json()
return jwks["keys"]


def validate_jwt(token: str = Depends(get_keycloak_jwks)):
header = get_unverified_header(token)
jwks = get_keycloak_jwks()

# Find the RSA key with the matching kid in the JWKS
rsa_key = None
for key in jwks:
if key["kid"] == header["kid"]:
rsa_key = RSAKey(
key=key["n"], alg=key["alg"], use=key["use"], kid=key["kid"]
)
break

if rsa_key is None:
raise HTTPException(status_code=401, detail="RSA Key not found in JWKS")

try:
payload = decode(token, rsa_key, algorithms=[header["alg"]])
except Exception:
raise HTTPException(status_code=401, detail="Invalid JWT token") from Exception

return payload
1 change: 1 addition & 0 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

class Settings(BaseSettings):
DATABASE_URL: str
OIDC_CONFIG_URL: str

class Config:
env_file = ".env"
Expand Down
2 changes: 2 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from fastapi import FastAPI

from app.admin.router import router as admin_router
from app.db import Base, engine
from app.health.router import router as health_router
from app.spacecraft.router import router as spacecraft_router
Expand All @@ -11,3 +12,4 @@
# Add routes
app.include_router(health_router)
app.include_router(spacecraft_router)
app.include_router(admin_router)
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ pydantic-settings
pysqlite3
pytest
python-dotenv
python-jose[cryptography]
requests
ruff
sqlalchemy
uvicorn[standard]

0 comments on commit 3a218ed

Please sign in to comment.