A credential ID identifies a WebAuthn public key credential. The server stores it with the associated public key, then uses it to locate the key when verifying a login response. section 15.3
A credential ID links registration to later authentication:
- Registration produces a public key credential whose essential details include the credential ID and raw public key. section 15.3
- The server associates the credential ID and public key with a user account. section 15.3 section 15.3.1
- During authentication, the server places the stored ID in allowCredentials so the authenticator can select the registered credential. section 15.3
- After receiving the response, the server reads its credential ID and retrieves the matching public key for verification. section 15.3
Registration and login
A registration request sends the generated credential details to the server, which stores the credential ID with the user. A later authentication response supplies that ID; the server uses it to retrieve the registered public key and verify the signature. Losing this association prevents the server from finding the key needed for authentication. section 15.3 section 15.3.1
Listing 15.6 The challenge endpoint
@PostMapping("/authenticate/challenge")
public Map<String, Object> getAuthenticationChallenge(
@RequestBody Map<String, String> request) {
String username = request.get("username");
String storedCredentialId = getUser(username); #1
byte[] challenge = new byte[32]; #2
new SecureRandom().nextBytes(challenge);
store.put(storedCredentialId, challenge); #3
Map<String, Object> allowCredential
= new HashMap<>(); #4
allowCredential.put("type", "public-key");
allowCredential.put("id", storedCredentialId);
var encChallange = Base64.getEncoder()
.encodeToString(challenge); #5
Map<String, Object> response = new HashMap<>(); #6
response.put("challenge", encChallange );
response.put("allowCredentials", List.of(allowCredential));
return response;
}
Shows how an authentication challenge endpoint retrieves a user’s stored credential ID and returns it as an allowed public-key credential. section 15.3
Listing 15.7 The authentication endpoint
@PostMapping("/authenticate")
public String authenticate(
@RequestBody AuthenticationResponse response) {
String credentialId = response.getId(); #1
byte[] signature = Base64.getDecoder()
.decode(response.getResponse().getSignature());
byte[] authenticatorData = Base64.getDecoder()
.decode(response.getResponse().getAuthenticatorData());
byte[] clientDataJSON = Base64.getDecoder()
.decode(response.getResponse().getClientDataJSON());
byte[] storedPublicKey #2
= getRegiteredPublicKey(credentialId); #2
byte[] originalChallenge #2
= store.get(credentialId); #2
var succss = verifySignatureAndAuthenticate( #3
storedPublicKey,
orginalChallenge,
signature);
if (success) return "Authentication successful";
else throw new UnsuccesfulAuthenticationException();
}
Shows how the authentication endpoint extracts the response credential ID and uses it to retrieve the registered public key. section 15.3
