wsj-filenaming/auth_gate.php
Vadym Samoilenko f4b4630826 Add msalInstance.initialize() before MSAL API calls
MSAL Browser 2.28+ requires explicit initialize() before handleRedirectPromise()
or loginRedirect(). Without it the authorization request is generated with
missing parameters, causing AADSTS90014.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 09:50:38 +00:00

181 lines
6.8 KiB
PHP

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Signing In Dow Jones Job Naming Tool</title>
<link rel="stylesheet" href="style.css">
<style>
body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
margin: 0;
background: var(--bg-color);
}
.auth-card {
text-align: center;
padding: 48px 40px;
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 8px;
max-width: 400px;
width: 90%;
}
.auth-card h1 {
font-size: 1.2rem;
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: 8px;
}
.auth-card p {
color: var(--text-secondary);
margin-bottom: 32px;
font-size: 0.9rem;
}
.spinner-ring {
display: inline-block;
width: 40px;
height: 40px;
border: 3px solid var(--border-color);
border-top-color: var(--text-primary);
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin-bottom: 20px;
}
@keyframes spin { to { transform: rotate(360deg); } }
.auth-status {
font-size: 0.85rem;
color: var(--text-secondary);
margin-top: 16px;
}
.auth-error {
color: var(--danger-color, #e53e3e);
font-size: 0.85rem;
margin-top: 16px;
display: none;
}
.btn-signin {
display: none;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="auth-card">
<h1>Dow Jones Job Naming Tool</h1>
<p>Oliver Agency</p>
<div class="spinner-ring" id="authSpinner"></div>
<div class="auth-status" id="authStatus">Signing you in&hellip;</div>
<div class="auth-error" id="authError"></div>
<button id="signInBtn" class="btn btn-primary btn-signin">Sign In with Microsoft</button>
</div>
<script src="https://alcdn.msauth.net/browser/2.32.2/js/msal-browser.min.js"></script>
<script>
(function () {
const msalConfig = {
auth: {
clientId: '<?php echo AZURE_CLIENT_ID; ?>',
authority: 'https://login.microsoftonline.com/<?php echo AZURE_TENANT_ID; ?>',
redirectUri: '<?php echo AZURE_REDIRECT_URI; ?>'
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: true
}
};
const loginRequest = { scopes: ['openid', 'profile', 'email'] };
const msalInstance = new msal.PublicClientApplication(msalConfig);
function showError(msg) {
document.getElementById('authSpinner').style.display = 'none';
document.getElementById('authStatus').style.display = 'none';
document.getElementById('authError').textContent = msg;
document.getElementById('authError').style.display = 'block';
document.getElementById('signInBtn').style.display = 'inline-block';
}
async function init() {
await msalInstance.initialize();
try {
// Always call handleRedirectPromise first
const result = await msalInstance.handleRedirectPromise();
if (result && result.idToken) {
// We have a token — create server session
document.getElementById('authStatus').textContent = 'Verifying…';
const resp = await fetch('api.php?action=create_session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id_token: result.idToken })
});
const json = await resp.json();
if (json.success) {
// Restore original destination or default to index.php
const returnUrl = sessionStorage.getItem('auth_return_url') || 'index.php';
sessionStorage.removeItem('auth_return_url');
window.location.href = returnUrl;
} else {
showError('Sign-in failed: ' + (json.message || 'Unknown error'));
}
return;
}
// No redirect result — check for cached account
const accounts = msalInstance.getAllAccounts();
if (accounts.length > 0) {
// Has cached account but no PHP session — try silent token
try {
const silentResult = await msalInstance.acquireTokenSilent({
...loginRequest,
account: accounts[0]
});
const resp = await fetch('api.php?action=create_session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ id_token: silentResult.idToken })
});
const json = await resp.json();
if (json.success) {
const returnUrl = sessionStorage.getItem('auth_return_url') || 'index.php';
sessionStorage.removeItem('auth_return_url');
window.location.href = returnUrl;
return;
}
} catch (e) {
// Silent failed — fall through to redirect login
}
}
// No account / silent failed — store return URL and redirect to Azure
if (!sessionStorage.getItem('auth_return_url')) {
sessionStorage.setItem('auth_return_url', window.location.href);
}
await msalInstance.loginRedirect(loginRequest);
} catch (err) {
console.error('MSAL error:', err);
showError('Authentication error: ' + (err.message || String(err)));
}
}
// Manual sign-in button (shown only on error)
document.getElementById('signInBtn').addEventListener('click', async () => {
sessionStorage.setItem('auth_return_url', window.location.href);
await msalInstance.loginRedirect(loginRequest);
});
init();
})();
</script>
</body>
</html>