1
0
forked from baron/baron-sso

ory용 MCP 제작, devfront/adminfront 백엔드 연결

This commit is contained in:
Lectom C Han
2026-01-28 10:57:22 +09:00
parent 1aaa772907
commit 93cab064fc
75 changed files with 7327 additions and 454 deletions

View File

@@ -0,0 +1,31 @@
import axios from "axios";
const apiClient = axios.create({
baseURL: import.meta.env.VITE_ADMIN_API_BASE ?? "/api/admin",
});
apiClient.interceptors.request.use((config) => {
// TODO: IdP 중립 Auth 레이어 연동 시 세션 토큰을 주입한다.
const sessionToken = window.localStorage.getItem("admin_session");
if (sessionToken) {
config.headers.Authorization = `Bearer ${sessionToken}`;
}
// TODO: 테넌트 선택 값을 보관하고 헤더로 전달한다.
const tenantId = window.localStorage.getItem("admin_tenant");
if (tenantId) {
config.headers["X-Tenant-ID"] = tenantId;
}
return config;
});
apiClient.interceptors.response.use(
(response) => response,
(error) => {
// TODO: 401/403 응답 시 로그인/재인증 플로우로 리다이렉션한다.
return Promise.reject(error);
},
);
export default apiClient;

View File

@@ -0,0 +1,89 @@
import apiClient from "./apiClient";
export type ClientStatus = "active" | "inactive";
export type ClientType = "confidential" | "public";
export type ClientSummary = {
id: string;
name: string;
type: ClientType;
status: ClientStatus;
createdAt?: string;
redirectUris: string[];
scopes: string[];
};
export type ClientListResponse = {
items: ClientSummary[];
limit: number;
offset: number;
};
export type ClientEndpoints = {
discovery: string;
issuer: string;
authorization: string;
token: string;
userinfo: string;
};
export type ClientDetailResponse = {
client: ClientSummary & {
metadata?: Record<string, unknown>;
};
endpoints: ClientEndpoints;
};
export type ConsentSummary = {
subject: string;
clientId: string;
clientName?: string;
grantedScopes: string[];
authenticatedAt?: string;
};
export type ConsentListResponse = {
items: ConsentSummary[];
};
export async function fetchClients() {
const { data } = await apiClient.get<ClientListResponse>("/clients");
return data;
}
export async function fetchClient(clientId: string) {
const { data } = await apiClient.get<ClientDetailResponse>(
`/clients/${clientId}`,
);
return data;
}
export async function updateClientStatus(
clientId: string,
status: ClientStatus,
) {
const { data } = await apiClient.patch<ClientDetailResponse>(
`/clients/${clientId}/status`,
{ status },
);
return data;
}
export async function fetchConsents(subject: string, clientId?: string) {
const params: Record<string, string> = { subject };
if (clientId) {
params.client_id = clientId;
}
const { data } = await apiClient.get<ConsentListResponse>("/consents", {
params,
});
return data;
}
export async function revokeConsent(subject: string, clientId?: string) {
const params: Record<string, string> = { subject };
if (clientId) {
params.client_id = clientId;
}
await apiClient.delete("/consents", { params });
}

View File

@@ -0,0 +1,6 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}