feat(frontend): 로그인 토큰을 Bearer 로 들고 다니게 — Django 백엔드 연결
Django(OpenCode 중계) 백엔드는 토큰을 쿠키가 아니라 응답 body 로 주고, Tauri 앱은
서버와 origin 이 달라 쿠키가 안 붙는다. 기존 tokenProvider seam 에 refresh 토큰과
localStorage 영속을 얹고, client/sse 의 refresh 를 body {refreshToken} 방식으로 바꿈.
로그인 때 저장하고 로그아웃 때 비움. 토큰 없으면 예전 쿠키 모드 그대로.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import MockAdapter from "axios-mock-adapter"
|
||||
import { apiClient, apiGet, apiPost, apiList } from "./client"
|
||||
import { ApiError } from "./errors"
|
||||
import { useSessionExpiryStore } from "@/features/auth/store/sessionExpiryStore"
|
||||
import { setAccessToken } from "@/lib/auth/tokenProvider"
|
||||
import { setAccessToken, setTokens, clearTokens, getAccessToken } from "@/lib/auth/tokenProvider"
|
||||
|
||||
const BASE = "http://localhost:8001/api/v1"
|
||||
|
||||
@@ -152,6 +152,31 @@ describe("401 인터셉터 — refresh 성공", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("401 인터셉터 — Bearer 모드 refresh", () => {
|
||||
afterEach(() => clearTokens())
|
||||
|
||||
it("refreshToken 있으면 body 로 보내고, 응답 토큰을 저장한 뒤 새 Bearer 로 재시도", async () => {
|
||||
setTokens({ token: "old", refreshToken: "ref" })
|
||||
const authHeaders: string[] = []
|
||||
clientMock.onGet("/users/me").reply((config) => {
|
||||
authHeaders.push(String(config.headers?.Authorization))
|
||||
return authHeaders.length === 1
|
||||
? [401, errorEnvelope({ statusCode: 401, message: "expired" })]
|
||||
: [200, envelope({ id: "u1" })]
|
||||
})
|
||||
globalMock
|
||||
.onPost(`${BASE}/auth/refresh`)
|
||||
.reply(200, envelope({ token: "new", refreshToken: "ref", tokenExpirationTime: 1 }))
|
||||
|
||||
await apiGet<{ id: string }>("/users/me")
|
||||
|
||||
const refreshReq = globalMock.history.post.find((r) => r.url?.endsWith("/auth/refresh"))
|
||||
expect(JSON.parse(refreshReq?.data as string)).toEqual({ refreshToken: "ref" })
|
||||
expect(getAccessToken()).toBe("new")
|
||||
expect(authHeaders).toEqual(["Bearer old", "Bearer new"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("401 인터셉터 — refresh 실패", () => {
|
||||
it("refresh가 401이면 sessionExpiryStore에 큐 push + open=true", async () => {
|
||||
clientMock.onGet("/users/me").reply(401, errorEnvelope({ statusCode: 401, message: "expired" }))
|
||||
|
||||
Reference in New Issue
Block a user