Add SSO and device management samples
This commit is contained in:
131
sso.html
Normal file
131
sso.html
Normal file
@@ -0,0 +1,131 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>amiPro SSO</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 0; padding: 24px; background: #f5f5f7; color: #1f2430; }
|
||||
.card { background: #fff; border-radius: 12px; padding: 20px; box-shadow: 0 6px 24px rgba(0,0,0,0.06); max-width: 520px; margin: 0 auto; }
|
||||
h1 { font-size: 22px; margin: 0 0 12px; }
|
||||
p { margin: 0 0 12px; color: #4a5160; }
|
||||
label { display: block; margin: 12px 0 6px; font-weight: 600; }
|
||||
input, select, button { width: 100%; padding: 10px 12px; border-radius: 8px; border: 1px solid #cfd2dc; box-sizing: border-box; font-size: 14px; }
|
||||
button { background: #6c63ff; color: #fff; border: none; cursor: pointer; margin-top: 14px; font-weight: 700; }
|
||||
button.secondary { background: #e8e9ef; color: #1f2430; border: 1px solid #cfd2dc; }
|
||||
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
||||
.muted { font-size: 12px; color: #6c758a; }
|
||||
.pill { display: inline-block; padding: 4px 10px; border-radius: 999px; background: #eef1ff; color: #3c45a0; font-size: 12px; margin-left: 6px; }
|
||||
#status { margin-top: 10px; font-size: 13px; min-height: 18px; }
|
||||
</style>
|
||||
<script src="files/dfido2-lib.js"></script>
|
||||
<script>
|
||||
const PROD_URL = 'https://fido2.amipro.me';
|
||||
const DEV_DEFAULT = localStorage.getItem('dfido2_dev_url') || '';
|
||||
|
||||
let redirectUri = '';
|
||||
|
||||
function setServer(url) {
|
||||
if (!url) return;
|
||||
setFidoServerURL(url);
|
||||
document.getElementById('currentServer').textContent = url;
|
||||
if (url !== PROD_URL) localStorage.setItem('dfido2_dev_url', url);
|
||||
}
|
||||
|
||||
function init() {
|
||||
const params = new URL(window.location.href).searchParams;
|
||||
redirectUri = params.get('redirect_uri') || `${window.location.origin}/app-callback`;
|
||||
|
||||
const devInput = document.getElementById('devUrl');
|
||||
devInput.value = DEV_DEFAULT;
|
||||
|
||||
const rpInput = document.getElementById('rpId');
|
||||
rpInput.value = location.hostname;
|
||||
|
||||
setServer(PROD_URL);
|
||||
}
|
||||
|
||||
function useProd() {
|
||||
setServer(PROD_URL);
|
||||
}
|
||||
|
||||
function useDev() {
|
||||
const v = document.getElementById('devUrl').value.trim();
|
||||
if (!v) {
|
||||
setStatus('Enter a dev/ngrok URL (https://...) first.');
|
||||
return;
|
||||
}
|
||||
setServer(v);
|
||||
setStatus('Dev server set.');
|
||||
}
|
||||
|
||||
function setStatus(msg) {
|
||||
document.getElementById('status').textContent = msg || '';
|
||||
}
|
||||
|
||||
async function doRegister() {
|
||||
setStatus('Registering...');
|
||||
const uid = document.getElementById('uid').value.trim();
|
||||
const display = document.getElementById('display').value.trim() || uid;
|
||||
const rpId = document.getElementById('rpId').value.trim() || location.hostname;
|
||||
if (!uid) { setStatus('User ID required'); return; }
|
||||
const result = await registerFido2(uid, display, rpId);
|
||||
await handleResult(result, rpId);
|
||||
}
|
||||
|
||||
async function doLogin() {
|
||||
setStatus('Signing in...');
|
||||
const uid = document.getElementById('uid').value.trim();
|
||||
const rpId = document.getElementById('rpId').value.trim() || location.hostname;
|
||||
if (!uid) { setStatus('User ID required'); return; }
|
||||
const result = await authenticateFido2(uid, rpId);
|
||||
await handleResult(result, rpId);
|
||||
}
|
||||
|
||||
async function handleResult(result, rpId) {
|
||||
if (result.status !== 'ok') {
|
||||
errProcessFido2(result);
|
||||
setStatus(result.errorMessage || 'Failed');
|
||||
return;
|
||||
}
|
||||
// No server handoff: send session + username directly to redirect_uri for the app to consume.
|
||||
const params = new URLSearchParams({
|
||||
session: result.session,
|
||||
username: result.username,
|
||||
rpId: rpId || ''
|
||||
});
|
||||
setStatus('Success. Returning to app...');
|
||||
window.location.href = `${redirectUri}?${params.toString()}`;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<div class="card">
|
||||
<h1>amiPro Passkey SSO <span class="pill">Beta</span></h1>
|
||||
<p>Use passkeys to sign in. Choose production or your ngrok dev host.</p>
|
||||
|
||||
<div class="row">
|
||||
<button class="secondary" onclick="useProd()">Use production</button>
|
||||
<button class="secondary" onclick="useDev()">Use dev/ngrok</button>
|
||||
</div>
|
||||
<label for="devUrl">Dev / ngrok URL</label>
|
||||
<input id="devUrl" placeholder="https://amipro-dev.ngrok-free.app" />
|
||||
|
||||
<p class="muted">Current server: <span id="currentServer">(not set)</span></p>
|
||||
|
||||
<label for="uid">User ID</label>
|
||||
<input id="uid" placeholder="user@example.com" />
|
||||
|
||||
<label for="display">Display name (optional)</label>
|
||||
<input id="display" placeholder="Name shown to user" />
|
||||
|
||||
<label for="rpId">rpId</label>
|
||||
<input id="rpId" placeholder="fido2.amipro.me or your ngrok host" value="" />
|
||||
|
||||
<button onclick="doLogin()">Passwordless login</button>
|
||||
<button onclick="doRegister()">Register new passkey</button>
|
||||
|
||||
<div id="status" class="muted"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user