{"id":991,"date":"2026-05-04T17:10:08","date_gmt":"2026-05-04T22:10:08","guid":{"rendered":"https:\/\/cuart.co\/?page_id=991"},"modified":"2026-05-05T11:24:35","modified_gmt":"2026-05-05T16:24:35","slug":"entra-login-page","status":"publish","type":"page","link":"https:\/\/cuart.co\/en\/entra-login-page\/","title":{"rendered":"Entra Login Page"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\" \/>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\/>\n  <title>Secure Portal \u2014 Microsoft Entra SSO<\/title>\n  <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Sora:wght@300;400;500;600;700&#038;family=DM+Mono:wght@400;500&#038;display=swap\" rel=\"stylesheet\"\/>\n  <style>\n    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n    :root {\n      --bg:      #06080f; --surface: #0d1117; --panel: #111823;\n      --border:  rgba(255,255,255,0.07); --accent: #0078d4;\n      --accent2: #50e6ff; --text: #e8eaf0; --muted: #6b7280;\n      --success: #22d3a0; --warn: #f59e0b;\n      --mono: 'DM Mono', monospace; --sans: 'Sora', sans-serif;\n    }\n    html, body { height: 100%; background: var(--bg); color: var(--text); font-family: var(--sans); overflow-x: hidden; }\n    body::before {\n      content: ''; position: fixed; inset: 0; pointer-events: none; z-index: 0;\n      background-image: linear-gradient(rgba(0,120,212,.04) 1px,transparent 1px),\n                        linear-gradient(90deg,rgba(0,120,212,.04) 1px,transparent 1px);\n      background-size: 48px 48px; animation: gridDrift 30s linear infinite;\n    }\n    @keyframes gridDrift { from{background-position:0 0} to{background-position:48px 48px} }\n    .orb { position:fixed; border-radius:50%; filter:blur(90px); opacity:.18; pointer-events:none; z-index:0; }\n    .orb-1 { width:520px; height:520px; background:#0078d4; top:-160px; left:-160px; }\n    .orb-2 { width:400px; height:400px; background:#50e6ff; bottom:-120px; right:-80px; }\n    .page { position:relative; z-index:1; min-height:100vh; display:flex; flex-direction:column; align-items:center; justify-content:center; padding:2rem 1rem; }\n    .card {\n      width:100%; max-width:520px; background:var(--panel); border:1px solid var(--border);\n      border-radius:20px; padding:2.6rem 2.4rem;\n      box-shadow:0 32px 80px rgba(0,0,0,.6),0 0 0 1px rgba(0,120,212,.08);\n      animation:cardIn .55s cubic-bezier(.22,1,.36,1) both;\n    }\n    @keyframes cardIn { from{opacity:0;transform:translateY(28px) scale(.97)} to{opacity:1;transform:translateY(0) scale(1)} }\n    .wordmark { display:flex; align-items:center; gap:.6rem; margin-bottom:2rem; }\n    .ms-icon { display:grid; grid-template-columns:1fr 1fr; gap:3px; width:22px; height:22px; flex-shrink:0; }\n    .ms-icon span { border-radius:2px; }\n    .ms-icon span:nth-child(1){background:#f25022} .ms-icon span:nth-child(2){background:#7fba00}\n    .ms-icon span:nth-child(3){background:#00a4ef} .ms-icon span:nth-child(4){background:#ffb900}\n    .wordmark-text { font-size:.78rem; font-weight:500; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); }\n    h1 { font-size:1.85rem; font-weight:700; line-height:1.15; letter-spacing:-.02em; margin-bottom:.55rem; }\n    h1 span { background:linear-gradient(135deg,#fff 0%,var(--accent2) 100%); -webkit-background-clip:text; -webkit-text-fill-color:transparent; }\n    .subtitle { font-size:.88rem; color:var(--muted); line-height:1.6; margin-bottom:2rem; }\n    .btn-ms {\n      width:100%; padding:.85rem 1.2rem; display:flex; align-items:center; justify-content:center; gap:.75rem;\n      background:var(--accent); border:none; border-radius:10px; color:#fff;\n      font-family:var(--sans); font-size:.92rem; font-weight:600; cursor:pointer;\n      position:relative; overflow:hidden; transition:background .2s,transform .15s,box-shadow .2s;\n      box-shadow:0 4px 24px rgba(0,120,212,.35);\n    }\n    .btn-ms:hover { background:#106ebe; box-shadow:0 6px 32px rgba(0,120,212,.5); transform:translateY(-1px); }\n    .btn-ms:active { transform:translateY(0); }\n    .btn-ms:disabled { opacity:.5; cursor:not-allowed; }\n    .spinner { width:16px; height:16px; border-radius:50%; border:2px solid rgba(255,255,255,.3); border-top-color:#fff; animation:spin .7s linear infinite; display:inline-block; }\n    @keyframes spin { to{transform:rotate(360deg)} }\n    .status { margin-top:1.2rem; padding:.75rem 1rem; border-radius:8px; font-size:.82rem; line-height:1.5; display:none; }\n    .status.error { display:block; background:rgba(239,68,68,.1); border:1px solid rgba(239,68,68,.25); color:#fca5a5; }\n    .status.info  { display:block; background:rgba(0,120,212,.1);  border:1px solid rgba(0,120,212,.25); color:#93c5fd; }\n    \/* success view *\/\n    .success-panel { display:none; }\n    .success-panel.visible { display:block; animation:cardIn .5s cubic-bezier(.22,1,.36,1) both; }\n    .success-badge { display:flex; align-items:center; gap:.6rem; margin-bottom:1.4rem; }\n    .check-circle { width:32px; height:32px; border-radius:50%; background:rgba(34,211,160,.15); border:1px solid rgba(34,211,160,.35); display:flex; align-items:center; justify-content:center; flex-shrink:0; }\n    .check-circle svg { width:14px; height:14px; stroke:var(--success); }\n    .success-badge p { font-size:.85rem; color:var(--success); font-weight:600; }\n    .user-row { display:flex; align-items:center; gap:.9rem; background:var(--surface); border:1px solid var(--border); border-radius:10px; padding:.85rem 1rem; margin-bottom:1.4rem; }\n    .avatar { width:36px; height:36px; border-radius:50%; background:linear-gradient(135deg,var(--accent),var(--accent2)); display:flex; align-items:center; justify-content:center; font-size:.9rem; font-weight:700; color:#fff; flex-shrink:0; }\n    .user-info p:first-child { font-size:.88rem; font-weight:600; }\n    .user-info p:last-child  { font-size:.76rem; color:var(--muted); }\n    \/* token \/ data sections *\/\n    .section { margin-bottom:1.1rem; }\n    .section-label { font-size:.68rem; font-weight:600; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); margin-bottom:.4rem; display:flex; align-items:center; gap:.5rem; }\n    .section-label .badge { font-size:.62rem; padding:.15em .45em; border-radius:4px; font-weight:600; letter-spacing:.04em; }\n    .badge-pending { background:rgba(245,158,11,.15); color:var(--warn); border:1px solid rgba(245,158,11,.25); }\n    .badge-ok      { background:rgba(34,211,160,.12); color:var(--success); border:1px solid rgba(34,211,160,.25); }\n    .badge-err     { background:rgba(239,68,68,.1); color:#fca5a5; border:1px solid rgba(239,68,68,.2); }\n    .data-box {\n      background:var(--surface); border:1px solid var(--border); border-radius:10px;\n      padding:.8rem 1rem; font-family:var(--mono); font-size:.77rem;\n      color:var(--accent2); word-break:break-all; line-height:1.65;\n      max-height:100px; overflow-y:auto;\n    }\n    .data-box.muted  { color:var(--muted); font-family:var(--sans); font-style:italic; font-size:.8rem; }\n    .data-box.spin-state { color:var(--muted); font-family:var(--sans); font-size:.8rem; display:flex; align-items:center; gap:.5rem; }\n    \/* subscription result card *\/\n    .sub-card { background:var(--surface); border:1px solid var(--border); border-radius:12px; padding:1rem 1.1rem; margin-bottom:1.1rem; }\n    .sub-card.error-card { border-color:rgba(239,68,68,.25); }\n    .sub-grid { display:grid; grid-template-columns:1fr 1fr; gap:.55rem .8rem; }\n    .sub-field label { font-size:.65rem; font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--muted); display:block; margin-bottom:.15rem; }\n    .sub-field span  { font-size:.82rem; color:var(--text); font-family:var(--mono); word-break:break-all; }\n    .sub-field.full  { grid-column:1\/-1; }\n    .status-pill { display:inline-block; padding:.2em .55em; border-radius:5px; font-size:.72rem; font-weight:600; }\n    .pill-pending     { background:rgba(245,158,11,.15); color:var(--warn); }\n    .pill-subscribed  { background:rgba(34,211,160,.12); color:var(--success); }\n    .pill-suspended   { background:rgba(239,68,68,.1);   color:#fca5a5; }\n    .pill-unsubscribed{ background:rgba(107,114,128,.15); color:var(--muted); }\n    \/* copy + signout buttons *\/\n    .copy-btn { margin-top:.45rem; padding:.32rem .75rem; background:transparent; border:1px solid var(--border); border-radius:6px; color:var(--muted); font-family:var(--sans); font-size:.73rem; cursor:pointer; transition:all .15s; }\n    .copy-btn:hover { border-color:var(--accent); color:var(--accent); }\n    .copy-btn.copied { border-color:var(--success); color:var(--success); }\n    .btn-resolve { width:100%; padding:.8rem 1.2rem; background:var(--accent); border:none; border-radius:10px; color:#fff; font-family:var(--sans); font-size:.88rem; font-weight:600; cursor:pointer; transition:background .2s,transform .15s,box-shadow .2s; box-shadow:0 4px 24px rgba(0,120,212,.3); display:flex; align-items:center; justify-content:center; gap:.6rem; margin-bottom:.5rem; }\n    .btn-resolve:hover { background:#106ebe; transform:translateY(-1px); box-shadow:0 6px 28px rgba(0,120,212,.45); }\n    .btn-resolve:active { transform:translateY(0); }\n    .btn-resolve:disabled { opacity:.5; cursor:not-allowed; }\n    .btn-activate { width:100%; padding:.8rem 1.2rem; background:rgba(34,211,160,.15); border:1px solid rgba(34,211,160,.4); border-radius:10px; color:var(--success); font-family:var(--sans); font-size:.88rem; font-weight:600; cursor:pointer; transition:all .2s; display:flex; align-items:center; justify-content:center; gap:.6rem; margin-bottom:.5rem; }\n    .btn-activate:hover { background:rgba(34,211,160,.25); border-color:var(--success); transform:translateY(-1px); }\n    .btn-activate:active { transform:translateY(0); }\n    .btn-activate:disabled { opacity:.5; cursor:not-allowed; }\n    .btn-signout { width:100%; padding:.7rem; background:transparent; border:1px solid var(--border); border-radius:10px; color:var(--muted); font-family:var(--sans); font-size:.84rem; cursor:pointer; margin-top:.6rem; transition:all .2s; }\n    .btn-signout:hover { border-color:rgba(239,68,68,.4); color:#fca5a5; }\n    .footer { margin-top:1.6rem; font-size:.72rem; color:var(--muted); text-align:center; }\n    .footer a { color:var(--muted); text-decoration:underline dotted; }\n    .config-notice { background:rgba(255,184,0,.07); border:1px solid rgba(255,184,0,.2); border-radius:10px; padding:.9rem 1.1rem; margin-bottom:1.4rem; font-size:.79rem; color:#fde68a; line-height:1.6; }\n    .config-notice strong { display:block; margin-bottom:.2rem; }\n    .config-notice code { background:rgba(0,0,0,.3); border-radius:4px; padding:.1em .35em; font-family:var(--mono); }\n    .divider { height:1px; background:var(--border); margin:1.2rem 0; }\n  <\/style>\n<\/head>\n<body>\n<div class=\"orb orb-1\"><\/div>\n<div class=\"orb orb-2\"><\/div>\n<div class=\"page\">\n  <div class=\"card\">\n\n    <div class=\"wordmark\">\n      <div class=\"ms-icon\"><span><\/span><span><\/span><span><\/span><span><\/span><\/div>\n      <span class=\"wordmark-text\">Microsoft Marketplace \u00b7 SaaS Landing Page<\/span>\n    <\/div>\n\n    <!-- LOGIN VIEW -->\n    <div id=\"loginView\">\n      <h1><span>Activate Your Subscription<\/span><\/h1>\n      <p class=\"subtitle\">Sign in with your Microsoft account to verify your identity and resolve your marketplace subscription purchase.<\/p>\n      <div class=\"config-notice\" id=\"configNotice\" style=\"display:none\">\n        <strong>&#9881; Configuration Required<\/strong>\n        Two separate app registrations are needed:\n        <br><br>\n        <strong>1. Landing page app<\/strong> (used by MSAL for SSO login) &rarr; set <code>CLIENT_ID<\/code> and <code>TENANT_ID<\/code> below.<br>\n        <strong>2. Publisher app<\/strong> (registered in Partner Center &rarr; your SaaS offer &rarr; Technical configuration &rarr; Microsoft Entra application) &rarr; set as <code>TENANT_ID<\/code>, <code>CLIENT_ID<\/code> and <code>CLIENT_SECRET<\/code> Worker secrets. This must be a different app from the landing page app.\n      <\/div>\n      <button class=\"btn-ms\" id=\"loginBtn\">\n        <div class=\"ms-icon\" style=\"width:18px;height:18px\"><span><\/span><span><\/span><span><\/span><span><\/span><\/div>\n        <span id=\"loginBtnText\">Sign in with Microsoft<\/span>\n      <\/button>\n      <div class=\"status\" id=\"statusMsg\"><\/div>\n    <\/div>\n\n    <!-- SUCCESS VIEW -->\n    <div id=\"successView\" class=\"success-panel\">\n\n      <div class=\"success-badge\">\n        <div class=\"check-circle\">\n          <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"\/><\/svg>\n        <\/div>\n        <p>Identity verified<\/p>\n      <\/div>\n\n      <div class=\"user-row\">\n        <div class=\"avatar\" id=\"userAvatar\">?<\/div>\n        <div class=\"user-info\"><p id=\"userName\">\u2014<\/p><p id=\"userEmail\">\u2014<\/p><\/div>\n      <\/div>\n\n      <div class=\"divider\"><\/div>\n\n      <!-- Marketplace token -->\n      <div class=\"section\" style=\"display:none\">\n        <div class=\"section-label\">x-ms-marketplace-token (URL parameter)<\/div>\n        <div class=\"data-box muted\" id=\"urlTokenBox\">No ?token= found in URL.<\/div>\n        <button class=\"copy-btn\" id=\"copyUrlTokenBtn\" style=\"display:none\">Copy<\/button>\n      <\/div>\n\n      <!-- Entra access token -->\n      <div class=\"section\" style=\"display:none\">\n        <div class=\"section-label\">Entra Access Token (Bearer)<\/div>\n        <div class=\"data-box spin-state\" id=\"entraTokenBox\"><span class=\"spinner\"><\/span> Acquiring&hellip;<\/div>\n        <button class=\"copy-btn\" id=\"copyEntraBtn\" style=\"display:none\">Copy<\/button>\n      <\/div>\n\n      <div class=\"divider\"><\/div>\n\n      <!-- Resolve API -->\n      <div class=\"section\">\n        <div class=\"section-label\">\n          Resolve API &mdash; Subscription Details\n          <span class=\"badge badge-pending\" id=\"resolveStatus\" style=\"display:none\"><\/span>\n        <\/div>\n        <div id=\"resolveResult\" style=\"display:none\"><\/div>\n      <\/div>\n\n      <button class=\"btn-resolve\" id=\"resolveBtn\">\n        Resolve subscription\n      <\/button>\n\n      <!-- Activate section \u2014 shown only after a successful resolve -->\n      <div id=\"activateSection\" style=\"display:none\">\n        <div class=\"divider\"><\/div>\n        <div class=\"section\">\n          <div class=\"section-label\">\n            Activate Subscription\n            <span class=\"badge badge-pending\" id=\"activateStatus\" style=\"display:none\"><\/span>\n          <\/div>\n          <div id=\"activateResult\" style=\"display:none\"><\/div>\n        <\/div>\n        <button class=\"btn-activate\" id=\"activateBtn\">\n          Activate subscription\n        <\/button>\n      <\/div>\n\n      <button class=\"btn-signout\" id=\"signoutBtn\">Sign out<\/button>\n    <\/div>\n\n    <div class=\"footer\">\n      Protected by <a href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/identity\/\" target=\"_blank\">Microsoft Entra ID<\/a>\n      &nbsp;&middot;&nbsp;\n      <a href=\"https:\/\/learn.microsoft.com\/en-us\/partner-center\/marketplace-offers\/pc-saas-fulfillment-subscription-api\" target=\"_blank\">SaaS Fulfillment API<\/a>\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\nfunction init() {\n  \/\/ \u2500\u2500 CONFIG \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  var CLIENT_ID    = \"15286b07-e97d-4d34-8191-652107b05c64\";\n    var TENANT_ID    = \"1221bc1d-e762-48f4-a7a5-6a5fafd089f7\";\n    var REDIRECT_URI = window.location.origin + '\/entra-login-page';\n  var PROXY_URL  = \"https:\/\/marketplace-token-proxy.cuart.workers.dev\/resolve\"; \/\/ Cloudflare Worker URL\n  \/\/ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n  var urlToken      = new URLSearchParams(window.location.search).get(\"token\");\n  var entraToken    = null;\n\n  if (CLIENT_ID === \"YOUR_CLIENT_ID\" || PROXY_URL.indexOf(\"YOUR_WORKER\") !== -1) {\n    document.getElementById(\"configNotice\").style.display = \"block\";\n  }\n\n  var pca = new msal.PublicClientApplication({\n    auth: { clientId: CLIENT_ID, authority: \"https:\/\/login.microsoftonline.com\/\" + TENANT_ID, redirectUri: REDIRECT_URI },\n    cache: { cacheLocation: \"sessionStorage\", storeAuthStateInCookie: false }\n  });\n\n  var loginRequest = { scopes: [\"openid\", \"profile\", \"email\", \"User.Read\"] };\n\n  \/\/ \u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function setStatus(msg, type) {\n    var el = document.getElementById(\"statusMsg\");\n    el.textContent = msg; el.className = \"status \" + (type || \"\");\n  }\n\n  function setLoading(on) {\n    var btn = document.getElementById(\"loginBtn\");\n    var txt = document.getElementById(\"loginBtnText\");\n    btn.disabled = !!on;\n    txt.innerHTML = on ? '<span class=\"spinner\"><\/span>&nbsp;Signing in\\u2026' : \"Sign in with Microsoft\";\n  }\n\n  function copyText(text, btnId) {\n    navigator.clipboard.writeText(text).then(function() {\n      var btn = document.getElementById(btnId);\n      btn.textContent = \"\\u2713 Copied!\"; btn.classList.add(\"copied\");\n      setTimeout(function() { btn.textContent = \"Copy\"; btn.classList.remove(\"copied\"); }, 2000);\n    });\n  }\n\n  function generateGuid() {\n    return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(\/[xy]\/g, function(c) {\n      var r = Math.random() * 16 | 0;\n      return (c === \"x\" ? r : (r & 0x3 | 0x8)).toString(16);\n    });\n  }\n\n  \/\/ \u2500\u2500 show user info & tokens \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function showSuccess(account) {\n    var name     = account.name || account.username || \"User\";\n    var email    = account.username || \"\";\n    var initials = name.split(\" \").map(function(n) { return n[0]; }).join(\"\").slice(0,2).toUpperCase();\n    document.getElementById(\"userAvatar\").textContent = initials;\n    document.getElementById(\"userName\").textContent   = name;\n    document.getElementById(\"userEmail\").textContent  = email;\n\n    \/\/ URL token\n    var urlBox = document.getElementById(\"urlTokenBox\");\n    if (urlToken) {\n      urlBox.textContent = urlToken;\n      urlBox.classList.remove(\"muted\");\n      document.getElementById(\"copyUrlTokenBtn\").style.display = \"inline-block\";\n    }\n\n    document.getElementById(\"loginView\").style.display = \"none\";\n    document.getElementById(\"successView\").classList.add(\"visible\");\n  }\n\n  \/\/ \u2500\u2500 display the entra token \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function showEntraToken(token) {\n    entraToken = token;\n    var box = document.getElementById(\"entraTokenBox\");\n    box.textContent = token;\n    box.classList.remove(\"spin-state\");\n    document.getElementById(\"copyEntraBtn\").style.display = \"inline-block\";\n  }\n\n  \/\/ \u2500\u2500 reset resolve button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function resetResolveBtn() {\n    var btn = document.getElementById(\"resolveBtn\");\n    btn.disabled = false;\n    btn.textContent = \"Resolve subscription\";\n  }\n\n  \/\/ \u2500\u2500 call Resolve API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function callResolveApi(accessToken) {\n    if (!urlToken) {\n      showResolveError(\"No marketplace token found in URL (?token=). Cannot call Resolve API.\");\n      return;\n    }\n\n    var endpoint = \"https:\/\/marketplaceapi.microsoft.com\/api\/saas\/subscriptions\/resolve?api-version=2018-08-31\";\n\n    \/\/ The marketplace token may be URL-encoded in the query string; decode it before sending.\n    var decodedMarketplaceToken;\n    try { decodedMarketplaceToken = decodeURIComponent(urlToken); }\n    catch(e) { decodedMarketplaceToken = urlToken; }\n\n    document.getElementById(\"resolveResult\").style.display = \"block\";\n\n    fetch(endpoint, {\n      method: \"POST\",\n      headers: {\n        \"Content-Type\":          \"application\/json\",\n        \"Authorization\":         \"Bearer \" + accessToken,\n        \"x-ms-marketplace-token\": decodedMarketplaceToken,\n        \"x-ms-requestid\":        generateGuid(),\n        \"x-ms-correlationid\":    generateGuid()\n      }\n    })\n    .then(function(resp) {\n      var status = resp.status;\n      resetResolveBtn();\n      if (resp.ok) {\n        return resp.json().then(function(data) { showResolveSuccess(data); });\n      }\n      return resp.text().then(function(body) {\n        var detail = \"\";\n        try { detail = JSON.parse(body).message || body; } catch(e) { detail = body; }\n        showResolveError(\"HTTP \" + status + \": \" + (detail || resp.statusText));\n      });\n    })\n    .catch(function(err) {\n      resetResolveBtn();\n      showResolveError(\"Network error: \" + (err.message || String(err)));\n    });\n  }\n\n  \/\/ \u2500\u2500 render resolve success \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function showResolveSuccess(data) {\n    var badge = document.getElementById(\"resolveStatus\");\n    badge.textContent = \"200 OK\"; badge.className = \"badge badge-ok\"; badge.style.display = \"\";\n\n    var sub = data.subscription || {};\n    var statusVal = (sub.saasSubscriptionStatus || data.saasSubscriptionStatus || \"\").trim();\n    var pillClass = {\n      \"PendingFulfillmentStart\": \"pill-pending\",\n      \"Subscribed\":              \"pill-subscribed\",\n      \"Suspended\":               \"pill-suspended\",\n      \"Unsubscribed\":            \"pill-unsubscribed\"\n    }[statusVal] || \"pill-pending\";\n\n    var term = sub.term || {};\n    var beneficiary = sub.beneficiary || {};\n    var purchaser   = sub.purchaser   || {};\n\n    function field(label, value, full) {\n      return '<div class=\"sub-field' + (full ? \" full\" : \"\") + '\">' +\n        '<label>' + label + '<\/label>' +\n        '<span>' + (value || '<span style=\"color:var(--muted)\">\u2014<\/span>') + '<\/span>' +\n        '<\/div>';\n    }\n\n    var html = '<div class=\"sub-card\">' +\n      '<div class=\"sub-grid\">' +\n        field(\"Subscription ID\",   data.id || sub.id) +\n        field(\"Status\", '<span class=\"status-pill ' + pillClass + '\">' + (statusVal || \"Unknown\") + '<\/span>') +\n        field(\"Subscription Name\", data.subscriptionName || sub.name, true) +\n        field(\"Offer ID\",   data.offerId  || sub.offerId) +\n        field(\"Plan ID\",    data.planId   || sub.planId) +\n        field(\"Quantity\",   data.quantity || sub.quantity || \"\u2014\") +\n        field(\"Publisher\",  sub.publisherId) +\n        field(\"Free Trial\", sub.isFreeTrial ? \"Yes\" : \"No\") +\n        field(\"Auto Renew\", sub.autoRenew  ? \"Yes\" : \"No\") +\n        field(\"Test Mode\",  sub.isTest     ? \"Yes\" : \"No\") +\n        (beneficiary.emailId ? field(\"Beneficiary\", beneficiary.emailId) : \"\") +\n        (purchaser.emailId   ? field(\"Purchaser\",   purchaser.emailId)   : \"\") +\n        (term.startDate ? field(\"Term Start\", term.startDate.split(\"T\")[0]) : \"\") +\n        (term.endDate   ? field(\"Term End\",   term.endDate.split(\"T\")[0])   : \"\") +\n        (term.termUnit  ? field(\"Term Unit\",  term.termUnit)                : \"\") +\n      '<\/div><\/div>';\n\n    document.getElementById(\"resolveResult\").innerHTML = html;\n  }\n\n  \/\/ \u2500\u2500 render resolve error \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function showResolveError(msg, diagLines) {\n    var badge = document.getElementById(\"resolveStatus\");\n    badge.textContent = \"Error\"; badge.className = \"badge badge-err\"; badge.style.display = \"\";\n\n    var diagHtml = \"\";\n    if (diagLines && diagLines.length > 0) {\n      diagHtml = '<div style=\"margin-top:.75rem;padding-top:.75rem;border-top:1px solid rgba(239,68,68,.2)\">' +\n        '<div style=\"font-size:.68rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:#f87171;margin-bottom:.4rem\">Diagnostics<\/div>' +\n        diagLines.map(function(l) {\n          return '<div style=\"font-family:var(--mono);font-size:.74rem;color:#fca5a5;word-break:break-all;margin-bottom:.2rem\">' + l + '<\/div>';\n        }).join(\"\") +\n        '<\/div>';\n    }\n\n    document.getElementById(\"resolveResult\").innerHTML =\n      '<div class=\"sub-card error-card\">' +\n        '<div style=\"color:#fca5a5;font-size:.82rem;line-height:1.6\">' + msg + '<\/div>' +\n        diagHtml +\n      '<\/div>';\n    document.getElementById(\"resolveResult\").style.display = \"block\";\n  }\n\n  \/\/ \u2500\u2500 acquire token and display it (no resolve yet) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function acquireAndShowToken(account, accessTokenFromLogin) {\n    if (accessTokenFromLogin) {\n      showEntraToken(accessTokenFromLogin);\n      return;\n    }\n    \/\/ Restoring a cached session: silent only, no popup.\n    var req = { scopes: [\"User.Read\"], account: account };\n    pca.acquireTokenSilent(req).then(function(result) {\n      showEntraToken(result.accessToken);\n    }).catch(function(err) {\n      console.error(\"Silent token acquisition failed:\", err);\n      var box = document.getElementById(\"entraTokenBox\");\n      box.textContent = \"Failed to acquire token silently. Please sign out and sign in again.\";\n      box.classList.remove(\"spin-state\"); box.classList.add(\"muted\");\n    });\n  }\n\n  \/\/ \u2500\u2500 resolve button handler \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  \/\/ Calls the Cloudflare Worker proxy which:\n  \/\/   1. Acquires a client_credentials token server-side (secret stays safe)\n  \/\/   2. Calls the Marketplace Resolve API\n  \/\/   3. Returns both the access token and the subscription data\n  function resolveSubscription() {\n    var btn = document.getElementById(\"resolveBtn\");\n    btn.disabled = true;\n    btn.innerHTML = '<span class=\"spinner\"><\/span>&nbsp;Resolving\u2026';\n    document.getElementById(\"resolveResult\").style.display = \"none\";\n    document.getElementById(\"resolveStatus\").style.display = \"none\";\n\n    if (!urlToken) {\n      resetResolveBtn();\n      showResolveError(\"No marketplace token found in URL (?token=). Cannot resolve.\");\n      document.getElementById(\"resolveResult\").style.display = \"block\";\n      return;\n    }\n\n    fetch(PROXY_URL, {\n      method:  \"POST\",\n      headers: { \"Content-Type\": \"application\/json\" },\n      body:    JSON.stringify({ marketplaceToken: urlToken }),\n    })\n    .then(function(resp) { return resp.json(); })\n    .then(function(data) {\n      resetResolveBtn();\n\n      \/\/ Show the access token the worker used\n      if (data.accessToken) {\n        showEntraToken(data.accessToken);\n      }\n\n      var apiStatus = data.marketplaceApiStatus || 0;\n\n      if (data.ok) {\n        var subData = data.body || data;\n        showResolveSuccess(subData);\n        \/\/ Store for activate call and show the activate section\n        window._resolvedSubscription = subData;\n        document.getElementById(\"activateSection\").style.display = \"block\";\n        var rb = document.getElementById(\"resolveBtn\");\n        rb.disabled = true; rb.textContent = \"Subscription resolved\";\n      } else {\n        \/\/ Build a detailed error message including diagnostics\n        var bodyMsg = \"\";\n        if (data.body) {\n          bodyMsg = data.body.message || data.body.error || data.body.raw || JSON.stringify(data.body);\n        }\n        var msg = data.error || (\"HTTP \" + apiStatus + (bodyMsg ? \": \" + bodyMsg : \"\"));\n\n        \/\/ Append key diagnostic fields if available\n        var diag = data.diagnostics || {};\n        var diagLines = [];\n        if (diag.requestId)     diagLines.push(\"Request ID: \"     + diag.requestId);\n        if (diag.correlationId) diagLines.push(\"Correlation ID: \" + diag.correlationId);\n        if (diag.accessTokenClaims) {\n          var c = diag.accessTokenClaims;\n          if (c.aud)   diagLines.push(\"Token audience: \" + (Array.isArray(c.aud) ? c.aud.join(\", \") : c.aud));\n          if (c.appid) diagLines.push(\"App ID: \"         + c.appid);\n          if (c.tid)   diagLines.push(\"Tenant ID: \"      + c.tid);\n          if (c.exp)   diagLines.push(\"Token expires: \"  + c.exp);\n        }\n        if (diag.marketplaceTokenPreview) diagLines.push(\"Marketplace token preview: \" + diag.marketplaceTokenPreview);\n        if (diag.responseHeaders && diag.responseHeaders[\"www-authenticate\"]) {\n          diagLines.push(\"WWW-Authenticate: \" + diag.responseHeaders[\"www-authenticate\"]);\n        }\n\n        showResolveError(msg, diagLines);\n      }\n    })\n    .catch(function(err) {\n      resetResolveBtn();\n      showResolveError(\"Network error calling proxy: \" + (err.message || String(err)));\n      document.getElementById(\"resolveResult\").style.display = \"block\";\n    });\n  }\n\n  \/\/ \u2500\u2500 sign in \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function signIn() {\n    setLoading(true);\n    pca.loginPopup(loginRequest).then(function(result) {\n      pca.setActiveAccount(result.account);\n      setLoading(false);\n      showSuccess(result.account);\n      \/\/ Show the token \u2014 resolve happens only when the button is pressed.\n      acquireAndShowToken(result.account, result.accessToken);\n    }).catch(function(err) {\n      console.error(err);\n      setStatus(\n        err.errorCode === \"user_cancelled\"     ? \"Sign-in was cancelled.\" :\n        err.errorCode === \"popup_window_error\" ? \"Popup blocked \\u2014 allow popups for this site and try again.\" :\n        \"Authentication error: \" + (err.message || err.errorCode || String(err)),\n        \"error\"\n      );\n      setLoading(false);\n    });\n  }\n\n  \/\/ \u2500\u2500 sign out \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function signOut() {\n    entraToken = null;\n    pca.logoutPopup({ account: pca.getActiveAccount() }).catch(function(){}).finally(function() {\n      document.getElementById(\"successView\").classList.remove(\"visible\");\n      document.getElementById(\"loginView\").style.display = \"block\";\n      \/\/ reset UI state\n      document.getElementById(\"entraTokenBox\").innerHTML = '<span class=\"spinner\"><\/span> Acquiring&hellip;';\n      document.getElementById(\"entraTokenBox\").className = \"data-box spin-state\";\n      document.getElementById(\"copyEntraBtn\").style.display = \"none\";\n      document.getElementById(\"resolveResult\").style.display = \"none\";\n      document.getElementById(\"resolveResult\").innerHTML = \"\";\n      document.getElementById(\"resolveStatus\").style.display = \"none\";\n      var rb = document.getElementById(\"resolveBtn\");\n      rb.disabled = false; rb.textContent = \"Resolve subscription\";\n      document.getElementById(\"activateSection\").style.display = \"none\";\n      document.getElementById(\"activateResult\").style.display = \"none\";\n      document.getElementById(\"activateResult\").innerHTML = \"\";\n      document.getElementById(\"activateStatus\").style.display = \"none\";\n      document.getElementById(\"activateBtn\").disabled = false;\n      document.getElementById(\"activateBtn\").textContent = \"Activate subscription\";\n      window._resolvedSubscription = null;\n      setStatus(\"\", \"\");\n    });\n  }\n\n  \/\/ \u2500\u2500 reset activate button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function resetActivateBtn() {\n    var btn = document.getElementById(\"activateBtn\");\n    btn.disabled = false;\n    btn.textContent = \"Activate subscription\";\n  }\n\n  \/\/ \u2500\u2500 activate subscription \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  function activateSubscription() {\n    var sub = window._resolvedSubscription;\n    if (!sub) { return; }\n\n    \/\/ Extract subscriptionId, planId, quantity from resolved data\n    var subscriptionId = sub.id || (sub.subscription && sub.subscription.id);\n    var planId         = sub.planId || (sub.subscription && sub.subscription.planId);\n    var quantity       = sub.quantity || (sub.subscription && sub.subscription.quantity) || undefined;\n\n    if (!subscriptionId || !planId) {\n      document.getElementById(\"activateResult\").style.display = \"block\";\n      document.getElementById(\"activateResult\").innerHTML =\n        '<div class=\"sub-card error-card\"><div style=\"color:#fca5a5;font-size:.82rem\">Could not find subscriptionId or planId in the resolved subscription data.<\/div><\/div>';\n      return;\n    }\n\n    var btn = document.getElementById(\"activateBtn\");\n    btn.disabled = true;\n    btn.innerHTML = '<span class=\"spinner\"><\/span>&nbsp;Activating\u2026';\n    document.getElementById(\"activateResult\").style.display = \"none\";\n    document.getElementById(\"activateStatus\").style.display = \"none\";\n\n    var activateUrl = PROXY_URL.replace(\"\/resolve\", \"\/activate\");\n\n    fetch(activateUrl, {\n      method:  \"POST\",\n      headers: { \"Content-Type\": \"application\/json\" },\n      body:    JSON.stringify({ subscriptionId: subscriptionId, planId: planId, quantity: quantity }),\n    })\n    .then(function(resp) { return resp.json(); })\n    .then(function(data) {\n      resetActivateBtn();\n      var badge = document.getElementById(\"activateStatus\");\n      var resultDiv = document.getElementById(\"activateResult\");\n      resultDiv.style.display = \"block\";\n\n      if (data.ok || data.marketplaceApiStatus === 200) {\n        badge.textContent = \"200 OK\"; badge.className = \"badge badge-ok\"; badge.style.display = \"\";\n        resultDiv.innerHTML =\n          '<div class=\"sub-card\" style=\"border-color:rgba(34,211,160,.3)\">' +\n            '<div style=\"display:flex;align-items:center;gap:.6rem\">' +\n              '<div style=\"width:28px;height:28px;border-radius:50%;background:rgba(34,211,160,.15);border:1px solid rgba(34,211,160,.35);display:flex;align-items:center;justify-content:center;flex-shrink:0\">' +\n                '<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#22d3a0\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"\/><\/svg>' +\n              '<\/div>' +\n              '<div>' +\n                '<div style=\"font-size:.88rem;font-weight:600;color:var(--success)\">Subscription activated successfully<\/div>' +\n                '<div style=\"font-size:.78rem;color:var(--muted);margin-top:.15rem\">The subscription is now marked as Subscribed. The customer will be billed.<\/div>' +\n              '<\/div>' +\n            '<\/div>' +\n            '<div style=\"margin-top:.8rem;padding-top:.8rem;border-top:1px solid var(--border);font-family:var(--mono);font-size:.75rem;color:var(--muted)\">' +\n              'Subscription ID: ' + subscriptionId + '<br>' +\n              'Plan: ' + planId + (quantity ? ' &nbsp;&middot;&nbsp; Quantity: ' + quantity : '') +\n            '<\/div>' +\n          '<\/div>';\n        \/\/ Disable activate button \u2014 already activated\n        var ab = document.getElementById(\"activateBtn\");\n        ab.disabled = true; ab.textContent = \"Subscription activated\";\n      } else {\n        badge.textContent = \"Error\"; badge.className = \"badge badge-err\"; badge.style.display = \"\";\n        var apiStatus = data.marketplaceApiStatus || \"\";\n        var bodyMsg = \"\";\n        if (data.body) bodyMsg = data.body.message || data.body.error || data.body.raw || JSON.stringify(data.body);\n        var msg = data.error || (\"HTTP \" + apiStatus + (bodyMsg ? \": \" + bodyMsg : \"\"));\n\n        var diagLines = [];\n        var diag = data.diagnostics || {};\n        if (diag.requestId)     diagLines.push(\"Request ID: \"     + diag.requestId);\n        if (diag.correlationId) diagLines.push(\"Correlation ID: \" + diag.correlationId);\n\n        var diagHtml = \"\";\n        if (diagLines.length) {\n          diagHtml = '<div style=\"margin-top:.75rem;padding-top:.75rem;border-top:1px solid rgba(239,68,68,.2)\">' +\n            '<div style=\"font-size:.68rem;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:#f87171;margin-bottom:.4rem\">Diagnostics<\/div>' +\n            diagLines.map(function(l) { return '<div style=\"font-family:var(--mono);font-size:.74rem;color:#fca5a5;word-break:break-all;margin-bottom:.2rem\">' + l + '<\/div>'; }).join(\"\") +\n            '<\/div>';\n        }\n        resultDiv.innerHTML =\n          '<div class=\"sub-card error-card\"><div style=\"color:#fca5a5;font-size:.82rem;line-height:1.6\">' + msg + '<\/div>' + diagHtml + '<\/div>';\n      }\n    })\n    .catch(function(err) {\n      resetActivateBtn();\n      document.getElementById(\"activateResult\").style.display = \"block\";\n      document.getElementById(\"activateResult\").innerHTML =\n        '<div class=\"sub-card error-card\"><div style=\"color:#fca5a5;font-size:.82rem\">Network error: ' + (err.message || String(err)) + '<\/div><\/div>';\n    });\n  }\n\n  \/\/ \u2500\u2500 wire up \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  document.getElementById(\"loginBtn\").addEventListener(\"click\", signIn);\n  document.getElementById(\"signoutBtn\").addEventListener(\"click\", signOut);\n  document.getElementById(\"resolveBtn\").addEventListener(\"click\", resolveSubscription);\n  document.getElementById(\"activateBtn\").addEventListener(\"click\", activateSubscription);\n  document.getElementById(\"copyUrlTokenBtn\").addEventListener(\"click\", function() { if (urlToken) copyText(urlToken, \"copyUrlTokenBtn\"); });\n  document.getElementById(\"copyEntraBtn\").addEventListener(\"click\", function() { if (entraToken) copyText(entraToken, \"copyEntraBtn\"); });\n\n  \/\/ \u2500\u2500 bootstrap: restore session if already logged in \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  pca.handleRedirectPromise().then(function(result) {\n    if (result && result.account) {\n      pca.setActiveAccount(result.account);\n      showSuccess(result.account);\n      acquireAndShowToken(result.account);\n      return;\n    }\n    var accounts = pca.getAllAccounts();\n    if (accounts.length > 0) {\n      pca.setActiveAccount(accounts[0]);\n      showSuccess(accounts[0]);\n      acquireAndShowToken(accounts[0]);\n    }\n  }).catch(function(err) {\n    console.error(\"Bootstrap error:\", err);\n    setStatus(\"Initialization error: \" + (err.message || err), \"error\");\n  });\n}\n<\/script>\n\n<script>\n(function() {\n  var cdns = [\n    \"https:\/\/alcdn.msauth.net\/browser\/2.38.3\/js\/msal-browser.min.js\",\n    \"https:\/\/cdn.jsdelivr.net\/npm\/@azure\/msal-browser@2.38.3\/lib\/msal-browser.min.js\",\n    \"https:\/\/unpkg.com\/@azure\/msal-browser@2.38.3\/lib\/msal-browser.min.js\"\n  ];\n  var idx = 0;\n  function loadNext() {\n    if (idx >= cdns.length) {\n      var el = document.getElementById(\"statusMsg\");\n      el.textContent = \"Could not load the Microsoft authentication library. Check your Content Security Policy or network connection.\";\n      el.className = \"status error\"; return;\n    }\n    var s = document.createElement(\"script\");\n    s.src = cdns[idx++];\n    s.onload = function() { init(); };\n    s.onerror = function() { loadNext(); };\n    document.body.appendChild(s);\n  }\n  loadNext();\n})();\n<\/script>\n<\/body>\n<\/html>\n\n","protected":false},"excerpt":{"rendered":"<p>Secure Portal \u2014 Microsoft Entra SSO Microsoft Marketplace \u00b7 SaaS Landing Page Activate Your Subscription Sign in with your Microsoft account to verify your identity and resolve your marketplace subscription purchase. &#9881; Configuration Required Two separate app registrations are needed: 1. Landing page app (used by MSAL for SSO login) &rarr; set CLIENT_ID and TENANT_ID [&#8230;]\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-991","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/cuart.co\/en\/wp-json\/wp\/v2\/pages\/991","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cuart.co\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/cuart.co\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/cuart.co\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cuart.co\/en\/wp-json\/wp\/v2\/comments?post=991"}],"version-history":[{"count":24,"href":"https:\/\/cuart.co\/en\/wp-json\/wp\/v2\/pages\/991\/revisions"}],"predecessor-version":[{"id":1018,"href":"https:\/\/cuart.co\/en\/wp-json\/wp\/v2\/pages\/991\/revisions\/1018"}],"wp:attachment":[{"href":"https:\/\/cuart.co\/en\/wp-json\/wp\/v2\/media?parent=991"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}