Files
suaveplan/packages/identity/auth/webauthn/src/attestation/android-safetynet/android-safetynet.md
2026-05-27 23:47:53 +01:00

2.5 KiB

android-safetynet attestation verifier

(no submodules)

Purpose

Implements the W3C WebAuthn L3 §8.5 android-safetynet attestation format. Google's SafetyNet API issues a JWS attestation token whose payload binds the credential creation challenge (nonce = base64(sha256(authData || clientDataHash))) to a Google-signed claim that the device passed the SafetyNet integrity checks. The verifier delegates JWS structural parsing to @suaveplan/jws, confirms the nonce, and surfaces the x5c chain for the caller to bind to the Google attestation root.

Features

  • JWS parsing via @suaveplan/jws — no inline JWT/JOSE decoding.
  • nonce claim cross-bind via constant-time compare against base64(sha256(authData || clientDataHash)).
  • x5c chain extracted from the JWS header, decoded into raw DER bytes, and surfaced via trustPath.
  • Constant-time rpIdHash compare.
  • Reports attestationType: "basic".

Usage: Basic Example

import { verifyAndroidSafetynetAttestation } from "@suaveplan/webauthn/attestation/android-safetynet";

const result = await verifyAndroidSafetynetAttestation({
    attestationObject,
    clientDataHash,
    expectedRpIdHash,
});

Usage: Advanced Example

import {
    verifyAndroidSafetynetAttestation,
    type AttestationFormatRegistry,
} from "@suaveplan/webauthn";

function strictSafetynetRegistry(): AttestationFormatRegistry {
    return new Map([
        [
            "android-safetynet",
            async (input) => {
                const r = await verifyAndroidSafetynetAttestation(input);
                await assertGoogleAttestationRoot(r.trustPath);
                return r;
            },
        ],
    ]);
}

API Reference

  • verifyAndroidSafetynetAttestation: AttestationFormatVerifier — the format verifier.

Implementation Notes

  • Google has deprecated SafetyNet in favour of the Play Integrity API. The format is retained because Android devices still emit it during the transition window; new deployments SHOULD NOT depend on it for new policy.
  • Full JWS signature verification against the Google attestation root is intentionally NOT performed here — the root cert pool changes and the caller's metadata layer is the right place for it. The verifier surfaces the x5c chain via trustPath and confirms the nonce binding so the caller can do the full chain check with the correct trust anchor.
  • The nonce is base64 (not base64url) per the SafetyNet spec; the verifier explicitly encodes via btoa rather than via toBase64Url to match.