diff --git a/ui/litellm-dashboard/src/components/key_team_helpers/key_list.tsx b/ui/litellm-dashboard/src/components/key_team_helpers/key_list.tsx
index f410a04976..6b3c65aaf7 100644
--- a/ui/litellm-dashboard/src/components/key_team_helpers/key_list.tsx
+++ b/ui/litellm-dashboard/src/components/key_team_helpers/key_list.tsx
@@ -53,6 +53,7 @@ export interface KeyResponse {
organization_id: string | null;
org_id?: string | null;
created_at: string;
+ created_by?: string;
updated_at: string;
last_active: string | null;
team_spend: number;
diff --git a/ui/litellm-dashboard/src/components/team/TeamVirtualKeysTable.tsx b/ui/litellm-dashboard/src/components/team/TeamVirtualKeysTable.tsx
index a7e48ff12b..cfc08e8c4e 100644
--- a/ui/litellm-dashboard/src/components/team/TeamVirtualKeysTable.tsx
+++ b/ui/litellm-dashboard/src/components/team/TeamVirtualKeysTable.tsx
@@ -25,7 +25,8 @@ import {
Text,
} from "@tremor/react";
import { InfoCircleOutlined } from "@ant-design/icons";
-import { Popover, Skeleton, Tooltip } from "antd";
+import { Popover, Skeleton, Tooltip, Typography } from "antd";
+import DefaultProxyAdminTag from "../common_components/DefaultProxyAdminTag";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { getModelDisplayName } from "../key_team_helpers/fetch_available_models_team_key";
import { KeyResponse, Team } from "../key_team_helpers/key_list";
@@ -339,18 +340,59 @@ export function TeamVirtualKeysTable({ teamId, teamAlias, organization }: TeamVi
size: 70,
enableSorting: false,
cell: (info) => {
- const value = info.getValue() as string | null;
- const displayValue = value === "default_user_id" ? "Default Proxy Admin" : value;
+ const userId = info.getValue() as string | null;
+ if (!userId) return "-";
+ const { created_by_user } = info.row.original;
+ const userAlias = created_by_user?.user_alias ?? null;
+ const userEmail = created_by_user?.user_email ?? null;
+ const isDefaultAdmin = userId === "default_user_id";
+ const displayValue = userAlias || userEmail || userId;
const width = info.cell.column.getSize();
+
+ const popoverContent = (
+
+ {[
+ { label: "User Alias", value: userAlias },
+ { label: "User Email", value: userEmail },
+ { label: "User ID", value: userId },
+ ].map(({ label, value }) => (
+
+ {label}
+ {value ? (
+
+ {value}
+
+ ) : (
+ -
+ )}
+
+ ))}
+
+ );
+
+ if (isDefaultAdmin && !userAlias && !userEmail) {
+ return (
+
+
+
+
+
+ );
+ }
+
return (
-
+
- {displayValue ?? "-"}
+ {displayValue}
-
+
);
},
},
diff --git a/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.test.tsx b/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.test.tsx
index c9c5856129..1475078760 100644
--- a/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.test.tsx
+++ b/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.test.tsx
@@ -8,10 +8,12 @@ const MOCK_DATA: KeyInfoData = {
keyId: "sk-1234567890abcdef",
userId: "user-abc-123",
userEmail: "test@example.com",
+ userAlias: null,
createdBy: "admin@example.com",
createdAt: "Oct 29, 2025 at 1:26 AM",
lastUpdated: "Oct 29, 2025 at 1:47 AM",
lastActive: "Oct 29, 2025 at 2:00 AM",
+ expires: "Never",
};
describe("KeyInfoHeader", () => {
@@ -28,12 +30,11 @@ describe("KeyInfoHeader", () => {
it("should render all metadata fields", () => {
render();
- expect(screen.getByText("User Email")).toBeInTheDocument();
+ expect(screen.getByText("User")).toBeInTheDocument();
expect(screen.getByText("test@example.com")).toBeInTheDocument();
- expect(screen.getByText("User ID")).toBeInTheDocument();
- expect(screen.getByText("user-abc-123")).toBeInTheDocument();
expect(screen.getByText("Created At")).toBeInTheDocument();
expect(screen.getByText("Created By")).toBeInTheDocument();
+ expect(screen.getByText("Expires")).toBeInTheDocument();
expect(screen.getByText("Last Updated")).toBeInTheDocument();
expect(screen.getByText("Last Active")).toBeInTheDocument();
});
@@ -122,8 +123,8 @@ describe("KeyInfoHeader", () => {
});
describe("default_user_id handling", () => {
- it("should show Default Proxy Admin tag for User ID when value is default_user_id", () => {
- const data = { ...MOCK_DATA, userId: "default_user_id" };
+ it("should show Default Proxy Admin tag for User when userId is default_user_id and no alias/email", () => {
+ const data = { ...MOCK_DATA, userId: "default_user_id", userEmail: "", userAlias: null };
render();
expect(screen.getAllByText("Default Proxy Admin").length).toBeGreaterThanOrEqual(1);
});
@@ -135,9 +136,27 @@ describe("KeyInfoHeader", () => {
});
});
- describe("empty value handling", () => {
- it("should show '-' for User Email when value is empty", () => {
- const data = { ...MOCK_DATA, userEmail: "" };
+ describe("User field fallbacks", () => {
+ it("should display userAlias as primary when set, overriding email and userId", () => {
+ const data = { ...MOCK_DATA, userAlias: "alice" };
+ render();
+ expect(screen.getByText("alice")).toBeInTheDocument();
+ expect(screen.queryByText("test@example.com")).not.toBeInTheDocument();
+ });
+
+ it("should display userEmail when alias is null", () => {
+ render();
+ expect(screen.getByText("test@example.com")).toBeInTheDocument();
+ });
+
+ it("should fall back to userId when alias and email are missing", () => {
+ const data = { ...MOCK_DATA, userEmail: "", userAlias: null };
+ render();
+ expect(screen.getByText("user-abc-123")).toBeInTheDocument();
+ });
+
+ it("should show '-' when alias, email, and userId are all empty", () => {
+ const data = { ...MOCK_DATA, userId: "", userEmail: "", userAlias: null };
render();
expect(screen.getByText("-")).toBeInTheDocument();
});
diff --git a/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.tsx b/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.tsx
index 93ebae9c4b..d39b46a5cd 100644
--- a/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.tsx
+++ b/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.tsx
@@ -1,19 +1,20 @@
import React from "react";
-import { Button, Typography, Tooltip, Space, Divider, Flex } from "antd";
+import { Button, Typography, Tooltip, Space, Divider, Flex, Popover } from "antd";
import {
ArrowLeftOutlined,
SyncOutlined,
DeleteOutlined,
PlusOutlined,
UserOutlined,
- MailOutlined,
CalendarOutlined,
ClockCircleOutlined,
ThunderboltOutlined,
SafetyCertificateOutlined,
TransactionOutlined,
+ FieldTimeOutlined,
} from "@ant-design/icons";
import LabeledField from "../common_components/LabeledField";
+import DefaultProxyAdminTag from "../common_components/DefaultProxyAdminTag";
const { Title, Text } = Typography;
@@ -22,10 +23,12 @@ export interface KeyInfoData {
keyId: string;
userId: string;
userEmail: string;
+ userAlias?: string | null;
createdBy: string;
createdAt: string;
lastUpdated: string;
lastActive: string;
+ expires: string;
}
interface KeyInfoHeaderProps {
@@ -41,6 +44,94 @@ interface KeyInfoHeaderProps {
regenerateTooltip?: string;
}
+function UserField({
+ userAlias,
+ userEmail,
+ userId,
+}: {
+ userAlias?: string | null;
+ userEmail: string;
+ userId: string;
+}) {
+ const labelEl = (
+
+
+
+ User
+
+
+ );
+
+ const isEmpty = !userAlias && !userEmail && !userId;
+ if (isEmpty) {
+ return (
+
+ );
+ }
+
+ const isDefaultAdmin = userId === "default_user_id";
+ const displayValue = userAlias || userEmail || userId;
+
+ const popoverContent = (
+
+ {[
+ { label: "User Alias", value: userAlias ?? null },
+ { label: "User Email", value: userEmail || null },
+ { label: "User ID", value: userId || null },
+ ].map(({ label, value }) => (
+
+ {label}
+ {value ? (
+
+ {value}
+
+ ) : (
+ -
+ )}
+
+ ))}
+
+ );
+
+ if (isDefaultAdmin && !userAlias && !userEmail) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {labelEl}
+
+
+
+ {displayValue}
+
+
+
+
+ );
+}
+
export function KeyInfoHeader({
data,
onBack,
@@ -101,15 +192,8 @@ export function KeyInfoHeader({
- } />
- }
- truncate
- copyable
- defaultUserIdCheck
- />
+
+ } />
diff --git a/ui/litellm-dashboard/src/components/templates/key_info_view.tsx b/ui/litellm-dashboard/src/components/templates/key_info_view.tsx
index 65bd9d9eb9..f889778009 100644
--- a/ui/litellm-dashboard/src/components/templates/key_info_view.tsx
+++ b/ui/litellm-dashboard/src/components/templates/key_info_view.tsx
@@ -403,10 +403,16 @@ export default function KeyInfoView({
keyId: currentKeyData.token_id || currentKeyData.token,
userId: currentKeyData.user_id || "",
userEmail: currentKeyData.user_email || "",
- createdBy: currentKeyData.user_email || currentKeyData.user_id || "",
+ userAlias: currentKeyData.user?.user_alias ?? null,
+ createdBy:
+ currentKeyData.created_by_user?.user_alias ||
+ currentKeyData.created_by_user?.user_email ||
+ currentKeyData.created_by ||
+ "",
createdAt: currentKeyData.created_at ? formatTimestamp(currentKeyData.created_at) : "",
lastUpdated: currentKeyData.updated_at ? formatTimestamp(currentKeyData.updated_at) : "",
lastActive: currentKeyData.last_active ? formatTimestamp(currentKeyData.last_active) : "Never",
+ expires: currentKeyData.expires ? formatTimestamp(currentKeyData.expires) : "Never",
}}
onBack={onClose}
onRegenerate={() => setIsRegenerateModalOpen(true)}