Complete Authentication
To complete registration you'll need the same header values as used in Initiate Authentication
Request Spec
HTTP Method: POST
Headers:
X-Scope-Id: A UUID string representing the application scope.
X-Encrypted-Key: A string containing the encrypted key for secure communication.
X-Encrypted-User: The user input encrypted using the encryption key
Body:
encrypted_assertion: A string containing the encrypted user assertion data.
To create an encrypted_assertion, first have to decrypt the encrypted_request_challenge
from the response in Initiate Authentication, with the following functions.
const cryptoObj = typeof window !== "undefined" ? window.crypto : crypto;
const decrypt = async (algo, key, data) => {
try {
const decryptedResult = await cryptoObj.subtle.decrypt(algo, key, data);
return decryptedResult;
} catch (error) {
console.error("Decryption error:", error);
throw error;
}
};
const aesDecrypt = async (
cipherText: string,
encryptionKey: BufferSource,
keyFormat: "raw" = "raw",
keyLength: number = 256
) => {
if (!encryptionKey) {
throw Error("Encryption key not initialized");
}
let cryptoKey: CryptoKey;
let decryptedData: ArrayBuffer;
try {
const combined = Uint8Array.from(atob(cipherText), (c) => c.charCodeAt(0));
const iv = combined.slice(0, 12);
const encryptedData = combined.slice(12);
cryptoKey = await importKey(keyFormat, encryptionKey, { name: "AES-GCM", length: keyLength }, [
"decrypt",
]);
decryptedData = await decrypt({ name: "AES-GCM", iv }, cryptoKey, encryptedData);
const decoder = new TextDecoder();
return decoder.decode(new Uint8Array(decryptedData));
} catch (error) {
console.error("AES-GCM Decryption error:", error);
throw error;
}
};
const request_challenge_str = await aesDecrypt(
initAuthResponse.result.encrypted_request_challenge,
aesKey
);
const request_challenge_json = JSON.parse(request_challenge_str)
// Once you have the credential creation options you can create a webauthn compatible
// assertion / signature e.g by using the broswer navigator.credentials.get
// function
const assertion = navigator.credentials.get(request_challenge_json);
You can then encrypt the attestation with your AES Key and send it as part of the request
const encrypted_attestation = await aesEncrypt(JSON.stringify(assertion), aesKey);
challenge_id: A UUID string representing the unique challenge for this authentication request, returned from Initiate Authentication
Encrypt user for headers.
const params = {
username: "test_user",
userDisplayName: "test_user"
}
// Same aesKey created with `generateAesKey`
const encrypted_user = await aesEncrypt(JSON.stringify(params), aesKey);
Response Spec
Body:
encrypted_jwt: A string containing the encrypted JSON Web Token (JWT) if authentication is successful.
Request Example
POST / HTTP/1.1
Host: https://tiramisu.0xpass.i
Content-Type: application/json
X-Scope-Id: 123e4567-e89b-12d3-a456-426614174000
X-Encrypted-Key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==
X-Encrypted-User: JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg==
{
"jsonrpc": "2.0",
"method": "completeAuthentication",
"params": {
"encrypted_assertion": "JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg==",
"challenge_id": "123e4567-e89b-12d3-a456-426614174000",
},
"id": 1
}
Response Example
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 128
{
"jsonrpc": "2.0",
"result": {
"encrypted_jwt": "JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg=="
},
"id": 1
}
Last updated