# Complete Authentication

To complete registration you'll need the same header values as used in [Initiate Authentication](/authentication/passkeys/authentication/authenticating-with-api/initiate-authentication.md)

### **Request Spec**

**HTTP Method**: POST

* [**Headers**](broken://pages/6Ip1xrKh5rkgidowSGll):
  * **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](/authentication/passkeys/authentication/authenticating-with-api/initiate-authentication.md), with the following functions.&#x20;

<pre class="language-typescript"><code class="lang-typescript">const cryptoObj = typeof window !== "undefined" ? window.crypto : crypto;

<strong>const decrypt = async (algo, key, data) => {
</strong>  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;
  }
};
</code></pre>

```typescript
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&#x20;

```typescript
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](/authentication/passkeys/authentication/authenticating-with-api/initiate-authentication.md)

Encrypt user for headers.

```json
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**

```http
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
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 128

{
  "jsonrpc": "2.0",
  "result": {
    "encrypted_jwt": "JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg=="
  },
  "id": 1
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.0xpass.io/authentication/passkeys/authentication/authenticating-with-api/complete-authentication.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
