fix(auth): session secret'i response header'ından (X-Fallback-Cookies) oku
Sorun: - createEmailPasswordSession response body'sinde 'secret' alanı boş/redacted geliyor - Cookie'ye boş string yazılıyordu - requireUser() çağrısında account.get() 401 dönüyor → login'e geri redirect - Şifre doğru olsa bile bir döngüye giriyor Çözüm: - account.createEmailPasswordSession artık awRaw kullanıyor (Response objesi) - extractSessionFromHeaders helper'ı X-Fallback-Cookies (JSON) veya Set-Cookie header'ından gerçek session secret'i parse ediyor - Bu secret cookie'ye yazılıyor Browser SDK kaynağında 'cookieFallback' tam olarak bu mantığı kullanıyor — secret'i header'dan alıp localStorage'a yazıyor.
This commit is contained in:
+33
-3
@@ -42,7 +42,7 @@ type FetchOpts = {
|
|||||||
formData?: FormData;
|
formData?: FormData;
|
||||||
};
|
};
|
||||||
|
|
||||||
async function aw<T>(path: string, opts: FetchOpts = {}): Promise<T> {
|
async function awRaw(path: string, opts: FetchOpts = {}): Promise<Response> {
|
||||||
const url = new URL(ENDPOINT + path);
|
const url = new URL(ENDPOINT + path);
|
||||||
if (opts.query) {
|
if (opts.query) {
|
||||||
for (const [k, v] of Object.entries(opts.query)) {
|
for (const [k, v] of Object.entries(opts.query)) {
|
||||||
@@ -86,7 +86,11 @@ async function aw<T>(path: string, opts: FetchOpts = {}): Promise<T> {
|
|||||||
data.type,
|
data.type,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function aw<T>(path: string, opts: FetchOpts = {}): Promise<T> {
|
||||||
|
const res = await awRaw(path, opts);
|
||||||
const ct = res.headers.get("content-type") ?? "";
|
const ct = res.headers.get("content-type") ?? "";
|
||||||
if (ct.includes("application/json")) {
|
if (ct.includes("application/json")) {
|
||||||
return (await res.json()) as T;
|
return (await res.json()) as T;
|
||||||
@@ -94,6 +98,27 @@ async function aw<T>(path: string, opts: FetchOpts = {}): Promise<T> {
|
|||||||
return undefined as T;
|
return undefined as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractSessionFromHeaders(res: Response): string | null {
|
||||||
|
// Appwrite returns the session secret in X-Fallback-Cookies as JSON,
|
||||||
|
// or in Set-Cookie header. The response body may have empty/redacted secret.
|
||||||
|
const fallback = res.headers.get("x-fallback-cookies");
|
||||||
|
if (fallback) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(fallback) as Record<string, string>;
|
||||||
|
const first = Object.values(parsed)[0];
|
||||||
|
if (first) return first;
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const setCookie = res.headers.get("set-cookie");
|
||||||
|
if (setCookie) {
|
||||||
|
const m = setCookie.match(/a_session_[^=]+=([^;]+)/);
|
||||||
|
if (m?.[1]) return decodeURIComponent(m[1]);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Query helpers ───────────────────────────────────────────────
|
// ─── Query helpers ───────────────────────────────────────────────
|
||||||
|
|
||||||
export const Q = {
|
export const Q = {
|
||||||
@@ -149,11 +174,16 @@ export interface AwUser {
|
|||||||
// ─── Account ─────────────────────────────────────────────────────
|
// ─── Account ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
export const account = {
|
export const account = {
|
||||||
createEmailPasswordSession(email: string, password: string) {
|
async createEmailPasswordSession(email: string, password: string) {
|
||||||
return aw<AwSession>("/account/sessions/email", {
|
const res = await awRaw("/account/sessions/email", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: { email, password },
|
body: { email, password },
|
||||||
});
|
});
|
||||||
|
const body = (await res.json()) as AwSession;
|
||||||
|
// Appwrite redacts `secret` in the response body — read it from the
|
||||||
|
// X-Fallback-Cookies header (or Set-Cookie) where the real secret lives.
|
||||||
|
const secretFromHeader = extractSessionFromHeaders(res);
|
||||||
|
return { ...body, secret: secretFromHeader || body.secret };
|
||||||
},
|
},
|
||||||
get(session: string) {
|
get(session: string) {
|
||||||
return aw<AwUser>("/account", { session });
|
return aw<AwUser>("/account", { session });
|
||||||
|
|||||||
Reference in New Issue
Block a user