auth gateway

This commit is contained in:
2026-03-09 12:53:56 +01:00
parent fb6cc59d69
commit b9fe5c294e
3 changed files with 74 additions and 1 deletions

View File

@@ -104,6 +104,7 @@
</div> </div>
<script src="js/data.js"></script> <script src="js/data.js"></script>
<script src="js/auth.js"></script>
<script src="js/app.js"></script> <script src="js/app.js"></script>
</body> </body>
</html> </html>

View File

@@ -284,7 +284,7 @@ checkBtn.addEventListener('click', async () => {
feedbackContent.innerHTML = '<div class="loading-dots"><span></span><span></span><span></span></div>'; feedbackContent.innerHTML = '<div class="loading-dots"><span></span><span></span><span></span></div>';
try { try {
const res = await fetch('api/check', { const res = await authFetch('api/check', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ body: JSON.stringify({

72
src/public/js/auth.js Normal file
View 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(() => {});