# User Agent User Agents power Decentralized Web Apps (DWA) and execute in Chrome, Firefox, or Webkit browser runtime environments. End users interact directly with DWAs and use Web5 Connect to link an instantiated DWA with a remote Identity Agent (IDA). As each DWA is interacting with other applications and entities on the Internet using a DID and permissions delegated by the IDA, only one User Identity/DID will be active at any given time. ## App Launch 1. Check whether data vault is already initialized. 2. If not initialized, proceed to First Launch. 3. If already initialized, proceed to Every Launch process. ## First Launch Since this is the first time the Decentralized Web App has run on this computing device, proceed to initialize or restore the data vault and agent DID. ### Agent Initialization 1. Prompt end user to enter a passphrase. 2. An Ed25519 key pair is generated. 3. A did:key DID is created from the key pair generated in Step 2 (e.g., `did:key:ZM6abc123`). This DID will be subsequently referred to as the **Identity Agent DID**. 4. A non-secret static info value is combined with the Identity Agent DID public key as input to a Hash-based Key Derivation Function (HKDF) to derive a new 32-byte salt. 5. The salt value derived in Step 4 and the passphrase entered in Step 1 are used as input to the PBKDF2 algorithm to derive a secret key that will be referred to as the **Vault Unlock Key** (VUK). 6. The private key associated with the Identity Agent DID is encrypted using the derived VUK using XChaCha20-Poly1305 and the public key, salt, nonce, tag, and ciphertext are written to the AppDataVault store as a PBES2-HS512+XC20PKW JWE. 7. Cache the VUK in memory and set the data vault status to unlocked. 8. Set the Identity Agent's did:key identifier. 9. Import the Identity Agent's private key into the Identity Agent's KeyManager, which will be stored in a local KMS that persists only to memory. Proceed to the App Initialization process. ## Every Launch 1. Prompt end user to enter a `passphrase`. 2. The Identity Agent's salt value is read from the AppDataVault store. 3. The salt value retrieved in Step 2 and the passphrase entered in Step 1 are used as input to the PBKDF2 algorithm to derive the Vault Unlock Key (VUK). 4. Cache the VUK in memory and set the data vault status to unlocked. 5. Get the encrypted Identity Agent DID private key from the AppDataVault store (nonce, tag, and ciphertext) and decrypt it using the VUK. 6. Set the Identity Agent's did:key identifier. 7. Import the Identity Agent's private key into the Identity Agent's KeyManager, which will be stored in a local KMS that persists only to memory. Proceed to the App Initialization process. ## App Initialization 1. Query the embedded DWN for Identity records using the App DID's `did:key` as author and signed by the associated key set (default signing key). 2. (A) If one identity record is found and session timer hasn't expired (or set to never expire) then automatically restore that `did:ion` identity and return an intiatiated `Web5()` instance with Web5UserAgent and the `did:ion` identity as the `connectedDid`. (B) If multiple identity records are found that don't have an expired session timer, prompt the user to select which identity to use (or could default to most recently used). (C) If no identities are found give the user an option to either "Connect" or "Use local agent". ## Connect If user action bypasses connect to instantiate a local agent proceed to [Fallback to Local Agent]() process. Otherwise, proceed to [Connect to Agent]() process. ### Connect to Agent 1. DWA initiates a connection using `web5.connect()`. 2. (A) If localhost desktop Identity Agent is detected, then DWA posts a permissions request to the localhost desktop IDA's Connect Server and initiates a deep link to trigger desktop IDA, including the DWA's did:key, a random nonce, and the Connect Server URL of the localhost IDA that it sent the permissions request to. (B) If no localhost desktop IDA is detected, then DWA posts a permissions request to the Connect Server and Using either QR Code or deep link, DWA transmits did:key, a random nonce, and Connect Server URL to the IDA. 3. IDA fetches the DWA’s permissions request from the Connect Server using the provided URL. 4. End user selects an Identity (e.g., Social, Career, Family, etc.) for the DWA to use and authorizes the permissions request. 5. IDA posts the selected Identity’s DID (did:ion), a permissions grant, and a challenge PIN encrypted using the DWA’s did:key public key to the Connect Server. 6. DWA fetches the DID, permissions grant, and PIN from the Connect Server and decrypts the values using its private key. 7. End user validates the challenge PIN out of band by either: 8. Typing the PIN displayed in the DWA into the IDA interface. 9. Validating that the PIN values displayed in both the DWA and IDA match. If connect fails to connect or is denied by the remote agent then proceed to [Fallback to Local Agent]() process. If connect succeeds, the agent will now have a `did:ion` DID that was selected by the user in the IDA as well as a delegation signature. 10. A KeyManager `dwn` KMS entry in the App DID's `did:key` tenant is created with an alias of the "default signing key" of the `did:ion` delegated DID but with the keys of the App DID `did:key` key set. This is what enables the agent to sign on behalf of the `did:ion` delegated DID. 11. Store the delegation signature. Where does the delegation signature get stored? Perhaps in the App `did:key` DID's tenant so that when the agent starts up it can read this back in and use to sign records on behalf of the delegated `did:ion` straight away? This could even be in the same record as above Step 10 by adding a new property to the `managed-key` or `kms-key` structure that is for delegation signatures. That way, whenever a DwnManager calls `agent.keyManager.sign()` ith the `did:ion` default signing key reference, `sign()` finds the key & delegation signature and knows that it needs to append the additioanl signature material. Alternatively, it could be stored separately in such as away that DwnManager has to retrieve it and add it to the DWN record. 12. A Web5 instance is instantiated, passing in the existing Web5UserAgent and the provided `did:ion` DID as the `connectedDid`. 13. Local Web5UserAgent initiates sync to get at least the Identity & DID records for the `did:ion` tenant. These are needed to be able to know that a connection previous occurred when the agent is launched the next time. All `did:ion` tenant records are written with `did:ion` as the author, signed by App DID `did:key` keys, and with the delegation signature included. The `agentDid` always remains the App DID `did:key` value because this is how the agent is able to sign / interact with its own DWN stores and is able to get the `did:ion` identity keys out of its DWN-backed KMS. ### Fallback to Local Agent A local `did:key` DID was created during Agent initialization and stored in the Agent's app data vault. The `agentDid` remains the `did:key` DID. 1. Agent creates a new Identity: - new `did:ion` DID and key set are generated - DID key set is stored in the agent's `did:key` tenant and `dwn` KMS. - DID metadata is stored in the new `did:ion` Identity's tenant with author of the new `did:ion` DID and signed with the `did:ion` key set that's in the agent's KeyManager DWN-backed KMS store. - Identity metadata is stored in the new `did:ion` Identity's tenant with author of the new `did:ion` DID and signed with the `did:ion` key set that's in the agent's KeyManager DWN-backed KMS store. 2. A Web5 instance is instantiated, passing in the existing Web5UserAgent and the new `did:ion` DID as the `connectedDid`. All `did:ion` tenant records are written with `did:ion` as the author and signed by the `did:ion` keys. The `agentDid` always remains the App DID `did:key` value because this is how the agent is able to sign / interact with its own DWN stores and is able to get the `did:ion` identity keys out of its DWN-backed KMS. ## Migrate to Identity Agent In the case where a fallback Web5UserAgent was being used, it must be possible to migrate to an Identity Agent. Ideally, this process is painless for the end user. If migration is initiated by a user action, `Web5.connect()` is initiated with some property that flags migration as `true`. **Option A** During the connect() handshake, after PIN validation, the local fallback Web5UserAgent posts its `did:ion` keys to the Connect Server encrypted so that only the IDA can retrieve them. The remote IDA retrieves the keys from the Connect Server, writes them to its IDA `did:key` DWN-backed KMS, and initiates sync with that `did:ion` tenant's service endpoint to get all of the records. **Option B** A simple MVP could be to have an export format for the local fallback Web5UserAgent. The file would be encrypted using the `did:key` passphrase/key material. Add an import option to the IdentityAgent whereby it decrypts the export if given the correct DID and passphrase.