auth gateway
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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
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