Fix local-auth sections not showing for normal users + backup-code modal signature
settings load2FAStatus():
- Explicit credentials: 'same-origin' on the /me fetch (was relying
on fetch defaults, which can behave oddly in some browsers/edges)
- Fall back to window.CURRENT_USER (cached at login) if /me fails,
so local-auth users still see their password/2FA sections after
a transient error. Keeps cache in sync on each successful fetch.
enterApp():
- Cache the logged-in user object on window.CURRENT_USER so modules
that need the canLocalAuth flag don't have to re-fetch /me.
2FA regenerate modal:
- Previous call passed a wrong-shape options object to showConfirm.
Updated to the correct (message, callback, opts) signature with
input:true, inputType:'password', placeholder, required.
OIDC email_verified check:
- Accept boolean true or string 'true' for robustness. Some IdPs
serialize ID-token booleans as strings.
This commit is contained in:
parent
c7a04626a3
commit
37e58be5ec
2 changed files with 24 additions and 12 deletions
|
|
@ -147,6 +147,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
|
||||
function enterApp(user, token) {
|
||||
window.AUTH_TOKEN = token;
|
||||
window.CURRENT_USER = user; // cached so settings page doesn't re-fetch /me just to read canLocalAuth
|
||||
if (isNativeApp()) {
|
||||
// Mobile: persist token to Keychain/Keystore
|
||||
window.SecureStorage.set(TOKEN_KEY, token);
|
||||
|
|
@ -356,15 +357,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
// Regenerate backup codes
|
||||
if (target.id === 'btn-regen-backup-codes' || target.closest('#btn-regen-backup-codes')) {
|
||||
e.preventDefault();
|
||||
showConfirm({
|
||||
title: 'Regenerate backup codes?',
|
||||
message: 'This will invalidate your existing backup codes and generate 10 new ones. Enter your current password.',
|
||||
inputType: 'password',
|
||||
inputPlaceholder: 'Current password',
|
||||
confirmText: 'Regenerate',
|
||||
required: true,
|
||||
requiredMsg: 'Password is required'
|
||||
}, function(pw) {
|
||||
showConfirm('Regenerate backup codes? This invalidates your existing ones. Enter your current password to confirm.', function(pw) {
|
||||
if (!pw) return;
|
||||
fetch('/api/auth/2fa/backup-codes', {
|
||||
method: 'POST', headers: getAuthHeaders(),
|
||||
|
|
@ -375,6 +368,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
if (data.success && data.codes) showBackupCodesModal(data.codes);
|
||||
else showToast(data.error || 'Failed to regenerate codes', 'error');
|
||||
});
|
||||
}, {
|
||||
input: true,
|
||||
inputType: 'password',
|
||||
placeholder: 'Current password',
|
||||
confirmText: 'Regenerate',
|
||||
required: true,
|
||||
requiredMsg: 'Password is required'
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -729,10 +729,20 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
|
||||
// ---- 2FA STATUS ----
|
||||
function load2FAStatus() {
|
||||
fetch('/api/auth/me', { headers: getAuthHeaders() })
|
||||
fetch('/api/auth/me', { credentials: 'same-origin', headers: getAuthHeaders() })
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(data) {
|
||||
if (!data || !data.user) return;
|
||||
if (!data || !data.user) {
|
||||
// /me failed — if we already have a cached user from login, fall back to that
|
||||
// so reloaded Settings pages still render for local-auth users.
|
||||
if (window.CURRENT_USER && window.CURRENT_USER.canLocalAuth === true) {
|
||||
data = { user: window.CURRENT_USER };
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Keep cache in sync
|
||||
window.CURRENT_USER = data.user;
|
||||
// Sections are display:none by default in the HTML. Only reveal them
|
||||
// if the server confirms this user has a real password hash
|
||||
// (canLocalAuth === true). SSO-auto-created users never see these UIs.
|
||||
|
|
|
|||
|
|
@ -203,7 +203,9 @@ router.get('/oidc/callback', async function(req, res) {
|
|||
return res.redirect(appUrl + '?error=sub_mismatch');
|
||||
}
|
||||
if (!user.oidc_sub) {
|
||||
if (emailVerified !== true) {
|
||||
// Some IdPs (rare) serialize booleans as strings — accept both.
|
||||
var verified = emailVerified === true || emailVerified === 'true';
|
||||
if (!verified) {
|
||||
console.warn('[OIDC] refusing to auto-link existing user ' + user.id + ' — IdP did not assert email_verified=true');
|
||||
return res.redirect(appUrl + '?error=email_unverified');
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue