odoo/odoo · error · InvalidAuthenticationResponse
id and raw_id were not equivalent
Error message
id and raw_id were not equivalent
What it means
WebAuthn authentication verification rejects a credential whose 'id' string is not the base64url encoding of its 'raw_id' bytes. The spec requires both to represent the same credential ID; a mismatch means the JSON was hand-built or mangled in transit.
Source
Thrown at addons/auth_passkey/_vendor/webauthn/authentication/verify_authentication_response.py:85
- `credential_public_key`: The public key for the credential's ID as provided in a
preceding authenticator registration ceremony.
- `credential_current_sign_count`: The current known number of times the authenticator was
used.
- (optional) `require_user_verification`: Whether or not to require that the authenticator
verified the user.
Returns:
Information about the authenticator
Raises:
`helpers.exceptions.InvalidAuthenticationResponse` if the response cannot be verified
"""
if isinstance(credential, str) or isinstance(credential, dict):
credential = parse_authentication_credential_json(credential)
# FIDO-specific check
if bytes_to_base64url(credential.raw_id) != credential.id:
raise InvalidAuthenticationResponse("id and raw_id were not equivalent")
# FIDO-specific check
if credential.type != PublicKeyCredentialType.PUBLIC_KEY:
raise InvalidAuthenticationResponse(
f'Unexpected credential type "{credential.type}", expected "public-key"'
)
response = credential.response
client_data_bytes = byteslike_to_bytes(response.client_data_json)
authenticator_data_bytes = byteslike_to_bytes(response.authenticator_data)
signature_bytes = byteslike_to_bytes(response.signature)
client_data = parse_client_data_json(client_data_bytes)
if client_data.type != ClientDataType.WEBAUTHN_GET:
raise InvalidAuthenticationResponse(
f'Unexpected client data type "{client_data.type}", expected "{ClientDataType.WEBAUTHN_GET}"'View on GitHub (pinned to 1e661df964)
Solutions
- On the client, send PublicKeyCredentialJSON via credentials.toJSON() (native) or base64url-encode rawId so id === base64url(rawId)
- If building the dict server-side, derive id from raw_id: credential['id'] = base64url_to_bytes-style encoding of raw_id
- Log both values and confirm which side (client serialization vs server storage) re-encoded the ID
Example fix
// before: manual serialization
const body = { id: btoa(String.fromCharCode(...new Uint8Array(cred.rawId))), rawId: Array.from(new Uint8Array(cred.rawId)), ... };
// after: native toJSON
const body = cred.toJSON(); // id and rawId are consistent base64url Defensive patterns
Strategy: validation
Validate before calling
import base64
def credential_ids_consistent(cred: dict) -> bool:
try:
raw = base64.urlsafe_b64decode(cred['rawId'] + '==')
return base64.urlsafe_b64encode(raw).rstrip(b'=').decode() == cred['id']
except Exception:
return False Type guard
def is_wellformed_assertion_json(cred) -> bool:
return (
isinstance(cred, dict)
and isinstance(cred.get('id'), str)
and isinstance(cred.get('rawId'), str)
and isinstance(cred.get('response'), dict)
and all(isinstance(cred['response'].get(k), str)
for k in ('clientDataJSON', 'authenticatorData', 'signature'))
) Try / catch
from auth_passkey._vendor.webauthn.helpers.exceptions import InvalidAuthenticationResponse
try:
result = verify_authentication_response(...)
except InvalidAuthenticationResponse as e:
logger.warning('assertion rejected: %s', e)
return HTTPResponse(400, 'Passkey verification failed') # never leak internals to client Prevention
- Always serialize with the browser-native cred.toJSON(); do not hand-encode rawId
- Add a payload schema check (keys + base64url decodability) at the API boundary before verification
- Keep one shared encode/decode utility for base64url on both client and server
When it happens
Trigger: Calling verify_authentication_response() with a credential dict/JSON where 'id' was re-encoded (e.g. base64 instead of base64url, padding added/stripped) or where raw_id bytes were decoded with the wrong charset. Happens when a frontend passes navigator.credentials.get() output through a JSON layer that re-encodes ArrayBuffers.
Common situations: Custom JS serializing the PublicKeyCredential manually and encoding rawId with btoa (base64 with +/ and padding) instead of base64url; a middleware or ORM that base64-decodes then re-encodes fields; passing a dict built from database-stored fields with inconsistent encodings.
Related errors
- Unexpected credential type "{credential.type}", expected "pu
- Unexpected client data type "{client_data.type}", expected "
- User verification is required but user was not verified duri
- Authenticator did not provide attested credential data
- Authenticator did not provide a credential ID
AI-assisted analysis of odoo/odoo@1e661df964 (2026-08-15).
Data as JSON: /api/errors/c058f655f7990376.
Report an issue: GitHub.