Skip to content

Commit 5762695

Browse files
authored
feat: auth
* feat(backend): auth and oauth endpoints * feat(frontend): login signup forms and routing * feat: oauth2 * refactor: auth api typing * refactor: auth forms validation * refactor: oauth improvements and routes protection * style * fix: conditional rendering of nav and dropdown menu * fix * feat: routes protected for demo mode * fix * fix * fix * fix * style * fix * fix * test: updated tests to use auth client * test: added basic auth tests * feat: dynamic oauth buttons rendering * fix: fixed security violation (redirects based on user-controlled data)
1 parent 3e97de1 commit 5762695

59 files changed

Lines changed: 1781 additions & 94 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,29 @@ ENV=dev # dev | prod | demo
33
DATABASE_URL=postgresql+psycopg2://evsy:evsy@db:5432/evsy
44
FRONTEND_URL=http://localhost:3000
55

6+
67
# Frontend
78
VITE_ENV=dev # dev | prod | demo
89
VITE_API_URL=http://localhost:8000/api/v1
910
VITE_LOG_LEVEL=error
10-
__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=demo.evsy.dev
11+
__VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=demo.evsy.dev
12+
13+
14+
# Auth
15+
16+
## Secret key for signing JWTs. Use a secure 32+ character string.
17+
SECRET_KEY=YOUR_32_CHAR_SECRET_KEY
18+
19+
## GitHub OAuth credentials
20+
## Create your app here: https://github.com/settings/developers
21+
## Set "Authorization callback URL" to:
22+
## http://localhost:8000/api/v1/auth/oauth/callback
23+
GITHUB_CLIENT_ID=
24+
GITHUB_CLIENT_SECRET=
25+
26+
## Google OAuth credentials
27+
## Create credentials here: https://console.cloud.google.com/apis/credentials
28+
## Set "Authorized redirect URI" to:
29+
## http://localhost:8000/api/v1/auth/oauth/callback
30+
GOOGLE_CLIENT_ID=
31+
GOOGLE_CLIENT_SECRET=

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ up:
44
down:
55
docker compose down
66

7-
migrate: # e. g. make revision name="add auth"
7+
migrate:
88
docker compose exec backend alembic upgrade head
99

10-
revision:
11-
docker compose exec backend alembic revision -m "$(name)"
10+
revision: # e. g. make revision name="add auth"
11+
docker compose exec backend alembic revision --autogenerate -m "$(name)"
1212

1313
dev:
1414
docker compose -f docker-compose.dev.yaml up --build -d

backend/.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ __pycache__/
99
env/
1010
venv/
1111

12-
# Alembic
13-
migrations/versions/
14-
1512
# Database files
1613
*.sqlite3
1714
*.db

backend/app/api/v1/routes/admin.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
from fastapi import APIRouter
1+
from fastapi import APIRouter, Depends
22

33
from app.modules.admin.io.router import router as io_router
44
from app.modules.admin.reset.router import router as reset_router
55
from app.modules.admin.seed.router import router as seed_router
6+
from app.modules.auth.token import get_current_user
67

7-
router = APIRouter(prefix="/admin")
8+
router = APIRouter(prefix="/admin", dependencies=[Depends(get_current_user)])
89

910
router.include_router(io_router)
1011
router.include_router(seed_router)

backend/app/api/v1/routes/auth.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from fastapi import APIRouter
2+
3+
from app.modules.auth.router import router as auth_router
4+
5+
router = APIRouter(prefix="/auth", tags=["auth"])
6+
7+
router.include_router(auth_router)

backend/app/api/v1/routes/events.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@
1111
from sqlalchemy.orm import Session
1212

1313
from app.core.database import get_db
14+
from app.modules.auth.token import get_current_user
1415
from app.modules.events import crud as event_crud
1516
from app.modules.events.schemas import EventCreate, EventOut
1617
from app.modules.events.service import generate_json_schema_for_event
1718
from app.modules.fields.crud import get_fields_by_ids
1819
from app.modules.tags.crud import get_or_create_tags
1920

20-
router = APIRouter(prefix="/events", tags=["events"])
21+
router = APIRouter(
22+
prefix="/events", tags=["events"], dependencies=[Depends(get_current_user)]
23+
)
2124

2225

2326
@router.post(

backend/app/api/v1/routes/fields.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
from sqlalchemy.orm import Session
33

44
from app.core.database import get_db
5+
from app.modules.auth.token import get_current_user
56
from app.modules.fields import crud as field_crud
67
from app.modules.fields.schemas import FieldCreate, FieldOut, FieldOutWithEventCount
78

8-
router = APIRouter(prefix="/fields", tags=["fields"])
9+
router = APIRouter(
10+
prefix="/fields", tags=["fields"], dependencies=[Depends(get_current_user)]
11+
)
912

1013

1114
@router.post(

backend/app/api/v1/routes/tags.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
from sqlalchemy.orm import Session
33

44
from app.core.database import get_db
5+
from app.modules.auth.token import get_current_user
56
from app.modules.tags import crud as tag_crud
67
from app.modules.tags.schemas import TagCreate, TagOut
78

8-
router = APIRouter(prefix="/tags", tags=["tags"])
9+
router = APIRouter(
10+
prefix="/tags", tags=["tags"], dependencies=[Depends(get_current_user)]
11+
)
912

1013

1114
@router.post(

backend/app/core/guard.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from fastapi import Depends, HTTPException
2+
3+
from app.settings import get_settings
4+
5+
6+
def ensure_not_demo(settings=Depends(get_settings)):
7+
if settings.is_demo:
8+
raise HTTPException(
9+
status_code=403, detail="This action is not allowed in demo mode."
10+
)
11+
12+
13+
def ensure_dev(settings=Depends(get_settings)):
14+
if not settings.is_dev:
15+
raise HTTPException(
16+
status_code=403, detail="This action is allowed only in development."
17+
)

backend/app/core/security.py

Whitespace-only changes.

0 commit comments

Comments
 (0)