auth gateway
This commit is contained in:
@@ -104,6 +104,7 @@
|
||||
|
||||
</div>
|
||||
<script src="js/data.js"></script>
|
||||
<script src="js/auth.js"></script>
|
||||
<script src="js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -284,7 +284,7 @@ checkBtn.addEventListener('click', async () => {
|
||||
feedbackContent.innerHTML = '<div class="loading-dots"><span></span><span></span><span></span></div>';
|
||||
|
||||
try {
|
||||
const res = await fetch('api/check', {
|
||||
const res = await authFetch('api/check', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
|
||||
72
src/public/js/auth.js
Normal file
72
src/public/js/auth.js
Normal file
@@ -0,0 +1,72 @@
|
||||
// ── Guest Auth ────────────────────────────────────────────────────────────────
|
||||
const GUEST_EMAIL = "guest@gmail.com";
|
||||
const GUEST_PASSWORD = "Guest123!";
|
||||
|
||||
let _token = null;
|
||||
let _loginPromise = null;
|
||||
|
||||
async function guestLogin() {
|
||||
const res = await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email: GUEST_EMAIL, password: GUEST_PASSWORD }),
|
||||
});
|
||||
|
||||
if (res.status === 401) {
|
||||
// Guest doesn't exist yet — register
|
||||
const reg = await fetch('/api/auth/register', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
username: 'Guest',
|
||||
email: GUEST_EMAIL,
|
||||
password: GUEST_PASSWORD,
|
||||
confirmPassword: GUEST_PASSWORD,
|
||||
}),
|
||||
});
|
||||
if (!reg.ok) throw new Error('Guest registration failed');
|
||||
const regData = await reg.json();
|
||||
_token = regData.payload?.token ?? null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!res.ok) throw new Error('Guest login failed');
|
||||
const data = await res.json();
|
||||
_token = data.payload?.token ?? null;
|
||||
}
|
||||
|
||||
function ensureAuth() {
|
||||
if (!_loginPromise) {
|
||||
_loginPromise = guestLogin().catch(err => {
|
||||
_loginPromise = null;
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
return _loginPromise;
|
||||
}
|
||||
|
||||
// Authenticated fetch: adds Bearer token, retries once on 401
|
||||
async function authFetch(url, options = {}) {
|
||||
await ensureAuth();
|
||||
|
||||
const doRequest = () => {
|
||||
const headers = { ...(options.headers || {}) };
|
||||
if (_token) headers['Authorization'] = `Bearer ${_token}`;
|
||||
return fetch(url, { ...options, headers });
|
||||
};
|
||||
|
||||
let res = await doRequest();
|
||||
|
||||
if (res.status === 401) {
|
||||
// Token expired — re-login and retry once
|
||||
_loginPromise = null;
|
||||
_token = null;
|
||||
await ensureAuth();
|
||||
res = await doRequest();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Kick off login immediately on page load (fire-and-forget)
|
||||
ensureAuth().catch(() => {});
|
||||
Reference in New Issue
Block a user