Skip to content

DHService endpoints rely entirely on portal-layer permission gating #262

@rubin110

Description

@rubin110

Summary

DHService FastAPI endpoints (code/DHService/v1.py) require only AuthenticatedClient — i.e. any caller with a valid OAuth2 client-credentials token gets full read access to any member's identity, status, forms, access logs, etc. Permission gating happens entirely at the Flask portal layer via decorators like @requires_view_permission(\"member.forms\").

Two new endpoints added on new-member-onboard-flow follow the same pattern:

  • GET /v1/member/display_name/?member_id=N → returns first/last/username for any member ID
  • GET /v1/onboarder_search/?query=…&limit=N → enumerates members by name/username

This is consistent with existing endpoints (it's not a regression introduced by the onboarding work), but it means:

  1. Anyone with a DH service client token can enumerate the entire member directory
  2. The admin-portal permission check (@requires_view_permission(\"member.forms\")) is a portal-side speedbump that says nothing about who's actually authorized at the data layer
  3. Non-admin DH service clients (e.g. workers, member portal) can in principle query any member's data, even though their natural use case only needs the calling member's own data

Proposed approach

Push permission/scope checks down to the DHService layer. Options worth weighing:

  • Annotate endpoints with required permissions, looked up against the calling client's role/scope claims (requires DH OAuth2 to issue scoped tokens — currently it doesn't differentiate)
  • Add a per-client-id allowlist (e.g. dev-admin-portal can read everyone, dev-member-portal can only read its own session member, workers get tag-specific scopes)
  • Or simply harden the new endpoints (/member/display_name/, /onboarder_search/) to require an admin-style client and leave the existing pattern alone

This is a defense-in-depth concern, not a known-exploitable bug — the gateway routing and client-credential storage limit who can talk to DHService at all.

Out of scope

  • Changes to existing endpoints (track separately if we're going to do a full audit)
  • OAuth2 scope work (probably needed if we want fine-grained per-endpoint perms; bigger lift)

Where

  • code/DHService/v1.py — every endpoint declares only current_user: AuthenticatedClient
  • New endpoints landing in PR for new-member-onboard-flow: lines around get_member_display_name and onboarder_search

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions