Skip to content

Code review: issues to address before v1.0Β #2

Description

@lukwam

Code Review Summary

Overall assessment: 🟒 Excellent foundation β€” architecture, typing, and provider implementations are production-quality. The following items should be addressed before v1.0.


πŸ”΄ High Priority

1. No FastAPI Adapter Tests

The FastAPI adapter is ~384 lines with error mapping, telemetry, OIDC dependency factory, and all Auth.* methods β€” all untested. This is the largest code gap.

2. No Django Ninja Adapter Tests

Same issue β€” no tests for any of the Ninja auth classes (ApiKeyAuth, FirebaseAuth, GoogleAuth, OIDCAuth).

3. Flask Adapter Stores client_secret in Session

flask/__init__.py stores the OAuth2 client secret in the Flask session. If sessions are cookie-based (even encrypted), this is a security risk. The secret is already available from the client_secrets_file and does not need to be stored in the session.

4. Flask Adapter Bypasses AuthService

The Flask adapter directly uses google-auth and google-auth-oauthlib instead of going through the Provider β†’ Service β†’ Adapter pattern. This is architecturally inconsistent with the other adapters.


🟑 Medium Priority

5. No Telemetry in Django Ninja Adapter

The FastAPI adapter has _log_failure() and _set_request_auth_context() for structured auth telemetry. The Ninja adapter silently swallows errors (except AuthError: return None) with no logging. Should at least log failures for observability.

6. AuthCascade Does Not Handle Exceptions

If an auth method raises an exception instead of returning None, the cascade stops with an unhandled error. The Ninja auth classes return None on failure so this works today, but it is fragile.

Suggested fix:

# Current (fragile):
for method in self.auth_methods:
    result = method.authenticate(request)
    if result is not None:
        return result

# Safer:
for method in self.auth_methods:
    try:
        result = method.authenticate(request)
        if result is not None:
            return result
    except AuthError:
        continue

7. AuthPrincipal Model is Dead Code

core/models.py defines AuthPrincipal but it is never referenced in service, adapters, or tests. Either integrate it or remove it.

8. No Coverage Threshold in CI

Tests run with --cov but no --cov-fail-under. Adding --cov-fail-under=80 would prevent coverage regression.

9. CHANGELOG Missing Flask Adapter

The [0.1.0] entry mentions FastAPI and Django Ninja adapters but not the Flask adapter. The date 2024-01-01 also appears to be a placeholder.


🟒 Low Priority / Nitpicks

Issue Notes
AuthCascade typed as list[Any] Could use list[Callable] for type safety
No reset() for test isolation Module-level _service singleton in FastAPI adapter has no reset function
IAP provider is header-only Does not verify IAP JWT tokens β€” documented but should be noted more prominently
No token refresh in Flask adapter Access token expiry is not handled
Poetry version not pinned in CI pipx install poetry should pin a version for reproducibility
GoogleTokenInfo.jlt field Unusual JWT claim name β€” is this jti? Worth documenting

Test Coverage Summary

Area Status
Models βœ… Good
Exceptions βœ… Good
Policies βœ… Good
Service βœ… Good
Cascade βœ… Adequate
All 6 Providers βœ… Good to Excellent
Flask Adapter βœ… Good
FastAPI Adapter ❌ No tests
Django Ninja Adapter ❌ No tests
Telemetry ❌ No tests

Recommendations

  1. Add FastAPI and Django Ninja adapter tests
  2. Fix the Flask session client_secret storage
  3. Add telemetry to the Django Ninja adapter
  4. Add exception handling to AuthCascade
  5. Add --cov-fail-under=80 to CI
  6. Either use AuthPrincipal or remove it
  7. Update CHANGELOG to include Flask adapter and correct the date

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions