Input

Result

awaiting input
-
score / 4
-
-
Online (throttled)
-
100 guesses/hr - typical login form
Online (unthrottled)
-
10 guesses/sec - no rate limiting
Offline (slow hash)
-
bcrypt/scrypt - 10k guesses/sec
Offline (fast hash)
-
MD5/SHA-1 - 10B guesses/sec

Drop-in integration snippets.

Ready-to-use HTML and JavaScript logic for common authentication forms. Try typing in the forms below to see the logic in action, then grab the code to use in your own projects.

Live demo API usage: - / -

<form id="reg-form">
  <label for="reg-email">Email Address</label>
  <input type="email" id="reg-email" name="email" autocomplete="email" required>
  
  <div style="display: flex; justify-content: space-between;">
    <label for="reg-pwd">Password</label>
    <span id="reg-str-text" aria-live="polite"></span>
  </div>
  
  <!-- Input Wrap for toggle visibility -->
  <div class="input-wrap">
    <input type="password" id="reg-pwd" name="password" autocomplete="new-password" required>
    <button type="button" class="toggle-vis">show</button>
  </div>
  
  <div class="strength-track">
    <div id="reg-str-bar" class="strength-fill"></div>
  </div>
  
  <div id="reg-breach" class="breach-warn" style="display: none;" aria-live="assertive"></div>
  
  <button type="submit" id="reg-btn">Create Account</button>
</form>

/* Password Toggle Layout */
.input-wrap {
  position: relative;
  display: block;
}

.input-wrap input {
  width: 100%;
  box-sizing: border-box;
  padding-right: 3.5rem; /* Space for the show button */
}

.toggle-vis {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  color: #888;
  cursor: pointer;
}

.toggle-vis:hover {
  color: #333;
}

/* Strength Bar */
.strength-track {
  height: 4px;
  background-color: rgba(100, 100, 100, 0.2);
  border-radius: 2px;
  margin-bottom: 12px;
}

.strength-fill {
  height: 100%;
  width: 0%;
  background-color: transparent;
  border-radius: 2px;
  transition: width 0.3s ease, background-color 0.3s ease;
}

/* Breach Alert */
.breach-warn {
  color: #dc503c;
  background-color: rgba(220, 80, 60, 0.1);
  padding: 10px 12px;
  border-left: 3px solid #dc503c;
  margin-bottom: 12px;
  font-size: 0.85rem;
}

// Show/Hide Toggle Logic
document.querySelectorAll('.toggle-vis').forEach(btn => {
  btn.addEventListener('click', (e) => {
    const input = e.target.previousElementSibling;
    const isHidden = input.type === 'password';
    input.type = isHidden ? 'text' : 'password';
    e.target.textContent = isHidden ? 'hide' : 'show';
  });
});

// Password Evaluation Logic
const pwdInput = document.getElementById('reg-pwd');
const strText = document.getElementById('reg-str-text');
const strBar = document.getElementById('reg-str-bar');
const breachWarn = document.getElementById('reg-breach');

const colors = ['#dc503c', '#e0763a', '#e8a838', '#8bbf6e', '#4caf7d'];
let debounceTimer;

pwdInput.addEventListener('input', (e) => {
  clearTimeout(debounceTimer);
  const password = e.target.value;
  
  if (!password) {
    strText.textContent = ''; strBar.style.width = '0%'; breachWarn.style.display = 'none';
    pwdInput.style.borderColor = ''; pwdInput.style.opacity = '1';
    return;
  }

  // Set UI to loading state
  strText.textContent = 'Checking...';
  strText.style.color = '#888';
  pwdInput.style.opacity = '0.7';

  // Wait 500ms after user stops typing before calling API
  debounceTimer = setTimeout(async () => {
    try {
      const res = await fetch('https://bastion.eande171.workers.dev/v1/evaluate', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          // SECURITY WARNING: Route this via your backend proxy to hide your API key
          'Authorization': 'Bearer YOUR_API_KEY'
        },
        body: JSON.stringify({ password })
      });
      
      const data = await res.json();
      
      // Ensure the user hasn't cleared the input while waiting for the response
      if (pwdInput.value !== password) return; 

      pwdInput.style.opacity = '1';
      
      // Update Strength UI
      strText.textContent = data.strength;
      strText.style.color = colors[data.score];
      strBar.style.width = `${(data.score / 4) * 100}%`;
      strBar.style.backgroundColor = colors[data.score];
      pwdInput.style.borderColor = colors[data.score];
      
      // Update Breach UI
      if (data.breached) {
        breachWarn.style.display = 'block';
        breachWarn.innerHTML = `⚠ Password found in ${data.breach_count} data breaches.`;
      } else {
        breachWarn.style.display = 'none';
      }
    } catch (err) {
      pwdInput.style.opacity = '1';
      console.error("Evaluation failed", err);
    }
  }, 500);
});
Forgot?
Live demo API usage: - / -
<form id="login-form">
  <label for="login-email">Email Address</label>
  <input type="email" id="login-email" name="email" autocomplete="email" required>

  <div style="display: flex; justify-content: space-between;">
    <label for="login-pwd">Password</label>
    <a href="#" style="font-size: 0.8rem;">Forgot?</a>
  </div>

  <!-- Input Wrap for toggle visibility -->
  <div class="input-wrap">
    <input type="password" id="login-pwd" name="password" autocomplete="current-password" required>
    <button type="button" class="toggle-vis">show</button>
  </div>

  <div id="login-alert" class="breach-warn" style="display: none;" aria-live="assertive"></div>

  <button type="submit" id="login-btn">Sign In</button>
</form>

/* Password Toggle Layout */
.input-wrap {
  position: relative;
  display: block;
}

.input-wrap input {
  width: 100%;
  box-sizing: border-box;
  padding-right: 3.5rem; /* Space for the show button */
}

.toggle-vis {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  color: #888;
  cursor: pointer;
}

.toggle-vis:hover {
  color: #333;
}

/* Breach Alert */
.breach-warn {
  color: #dc503c;
  background-color: rgba(220, 80, 60, 0.1);
  padding: 10px 12px;
  border-left: 3px solid #dc503c;
  margin-bottom: 12px;
  font-size: 0.85rem;
}

// Show/Hide Toggle Logic
document.querySelectorAll('.toggle-vis').forEach(btn => {
  btn.addEventListener('click', (e) => {
    const input = e.target.previousElementSibling;
    const isHidden = input.type === 'password';
    input.type = isHidden ? 'text' : 'password';
    e.target.textContent = isHidden ? 'hide' : 'show';
  });
});

// Login Check Logic
const loginForm = document.getElementById('login-form');
const pwdInput = document.getElementById('login-pwd');
const alertBox = document.getElementById('login-alert');
const submitBtn = document.getElementById('login-btn');

loginForm.addEventListener('submit', async (e) => {
  e.preventDefault();
  const password = pwdInput.value;
  if (!password) return;
  
  submitBtn.disabled = true;
  submitBtn.textContent = 'Checking...';
  pwdInput.style.opacity = '0.7';
  alertBox.style.display = 'none';

  try {
    const res = await fetch('https://bastion.eande171.workers.dev/v1/evaluate', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        // SECURITY WARNING: Route this via your backend proxy to hide your API key
        'Authorization': 'Bearer YOUR_API_KEY'
      },
      body: JSON.stringify({ password })
    });
    
    const data = await res.json();
    
    // Intercept login if password is compromised
    if (data.breached) {
      alertBox.style.display = 'block';
      alertBox.textContent = `⚠ Action Required: This password was compromised in a data breach. You must reset it before proceeding.`;
    } else {
      // Password is safe, proceed with standard auth
      alertBox.style.display = 'none';
      console.log("Safe, submitting to backend...");
      // loginForm.submit();
    }
  } catch (err) {
    console.error("Evaluation failed", err);
  } finally {
    pwdInput.style.opacity = '1';
    submitBtn.disabled = false;
    submitBtn.textContent = 'Sign In';
  }
});
Live demo API usage: - / -
<form id="change-password-form">
  <label for="cp-current">Current Password</label>
  <div class="input-wrap">
    <input type="password" id="cp-current" name="current-password" autocomplete="current-password" required>
    <button type="button" class="toggle-vis">show</button>
  </div>

  <div style="display: flex; justify-content: space-between;">
    <label for="cp-new">New Password</label>
    <span id="cp-str-text" aria-live="polite"></span>
  </div>
  <div class="input-wrap">
    <input type="password" id="cp-new" name="new-password" autocomplete="new-password" required>
    <button type="button" class="toggle-vis">show</button>
  </div>

  <div class="strength-track">
    <div id="cp-str-bar" class="strength-fill"></div>
  </div>

  <div id="cp-breach" class="breach-warn" style="display: none;" aria-live="assertive"></div>

  <label for="cp-confirm">Confirm New Password</label>
  <div class="input-wrap">
    <input type="password" id="cp-confirm" name="confirm-password" autocomplete="new-password" required>
    <button type="button" class="toggle-vis">show</button>
  </div>
  <div id="cp-match" style="display: none; color: red;" aria-live="polite">Passwords do not match</div>

  <button type="submit" id="cp-btn">Update Password</button>
</form>

/* Password Toggle Layout */
.input-wrap {
  position: relative;
  display: block;
}

.input-wrap input {
  width: 100%;
  box-sizing: border-box;
  padding-right: 3.5rem; /* Space for the show button */
}

.toggle-vis {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  color: #888;
  cursor: pointer;
}

.toggle-vis:hover {
  color: #333;
}

/* Strength Bar */
.strength-track {
  height: 4px;
  background-color: rgba(100, 100, 100, 0.2);
  border-radius: 2px;
  margin-bottom: 12px;
}

.strength-fill {
  height: 100%;
  width: 0%;
  background-color: transparent;
  border-radius: 2px;
  transition: width 0.3s ease, background-color 0.3s ease;
}

/* Breach Alert */
.breach-warn {
  color: #dc503c;
  background-color: rgba(220, 80, 60, 0.1);
  padding: 10px 12px;
  border-left: 3px solid #dc503c;
  margin-bottom: 12px;
  font-size: 0.85rem;
}

// Show/Hide Toggle Logic
document.querySelectorAll('.toggle-vis').forEach(btn => {
  btn.addEventListener('click', (e) => {
    const input = e.target.previousElementSibling;
    const isHidden = input.type === 'password';
    input.type = isHidden ? 'text' : 'password';
    e.target.textContent = isHidden ? 'hide' : 'show';
  });
});

// Update Password Check Logic
const newPwd = document.getElementById('cp-new');
const confPwd = document.getElementById('cp-confirm');
const matchErr = document.getElementById('cp-match');
const strText = document.getElementById('cp-str-text');
const strBar = document.getElementById('cp-str-bar');
const breachWarn = document.getElementById('cp-breach');

const colors = ['#dc503c', '#e0763a', '#e8a838', '#8bbf6e', '#4caf7d'];
let debounceTimer;

// Match checker helper
const checkMatch = () => {
  if (confPwd.value && newPwd.value !== confPwd.value) {
    matchErr.style.display = 'block';
    confPwd.style.borderColor = '#dc503c';
  } else {
    matchErr.style.display = 'none';
    confPwd.style.borderColor = '';
  }
};
confPwd.addEventListener('input', checkMatch);

newPwd.addEventListener('input', (e) => {
  clearTimeout(debounceTimer);
  checkMatch();
  const password = e.target.value;
  
  if (!password) {
    strText.textContent = ''; strBar.style.width = '0%'; breachWarn.style.display = 'none';
    newPwd.style.borderColor = ''; newPwd.style.opacity = '1';
    return;
  }

  // Set UI to loading state
  strText.textContent = 'Checking...';
  strText.style.color = '#888';
  newPwd.style.opacity = '0.7';

  debounceTimer = setTimeout(async () => {
    try {
      const res = await fetch('https://bastion.eande171.workers.dev/v1/evaluate', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            // SECURITY WARNING: Route this via your backend proxy to hide your API key
            'Authorization': 'Bearer YOUR_API_KEY' 
        },
        body: JSON.stringify({ password })
      });
      const data = await res.json();
      
      // Ensure the user hasn't cleared the input while waiting for the response
      if (newPwd.value !== password) return; 

      newPwd.style.opacity = '1';
      
      strText.textContent = data.strength;
      strText.style.color = colors[data.score];
      strBar.style.width = `${(data.score / 4) * 100}%`;
      strBar.style.backgroundColor = colors[data.score];
      newPwd.style.borderColor = colors[data.score];
      
      if (data.breached) {
        breachWarn.style.display = 'block';
        breachWarn.innerHTML = `⚠ Cannot use breached password.`;
      } else {
        breachWarn.style.display = 'none';
      }
    } catch (err) { 
      newPwd.style.opacity = '1';
    }
  }, 500);
});

More than trying it out?

Register for a free native key to get direct API access. No billing required. The free tier gives you 100 requests per day.

Your email is hashed immediately on registration and is used only if you need to regenerate your key. It is never stored in plain text.

Demo IP rate-limited, no key needed
Free ← you're here 100 req/day, usage controls
RapidAPI Free and Paid tiers, available now
API Key
-
Regeneration Token
-
Store both values securely. This regeneration token cannot be recovered after this page is closed.