backend.auth

Authentication and authorisation utilities.

Provides JWT-based access and refresh token handling, password hashing (bcrypt with legacy SHA-1 fallback), user lookup and all FastAPI dependency helpers required by the API routers.

Constants:

ACCESS_TOKEN_EXPIRE_MINUTES (int): Lifetime of an access token in minutes (15). REFRESH_TOKEN_EXPIRE_DAYS (int): Lifetime of a refresh token in days (30). RESET_PASSWORD_TOKEN_EXPIRE_MINUTES (int): Lifetime of a password-reset token (15). ALGORITHM (str): JWT signing algorithm (HS256).

Extract a Bearer token from the Authorization header or the access_token cookie.

The header is checked first; the cookie serves as a backwards- compatible fallback.

Parameters:

request (Request) – The incoming FastAPI request object.

Returns:

The raw JWT string, or None if no token was found.

Return type:

str | None

backend.auth.hash_pw(plain_pw)[source]

Hash a plain-text password using bcrypt.

Parameters:

plain_pw (str) – The plain-text password to hash.

Returns:

The bcrypt hash string.

Return type:

str

backend.auth.verify_password(plain, hashed)[source]

Verify a plain-text password against a stored hash.

Supports bcrypt hashes ($2b$, $2a$, $2y$ prefix) and, until LEGACY_HASH_DEADLINE, LDAP-style SHA-1 hashes ({SHA} prefix).

Parameters:
  • plain (str) – The plain-text password provided by the user.

  • hashed (str) – The stored password hash.

Returns:

True if the password matches, False otherwise.

Return type:

bool

backend.auth.authenticate_user(db, username, password)[source]

Look up a user by username and verify their password.

If the stored hash uses a legacy format it is automatically upgraded to bcrypt on successful login.

Parameters:
  • db (Session) – Active database session.

  • username (str) – The username to look up.

  • password (str) – The plain-text password to verify.

Returns:

The authenticated user, or None if the credentials are invalid.

Return type:

models.User | None

backend.auth.create_access_token(data)[source]

Create a signed JWT access token.

The token expires after ACCESS_TOKEN_EXPIRE_MINUTES minutes.

Parameters:

data (dict) – Payload to encode (must contain at least sub and role).

Returns:

The encoded JWT string.

Return type:

str

backend.auth.revoke_all_refresh_tokens_for_user(user_id, db)[source]

Revoke all refresh tokens for a user (used for replay mitigation).

backend.auth.create_refresh_token(user_id, db)[source]

Create a refresh token, persist its hash in the database and return the raw token string.

Parameters:
  • user_id (int) – Primary key of the user the token belongs to.

  • db (Session) – Active database session.

Returns:

The raw (unhashed) refresh token.

Return type:

str

backend.auth.rotate_refresh_token(token, db)[source]

Rotate a refresh token and return (user, new_refresh_token).

If a revoked token is presented, all active refresh tokens of that user are revoked (replay detection).

backend.auth.verify_refresh_token(token, db)[source]

Validate a refresh token and return the associated user.

Parameters:
  • token (str) – The raw refresh token string.

  • db (Session) – Active database session.

Returns:

The user associated with the token.

Return type:

models.User

Raises:

HTTPException 401 – If the token is invalid, revoked or expired.

backend.auth.revoke_refresh_token(token, db)[source]

Mark a refresh token as revoked in the database.

Parameters:
  • token (str) – The raw refresh token string.

  • db (Session) – Active database session.

backend.auth.blacklist_access_token(token, db)[source]

Add an access token to the blacklist so it cannot be reused after logout.

Only tokens that have not yet expired are stored; already-expired tokens are silently ignored.

Parameters:
  • token (str) – The raw JWT access token string.

  • db (Session) – Active database session.

backend.auth.create_password_reset_token(user_name)[source]

Create a short-lived JWT token scoped to password reset.

Parameters:

user_name (str) – The username for which the reset is requested.

Returns:

The encoded JWT string with scope="password_reset_token".

Return type:

str

backend.auth.get_db()[source]

FastAPI dependency that yields a database session.

Yields:

Session – An active SQLAlchemy database session.

backend.auth.get_current_user(request, db=Depends(dependency=<function get_db>, use_cache=True, scope=None))[source]

FastAPI dependency that validates the access token and returns the current user’s payload.

Checks both the token blacklist and the JWT signature/expiry.

Parameters:
  • request (Request) – The incoming request (token read from header or cookie).

  • db (Session) – Active database session.

Returns:

A dictionary with keys user_name and user_group.

Return type:

dict

Raises:

HTTPException 401 – If the token is missing, invalid or blacklisted.

async backend.auth.get_current_user_dep(request, db=Depends(dependency=<function get_db>, use_cache=True, scope=None))[source]

Async wrapper for router-level dependencies

Parameters:
  • request (Request) – The incoming request.

  • db (Session) – Active database session.

Returns:

A dictionary with keys user_name and user_group.

Return type:

dict

backend.auth.check_user_role(token, expected_role)[source]

Verify that a JWT token carries a specific role.

Parameters:
  • token (str) – The raw JWT string.

  • expected_role (str) – The role to check against (e.g. "admin").

Returns:

True if the token’s role claim matches expected_role.

Return type:

bool

Raises:

HTTPException 401 – If the token cannot be decoded.

backend.auth.verify_password_reset_token(token=Depends(dependency=<fastapi.security.oauth2.OAuth2PasswordBearer object>, use_cache=True, scope=None), db=Depends(dependency=<function get_db>, use_cache=True, scope=None))[source]

Validate a password-reset token and ensure it has not been used before.

Parameters:
  • token (str) – The raw password-reset JWT.

  • db (Session) – Active database session.

Returns:

A tuple of (username, raw_token).

Return type:

tuple[str, str]

Raises:

HTTPException 400 – If the token is invalid, expired, has the wrong scope or has already been used.

backend.auth.generate_ical_token(user_name)[source]

Create a short-lived JWT token scoped to access internal ical.

Parameters:

user_name (str) – The username for which the reset is requested.

Returns:

The encoded JWT string with scope="internal_ical_token".

Return type:

str

backend.auth.verify_ical_token(token, db)[source]