OAuth 로그인 버튼으로 provider 연결 + 제공자 연결 패널 그리드 이동
Some checks failed
API contract / OpenAPI type drift (push) Failing after 59s

claude(setup-token과 동일한 PKCE, code#state 수동 흐름)와
openrouter(헤드리스 코드 표시 모드)는 OAuth 로그인 버튼으로 연결한다.
관리자가 제공자 로그인 뒤 표시되는 인증 코드를 붙여넣으면 서버가
토큰/키로 교환해 저장·게이트웨이 push한다. state는 서버 발급·15분
단일 사용으로 CSRF를 막는다. codex·agy는 붙여넣기 방식을 유지한다.

제공자 연결 패널은 우측 사이드에서 메인 컬럼의 Provider·모델별 사용
원장 아래로 옮기고 반응형 그리드(너비에 따라 1~n열)로 배치한다.
This commit is contained in:
Yun Chan 2026-09-11 17:33:51 +09:00
parent e3a9fc717c
commit cb4d45579d
9 changed files with 752 additions and 39 deletions

View file

@ -224,6 +224,46 @@ export interface paths {
patch?: never;
trace?: never;
};
"/admin/providers/{provider}/oauth/finish": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Finish Provider Oauth
* @description 붙여넣은 인증 코드를 토큰으로 교환해 저장하고 게이트웨이에 push한다.
*/
post: operations["finish_provider_oauth_admin_providers__provider__oauth_finish_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/admin/providers/{provider}/oauth/start": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Start Provider Oauth
* @description OAuth 로그인 시작 — 제공자 인증 화면 URL을 발급한다.
*/
post: operations["start_provider_oauth_admin_providers__provider__oauth_start_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/admin/providers/{provider}/verify": {
parameters: {
query?: never;
@ -3024,6 +3064,11 @@ export interface components {
last_verify_error?: string | null;
/** Last Verify Ok */
last_verify_ok?: boolean | null;
/**
* Oauth Supported
* @default false
*/
oauth_supported: boolean;
/** Provider */
provider: string;
/** Token Hint */
@ -3054,6 +3099,24 @@ export interface components {
/** Synced */
synced: boolean;
};
/** AdminProviderOAuthFinishRequest */
AdminProviderOAuthFinishRequest: {
/** Code */
code: string;
/** State */
state: string;
};
/** AdminProviderOAuthStartResponse */
AdminProviderOAuthStartResponse: {
/** Authorize Url */
authorize_url: string;
/** Expires In */
expires_in: number;
/** Provider */
provider: string;
/** State */
state: string;
};
/** AdminProviderVerifyResponse */
AdminProviderVerifyResponse: {
/** Detail */
@ -12103,6 +12166,78 @@ export interface operations {
};
};
};
finish_provider_oauth_admin_providers__provider__oauth_finish_post: {
parameters: {
query?: never;
header?: never;
path: {
provider: string;
};
cookie?: {
"__Host-vignette_sid"?: string | null;
vignette_sid?: string | null;
};
};
requestBody: {
content: {
"application/json": components["schemas"]["AdminProviderOAuthFinishRequest"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["AdminProviderCredentialResponse"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
start_provider_oauth_admin_providers__provider__oauth_start_post: {
parameters: {
query?: never;
header?: never;
path: {
provider: string;
};
cookie?: {
"__Host-vignette_sid"?: string | null;
vignette_sid?: string | null;
};
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["AdminProviderOAuthStartResponse"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
verify_provider_credential_admin_providers__provider__verify_post: {
parameters: {
query?: never;