Return the row in the db
| 2627 | |
| 2628 | |
| 2629 | class UserAPIKeyAuth(LiteLLM_VerificationTokenView): # the expected response object for user api key auth |
| 2630 | """ |
| 2631 | Return the row in the db |
| 2632 | """ |
| 2633 | |
| 2634 | api_key: str | None = None |
| 2635 | user_role: LitellmUserRoles | None = None |
| 2636 | allowed_model_region: AllowedModelRegion | None = None |
| 2637 | parent_otel_span: Span | None = None |
| 2638 | rpm_limit_per_model: dict[str, int] | None = None |
| 2639 | tpm_limit_per_model: dict[str, int] | None = None |
| 2640 | user_tpm_limit: int | None = None |
| 2641 | user_rpm_limit: int | None = None |
| 2642 | user_email: str | None = None |
| 2643 | user_spend: float | None = None |
| 2644 | user_max_budget: float | None = None |
| 2645 | request_route: str | None = None |
| 2646 | is_session_token: bool = False |
| 2647 | # Server-only marker set exclusively by the MCP gateway admission path |
| 2648 | # (_reload_admitted_user) for a keyless user-subject admitted via a gateway DCR session |
| 2649 | # bearer or bridge envelope. Not a DB column and never populated from caller-controlled key |
| 2650 | # metadata or JWT claims, so it cannot be forged to gain the team-inherited MCP grant union |
| 2651 | # or to escape the caller-Authorization egress scrub. exclude=True keeps it out of serialization. |
| 2652 | mcp_admitted_user_subject: bool = Field(default=False, exclude=True) |
| 2653 | # team_id -> that team's mcp_rpm_limit map, for a keyless admitted subject that reaches MCP |
| 2654 | # servers through several teams at once and therefore has no single team_id for the limiter to |
| 2655 | # key off. Server-only and stripped from validated input for the same reason as the marker |
| 2656 | # above: a forged entry would let a caller pick which team's rpm bucket it is charged against. |
| 2657 | mcp_source_team_rpm_limits: dict[str, dict[str, int]] | None = Field(default=None, exclude=True) |
| 2658 | via_virtual_key: bool = Field( |
| 2659 | default=False, |
| 2660 | exclude=True, |
| 2661 | description=( |
| 2662 | "Server-only marker set exclusively by the DB virtual-key and master-key auth paths via " |
| 2663 | "post-construction assignment. Stripped from validated input so custom auth handlers, JWT " |
| 2664 | "claims, or key metadata cannot forge it. Gates overwrite_user_with_key_hash stamping: only " |
| 2665 | "a credential the proxy itself validated as a key may be forwarded as the provider-facing " |
| 2666 | "user id." |
| 2667 | ), |
| 2668 | ) |
| 2669 | budget_reservation: dict[str, Any] | None = Field(default=None, exclude=True) |
| 2670 | budget_throttle_pct: float | None = Field(default=None, exclude=True) |
| 2671 | user: Any | None = None # Expanded user object when expand=user is used |
| 2672 | created_by_user: Any | None = None # Expanded created_by user when expand=user is used |
| 2673 | end_user_object_permission: LiteLLM_ObjectPermissionTable | None = None |
| 2674 | # Team object_permission preloaded in auth (e.g. get_team_object) to avoid |
| 2675 | # per-request object_permission fetches in downstream checks (vector stores, etc.) |
| 2676 | team_object_permission: LiteLLM_ObjectPermissionTable | None = None |
| 2677 | # Decoded upstream IdP claims (groups, roles, etc.) propagated by JWT auth machinery |
| 2678 | # and forwarded into outbound tokens by guardrails such as MCPJWTSigner. |
| 2679 | jwt_claims: dict | None = None |
| 2680 | |
| 2681 | model_config = ConfigDict(arbitrary_types_allowed=True) |
| 2682 | |
| 2683 | @model_validator(mode="before") |
| 2684 | @classmethod |
| 2685 | def check_api_key(cls, values): |
| 2686 | # If values is already an instance (not a dict), return it as-is |
no outgoing calls