feat: add JWT creation, decoding and cookie helpers

This commit is contained in:
Oliver Hofmann 2026-04-27 09:44:06 +02:00
parent f93793a1d8
commit fb7284b117
2 changed files with 74 additions and 0 deletions

47
app/core/auth.py Normal file
View File

@ -0,0 +1,47 @@
from datetime import datetime, timedelta, timezone
from typing import Optional
from fastapi import Request, Response
from jose import JWTError, jwt
from app.core.config import get_settings
settings = get_settings()
COOKIE_NAME = "access_token"
ALGORITHM = "HS256"
TOKEN_EXPIRE_HOURS = 8
def create_access_token(username: str, is_admin: bool) -> str:
expire = datetime.now(timezone.utc) + timedelta(hours=TOKEN_EXPIRE_HOURS)
return jwt.encode(
{"sub": username, "is_admin": is_admin, "exp": expire},
settings.SECRET_KEY,
algorithm=ALGORITHM,
)
def decode_token(token: str) -> Optional[dict]:
try:
return jwt.decode(token, settings.SECRET_KEY, algorithms=[ALGORITHM])
except JWTError:
return None
def get_token_from_request(request: Request) -> Optional[str]:
return request.cookies.get(COOKIE_NAME)
def set_auth_cookie(response: Response, token: str) -> None:
response.set_cookie(
key=COOKIE_NAME,
value=token,
httponly=True,
samesite="lax",
secure=settings.APP_ENV == "production",
)
def clear_auth_cookie(response: Response) -> None:
response.delete_cookie(key=COOKIE_NAME, httponly=True, samesite="lax")

27
tests/test_core_auth.py Normal file
View File

@ -0,0 +1,27 @@
from app.core.auth import COOKIE_NAME, create_access_token, decode_token
def test_create_and_decode_token():
token = create_access_token(username="alice", is_admin=False)
payload = decode_token(token)
assert payload is not None
assert payload["sub"] == "alice"
assert payload["is_admin"] is False
def test_admin_claim():
token = create_access_token(username="admin", is_admin=True)
assert decode_token(token)["is_admin"] is True
def test_decode_invalid_token():
assert decode_token("not.a.valid.token") is None
def test_decode_tampered_token():
token = create_access_token(username="alice", is_admin=False)
assert decode_token(token[:-4] + "xxxx") is None
def test_cookie_name():
assert COOKIE_NAME == "access_token"