fix: Bearer 토큰 인증으로 전환 — 쿠키 프록시 이슈 해결
Caddy 프록시를 거치면서 httpOnly 쿠키가 제대로 전달 안 되는 문제. 로그인 시 받은 토큰을 메모리에 저장하고 Authorization: Bearer 헤더로 전송하는 방식으로 변경. 쿠키 의존성 제거. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,27 +1,43 @@
|
|||||||
const BASE = '';
|
const BASE = '';
|
||||||
|
|
||||||
|
// Store token in memory for Bearer auth (more reliable than cookies through proxies)
|
||||||
|
let _token: string | null = null;
|
||||||
|
|
||||||
|
export function setToken(token: string | null) {
|
||||||
|
_token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
function authHeaders(): Record<string, string> {
|
||||||
|
const h: Record<string, string> = { 'Content-Type': 'application/json' };
|
||||||
|
if (_token) h['Authorization'] = `Bearer ${_token}`;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
export async function login(password: string): Promise<{ role: string; token: string }> {
|
export async function login(password: string): Promise<{ role: string; token: string }> {
|
||||||
const res = await fetch(`${BASE}/auth/login`, {
|
const res = await fetch(`${BASE}/auth/login`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
credentials: 'include',
|
|
||||||
body: JSON.stringify({ password }),
|
body: JSON.stringify({ password }),
|
||||||
});
|
});
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const err = await res.json().catch(() => null);
|
const err = await res.json().catch(() => null);
|
||||||
throw new Error(err?.error?.message || 'Login failed');
|
throw new Error(err?.error?.message || 'Login failed');
|
||||||
}
|
}
|
||||||
return res.json();
|
const data = await res.json();
|
||||||
|
_token = data.token;
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getMe(): Promise<{ role: string } | null> {
|
export async function getMe(): Promise<{ role: string } | null> {
|
||||||
const res = await fetch(`${BASE}/auth/me`, { credentials: 'include' });
|
if (!_token) return null;
|
||||||
if (!res.ok) return null;
|
const res = await fetch(`${BASE}/auth/me`, { headers: authHeaders() });
|
||||||
|
if (!res.ok) { _token = null; return null; }
|
||||||
return res.json();
|
return res.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function logout(): Promise<void> {
|
export async function logout(): Promise<void> {
|
||||||
await fetch(`${BASE}/auth/logout`, { method: 'POST', credentials: 'include' });
|
await fetch(`${BASE}/auth/logout`, { method: 'POST', headers: authHeaders() });
|
||||||
|
_token = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Model {
|
export interface Model {
|
||||||
@@ -33,7 +49,7 @@ export interface Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getModels(): Promise<Model[]> {
|
export async function getModels(): Promise<Model[]> {
|
||||||
const res = await fetch(`${BASE}/v1/models`, { credentials: 'include' });
|
const res = await fetch(`${BASE}/v1/models`, { headers: authHeaders() });
|
||||||
if (!res.ok) return [];
|
if (!res.ok) return [];
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
return data.data || [];
|
return data.data || [];
|
||||||
@@ -73,8 +89,7 @@ export async function* streamChat(
|
|||||||
): AsyncGenerator<string, void> {
|
): AsyncGenerator<string, void> {
|
||||||
const res = await fetch(`${BASE}/v1/chat/completions`, {
|
const res = await fetch(`${BASE}/v1/chat/completions`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: authHeaders(),
|
||||||
credentials: 'include',
|
|
||||||
body: JSON.stringify({ model, messages, stream: true }),
|
body: JSON.stringify({ model, messages, stream: true }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user