Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
NIST CSF 2.0
MITRE ATLAS
Overview
Deploy FIDO2/WebAuthn passwordless authentication using security keys and platform authenticators. Covers WebAuthn API integration, FIDO2 server configuration, passkey enrollment, biometric authentication, and migration from password-based systems aligned with NIST SP 800-63B AAL3.
When to Use
- When deploying or configuring implementing passwordless authentication with fido2 capabilities in your environment
- When establishing security controls aligned to compliance requirements
- When building or improving security architecture for this domain
- When conducting security assessments that require this implementation
Prerequisites
- Familiarity with identity access management concepts and tools
- Access to a test or lab environment for safe execution
- Python 3.8+ with required dependencies installed
- Appropriate authorization for any testing activities
Objectives
- Implement comprehensive implementing passwordless authentication with fido2 capability
- Establish automated discovery and monitoring processes
- Integrate with enterprise IAM and security tools
- Generate compliance-ready documentation and reports
- Align with NIST 800-53 access control requirements
Security Controls
| Control | NIST 800-53 | Description |
|---|---|---|
| Account Management | AC-2 | Lifecycle management |
| Access Enforcement | AC-3 | Policy-based access control |
| Least Privilege | AC-6 | Minimum necessary permissions |
| Audit Logging | AU-3 | Authentication and access events |
| Identification | IA-2 | User and service identification |
Verification
- Implementation tested in non-production environment
- Security policies configured and enforced
- Audit logging enabled and forwarding to SIEM
- Documentation and runbooks complete
- Compliance evidence generated
Source materials
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md3.0 KB
API Reference: Implementing Passwordless Authentication with FIDO2
WebAuthn Registration Flow
// 1. Server generates challenge
const options = await navigator.credentials.create({
publicKey: {
challenge: new Uint8Array(32),
rp: { name: "Example Corp", id: "example.com" },
user: { id: userId, name: "user@example.com", displayName: "User" },
pubKeyCredParams: [
{ type: "public-key", alg: -7 }, // ES256
{ type: "public-key", alg: -257 }, // RS256
],
authenticatorSelection: {
authenticatorAttachment: "platform", // or "cross-platform"
residentKey: "required", // for passkeys
userVerification: "required",
},
attestation: "direct",
}
});WebAuthn Authentication Flow
const assertion = await navigator.credentials.get({
publicKey: {
challenge: serverChallenge,
rpId: "example.com",
allowCredentials: [], // empty for discoverable credentials (passkeys)
userVerification: "required",
}
});python-fido2 Server Library
from fido2.server import Fido2Server
from fido2.webauthn import PublicKeyCredentialRpEntity
rp = PublicKeyCredentialRpEntity(id="example.com", name="Example")
server = Fido2Server(rp)
# Registration
registration_data, state = server.register_begin(user, credentials)
auth_data = server.register_complete(state, response)
# Authentication
request_data, state = server.authenticate_begin(credentials)
server.authenticate_complete(state, credentials, credential_id, client_data, auth_data, signature)FIDO2 Authenticator Types
| Type | Example | Attachment | Passkey Support |
|---|---|---|---|
| Platform | Windows Hello, Touch ID | platform | Yes |
| Roaming | YubiKey, Titan Key | cross-platform | Yes (FIDO2) |
| Software | 1Password, iCloud Keychain | platform | Yes |
COSE Algorithm Identifiers
| COSE ID | Algorithm | Use |
|---|---|---|
| -7 | ES256 (P-256) | Preferred for FIDO2 |
| -257 | RS256 | Legacy compatibility |
| -8 | EdDSA (Ed25519) | Strong, compact |
| -35 | ES384 (P-384) | Higher security |
NIST SP 800-63B AAL Levels
| Level | Requirements | FIDO2 Mapping |
|---|---|---|
| AAL1 | Single factor | Not applicable |
| AAL2 | Two factors | FIDO2 + PIN/biometric |
| AAL3 | Hardware crypto + verifier impersonation resistance | FIDO2 hardware key |
Azure AD FIDO2 Configuration
# Enable FIDO2 in Azure AD
Set-MgBetaPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
-AuthenticationMethodConfigurationId "fido2" `
-State "enabled" `
-AdditionalProperties @{
isSelfServiceRegistrationAllowed = $true
isAttestationEnforced = $true
}References
- WebAuthn Spec: https://www.w3.org/TR/webauthn-3/
- FIDO Alliance: https://fidoalliance.org/specifications/
- NIST SP 800-63B: https://pages.nist.gov/800-63-3/sp800-63b.html
- python-fido2: https://github.com/Yubico/python-fido2
standards.md0.9 KB
Standards - FIDO2 Passwordless Authentication
FIDO Standards
- FIDO2 Specification: https://fidoalliance.org/specifications/
- WebAuthn Level 2: W3C Web Authentication API
- CTAP2: Client to Authenticator Protocol 2.0
NIST Standards
- NIST SP 800-63B: AAL3 - Hardware-based phishing-resistant authenticator
- NIST SP 800-53 Rev 5: IA-2(6), IA-2(8) Replay-resistant authentication
- NIST SP 800-157: PIV Derived Credentials
CISA Guidance
- Phishing-Resistant MFA: Required for federal agencies under EO 14028
- OMB M-22-09: Federal zero trust strategy requiring phishing-resistant MFA
Vendor Resources
- Yubico FIDO2: https://www.yubico.com/authentication-standards/fido2/
- Microsoft Passkeys: https://www.microsoft.com/en-us/security/business/security-101/what-is-fido2
- Google Passkeys: Android and Chrome WebAuthn support
workflows.md1.5 KB
FIDO2 Passwordless Authentication Workflows
Workflow 1: Security Key Enrollment
- User receives FIDO2 security key (YubiKey, Titan Key)
- User navigates to enrollment portal
- System generates WebAuthn registration challenge
- Browser prompts user to insert/tap security key
- User verifies with PIN or biometric on key
- Key generates unique public/private key pair
- Public key registered with relying party
- User tests authentication with enrolled key
Workflow 2: Passkey Authentication Flow
- User visits login page, enters username
- Server sends WebAuthn authentication challenge
- Browser prompts for authenticator (key, biometric, passkey)
- User verifies identity (touch key, scan fingerprint, enter PIN)
- Authenticator signs challenge with private key
- Server validates signature with stored public key
- User authenticated, session created
Workflow 3: Migration from Passwords to Passwordless
- Phase 1: Deploy FIDO2 to pilot group (IT, security teams)
- Phase 2: Enable coexistence (password + FIDO2)
- Phase 3: Expand FIDO2 enrollment to all users
- Phase 4: Set FIDO2-only policy per group
- Phase 5: Disable password authentication for migrated groups
- Phase 6: Monitor for fallback authentication attempts
Workflow 4: Lost/Stolen Key Recovery
- User reports lost security key
- Admin disables lost key in identity provider
- User authenticates via backup method (recovery codes, backup key)
- User enrolls replacement security key
- Old key permanently revoked
- Security team reviews for unauthorized usage of lost key
Scripts 1
agent.py3.6 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""FIDO2 Passwordless Auth Agent - audits FIDO2 deployment readiness and credential status."""
import json
import argparse
import logging
import subprocess
from datetime import datetime
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
def graph_api(token, endpoint):
cmd = ["curl", "-s", "-H", f"Authorization: Bearer {token}",
f"https://graph.microsoft.com/v1.0{endpoint}"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
return json.loads(result.stdout) if result.stdout else {}
def get_fido2_policy(token):
return graph_api(token, "/policies/authenticationMethodsPolicy/authenticationMethodConfigurations/fido2")
def get_registrations(token):
return graph_api(token, "/reports/authenticationMethods/userRegistrationDetails")
def audit_fido2_policy(policy):
findings = []
if policy.get("state") != "enabled":
findings.append({"issue": f"FIDO2 policy state: {policy.get('state', 'unknown')}", "severity": "high"})
if not policy.get("keyRestrictions", {}).get("aaGuids"):
findings.append({"issue": "No AAGUID restrictions set", "severity": "medium"})
if not policy.get("isAttestationEnforced"):
findings.append({"issue": "Attestation not enforced", "severity": "medium"})
return findings
def analyze_adoption(registrations):
users = registrations.get("value", [])
total = len(users)
fido2 = sum(1 for u in users if "fido2" in str(u.get("methodsRegistered", [])).lower())
passwordless = sum(1 for u in users if u.get("isPasswordlessCapable", False))
return {
"total_users": total, "fido2_registered": fido2, "passwordless_capable": passwordless,
"fido2_adoption_rate": round(fido2 / max(total, 1) * 100, 1),
}
def check_rp_config(rp_url):
cmd = ["curl", "-s", f"{rp_url}/.well-known/webauthn"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
findings = []
try:
config = json.loads(result.stdout)
except json.JSONDecodeError:
config = {}
findings.append({"issue": "WebAuthn well-known not configured", "severity": "high"})
return {"config": config, "findings": findings}
def generate_report(policy, policy_findings, adoption, rp):
return {
"timestamp": datetime.utcnow().isoformat(),
"fido2_policy_state": policy.get("state", "unknown"),
"policy_findings": policy_findings, "adoption_metrics": adoption,
"rp_config": rp,
"total_findings": len(policy_findings) + len(rp.get("findings", [])),
}
def main():
parser = argparse.ArgumentParser(description="FIDO2 Passwordless Authentication Audit Agent")
parser.add_argument("--token", required=True, help="Graph API bearer token")
parser.add_argument("--rp-url", help="WebAuthn relying party URL")
parser.add_argument("--output", default="fido2_audit_report.json")
args = parser.parse_args()
policy = get_fido2_policy(args.token)
policy_findings = audit_fido2_policy(policy)
registrations = get_registrations(args.token)
adoption = analyze_adoption(registrations)
rp = check_rp_config(args.rp_url) if args.rp_url else {"config": {}, "findings": []}
report = generate_report(policy, policy_findings, adoption, rp)
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
logger.info("FIDO2: adoption %.1f%%, %d findings", adoption["fido2_adoption_rate"], report["total_findings"])
print(json.dumps(report, indent=2, default=str))
if __name__ == "__main__":
main()
Keep exploring