PaperMate / frontend /js /auth.js
Phuc-HugigFace's picture
feat(auth+db): session-aware nav, ownership fix, admin hardening, schema cleanup
73aafbd
Raw
History Blame
2.4 kB
// Supabase Auth helper (ES module). The frontend signs in with Google and
// sends the access token to the FastAPI backend as a Bearer token.
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
export const API_BASE =
window.location.protocol === "file:"
? "http://localhost:8000"
: window.location.origin;
let _client = null;
let _config = null;
async function getConfig() {
if (_config) return _config;
const resp = await fetch(`${API_BASE}/api/public-config`);
_config = await resp.json();
return _config;
}
export async function getClient() {
if (_client) return _client;
const cfg = await getConfig();
if (!cfg.supabase_url || !cfg.supabase_anon_key) {
throw new Error(
"Supabase chưa được cấu hình (thiếu SUPABASE_ANON_KEY trong .env)."
);
}
_client = createClient(cfg.supabase_url, cfg.supabase_anon_key, {
auth: { persistSession: true, autoRefreshToken: true, detectSessionInUrl: true },
});
return _client;
}
export async function signInWithGoogle(redirectTo) {
const supabase = await getClient();
return supabase.auth.signInWithOAuth({
provider: "google",
options: { redirectTo: redirectTo || window.location.href },
});
}
export async function getSession() {
const supabase = await getClient();
const { data } = await supabase.auth.getSession();
return data.session;
}
export async function getAccessToken() {
const session = await getSession();
return session ? session.access_token : null;
}
export async function signOut() {
const supabase = await getClient();
await supabase.auth.signOut();
}
export async function onAuthStateChange(cb) {
const supabase = await getClient();
return supabase.auth.onAuthStateChange(cb);
}
// fetch() wrapper that attaches the Bearer token to backend calls.
export async function authFetch(path, opts = {}) {
const token = await getAccessToken();
const headers = { ...(opts.headers || {}) };
if (token) headers["Authorization"] = `Bearer ${token}`;
const url = path.startsWith("http") ? path : `${API_BASE}${path}`;
return fetch(url, { ...opts, headers });
}
// Convenience: who am I (or null if not signed in / token rejected).
export async function getMe() {
const token = await getAccessToken();
if (!token) return null;
const resp = await authFetch("/api/me");
if (!resp.ok) return null;
return resp.json();
}