diff --git a/package.json b/package.json
index 844448df2..155aa963f 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"@web5/api": "0.8.4",
"@web5/credentials": "0.4.1",
"@web5/dids": "0.2.3",
+ "@web5/identity-agent": "0.2.5",
"font-awesome": "4.7.0",
"googleapis": "128.0.0",
"node-fetch": "3.3.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3b78c69bf..59771b875 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -26,6 +26,9 @@ importers:
'@web5/dids':
specifier: 0.2.3
version: 0.2.3
+ '@web5/identity-agent':
+ specifier: 0.2.5
+ version: 0.2.5
font-awesome:
specifier: 4.7.0
version: 4.7.0
@@ -4514,6 +4517,7 @@ packages:
dependencies:
is-glob: 4.0.3
micromatch: 4.0.5
+ napi-wasm: 1.1.0
dev: true
bundledDependencies:
- napi-wasm
@@ -6416,6 +6420,19 @@ packages:
- supports-color
dev: false
+ /@web5/identity-agent@0.2.5:
+ resolution: {integrity: sha512-TuTT8EYUICP0F64nYfQeXPKSR8dvxGeRDO40XreuSOYGKSxa2jtMxH5LAhakT42GWWAtvB1yfVdTWjfLq6Y6pQ==}
+ engines: {node: '>=18.0.0'}
+ dependencies:
+ '@web5/agent': 0.2.5
+ '@web5/common': 0.2.2
+ '@web5/crypto': 0.2.2
+ '@web5/dids': 0.2.3
+ transitivePeerDependencies:
+ - encoding
+ - supports-color
+ dev: false
+
/@web5/user-agent@0.2.5:
resolution: {integrity: sha512-qv5M698C5HSvq30xUgLWtcsbZppjfOH5qZthpTRx4ItL5UWA/eQ9DsQiQeb4vet3uIUy3NHRDIQezclOdwYErw==}
engines: {node: '>=18.0.0'}
@@ -13932,6 +13949,10 @@ packages:
resolution: {integrity: sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g==}
dev: false
+ /napi-wasm@1.1.0:
+ resolution: {integrity: sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg==}
+ dev: true
+
/natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true
diff --git a/site/__tests__/web5/build/decentralized-web-nodes/use-identity-agents.test.js b/site/__tests__/web5/build/decentralized-web-nodes/use-identity-agents.test.js
new file mode 100644
index 000000000..ce994a859
--- /dev/null
+++ b/site/__tests__/web5/build/decentralized-web-nodes/use-identity-agents.test.js
@@ -0,0 +1,24 @@
+import { test, expect, describe } from 'vitest';
+import {
+ getDwnEndpoints,
+} from '../../../../code-snippets/web5/build/decentralized-web-nodes/use-identity-agents';
+
+let agent;
+
+describe('create identity agent', () => {
+ // TO DO: add more tests for each code snippets after the team determines how to conditionally run tests for Web5.connect() vs. the Identity Agent
+ test('createDidOptions returns an object with cryptographic keys and service endpoints', async () => {
+ const didOptions = await getDwnEndpoints();
+
+ expect(didOptions).toHaveProperty('keySet.verificationMethodKeys');
+ expect(Array.isArray(didOptions.keySet.verificationMethodKeys)).toBe(true);
+ expect(didOptions).toHaveProperty('services');
+ expect(Array.isArray(didOptions.services)).toBe(true);
+ didOptions.services.forEach(service => {
+ expect(service).toHaveProperty('id');
+ expect(service).toHaveProperty('serviceEndpoint');
+ expect(service).toHaveProperty('type');
+ expect(service.type).toBe('DecentralizedWebNode');
+ });
+ });
+});
diff --git a/site/code-snippets/web5/build/decentralized-web-nodes/use-identity-agents.js b/site/code-snippets/web5/build/decentralized-web-nodes/use-identity-agents.js
new file mode 100644
index 000000000..f5b60849c
--- /dev/null
+++ b/site/code-snippets/web5/build/decentralized-web-nodes/use-identity-agents.js
@@ -0,0 +1,57 @@
+import { IdentityAgent } from '@web5/identity-agent';
+import { getTechPreviewDwnEndpoints } from '@web5/api';
+import { DidIonMethod } from '@web5/dids';
+
+
+export async function createIdentityAgent() {
+ const agent = await IdentityAgent.create();
+ return agent;
+}
+
+export async function authenticateIdentityAgent(agent) {
+ await agent.start({ passphrase: 'default-passphrase' });
+ return agent.agentDid;
+}
+
+export async function getDwnEndpoints() {
+// selects DWN endpoints that are provided by default during the Web5 tech preview period
+const serviceEndpointNodes = await getTechPreviewDwnEndpoints();
+
+// generates key pairs used for authorization and encryption when interfacing with DWNs
+const didOptions = await DidIonMethod.generateDwnOptions({ serviceEndpointNodes });
+return didOptions;
+}
+
+export async function createSocialMediaAndCareerIdentity() {
+ const socialMediaIdentity = await agent.identityManager.create({
+ name: 'SocialMedia',
+ didMethod: 'ion',
+ didOptions,
+ kms: 'local'
+ });
+
+ const careerIdentity = await agent.identityManager.create({
+ name: 'Career',
+ didMethod: 'ion',
+ didOptions,
+ kms: 'local'
+ });
+
+ return { socialMediaIdentity, careerIdentity };
+}
+
+export async function connectIdentityToWeb5() {
+ const { web5 } = await Web5.connect({
+ connectedDid: socialMediaIdentity.did,
+ agent,
+ });
+ return web5;
+}
+
+export async function connectToWeb5() {
+ const { web5 } = await Web5.connect({
+ connectedDid: socialIdentity.did,
+ agent,
+ });
+ return web5;
+}
\ No newline at end of file
diff --git a/site/docs/web5/build/decentralized-web-nodes/using-identity-agents.mdx b/site/docs/web5/build/decentralized-web-nodes/using-identity-agents.mdx
new file mode 100644
index 000000000..45529307e
--- /dev/null
+++ b/site/docs/web5/build/decentralized-web-nodes/using-identity-agents.mdx
@@ -0,0 +1,94 @@
+---
+sidebar_position: 9
+---
+
+import CodeSnippet from '@site/src/components/CodeSnippet';
+
+# Using Identity Agents
+
+Identity Agents are a specialized type of [agent](https://developer.tbd.website/docs/web5/learn/agents/) that act as personal identity managers. Similar to how a password manager securely stores login credentials for different web apps, Identity Agents manage your [DIDs](https://developer.tbd.website/docs/web5/learn/decentralized-identifiers).
+
+By default, the `Web5.connect()` function generates a **new** identity; however, Identity Agents allow you to connect to a Web5 app with an **existing** identity. This is useful for maintaining a cohesive online presence.
+
+This guide will walk you through creating an Identity Agent as a standalone application to manage multiple user identities and connect to a **separate** Web5 application.
+
+
+
+Prerequisites
+
+**Install the following packages**
+
+```bash
+npm i @web5/dids @web5/identity-agent @web5/api
+```
+
+**Import the following modules**
+
+```js
+import { DidIonMethod } from '@web5/dids';
+import { IdentityAgent } from '@web5/identity-agent';
+import { Web5, getTechPreviewDwnEndpoints } from '@web5/api';
+```
+
+
+
+## Initialize the Agent
+To create an Identity Agent, start by creating an instance of the `IdentityAgent`.
+
+
+
+## Prompt Users to Authenticate
+In your Identity Agent app, include the code snippet below to prompt users to authenticate with a one-time passphrase for security purposes.
+
+
+
+## Connect DIDs to DWNs
+To add [DWNs](https://developer.tbd.website/docs/web5/learn/decentralized-web-nodes/) as service endpoints to the DIDs that will be managed by the Identity Agent, you can add the endpoints as `didOptions`.
+
+Below is an example using TBD-hosted DWN endpoints:
+
+
+
+
+
+Expected Output of didOptions
+
+```js
+{
+ keySet: { verificationMethodKeys: [ [Object], [Object] ] },
+ services: [
+ {
+ id: '#dwn',
+ serviceEndpoint: [Object],
+ type: 'DecentralizedWebNode'
+ }
+ ]
+}
+```
+
+
+
+## Create Identities
+Now that `didOptions` contains cryptographic key pairs and service endpoints, you can create as many identities as necessary.
+
+Each identity, linked to a unique DID, represents and compartmentalizes different aspects of a user. For example, a user can have an identity for social media interactions and another for professional engagements.
+
+
+
+:::note
+* The `name` field serves as a friendly name for reference.
+* The `kms` field stands for [Key Management Service](/docs/web5/build/decentralized-identifiers/key-management) and can securely store and manage the cryptographic keys associated with a DID. If you don't specify a particular key management service, such as AWS Key Management Service, Web5 will default to an in-memory key manager.
+:::
+
+## Use your Identity in a Web5 Application
+Once your Identity Agent is set up to manage multiple identities, you can use it to help you login to a Web5 application. Here's the typical workflow:
+
+1. The Web5 application may display a QR code or a deep link for login purposes.
+2. Use the Identity Agent to scan the QR code or click the deep link to establish a connection between your Identity Agent and the Web5 application.
+3. The Identity Agent then prompts you to select the identity you prefer to use for authentication.
+
+## Connect to Web5
+Finally, the Web5 application can use the DID linked to your identity, so that you can interact within the Web5 application as your chosen identity.
+
+
+
diff --git a/site/src/util/code-snippets-map.json b/site/src/util/code-snippets-map.json
index 041c07ac6..5aa26ac00 100644
--- a/site/src/util/code-snippets-map.json
+++ b/site/src/util/code-snippets-map.json
@@ -46,6 +46,12 @@
"sendProtocolToRemoteDWNs": "const { protocol } = await web5.dwn.protocols.configure({\n message: {\n definition: protocolDefinition\n }\n});\n\n//immediately send protocol to user's remote DWNs\nconst {status} = await protocol.send(userDid);",
"sendRecordToDWNOfRecipient": "const { record } = await web5.dwn.records.create({\n data: \"this record will be created but not saved to DWN\",\n store: false, //remove this line if you want to keep a copy of the record in the sender's DWN\n message: {\n dataFormat: 'text/plain'\n },\n});\n\n//send record to recipient's DWN\nconst {status} = await record.send(recipientDid);",
"updateDwnRecord": "// Get the record\nconst { record } = await web5.dwn.records.read({\n message: {\n filter: {\n recordId: createdRecord.id\n }\n }\n});\n\n// Update the record\n// highlight-next-line\nconst {status} = await record.update({ data: \"Hello, I'm updated!\" });",
+ "createIdentityAgent": "const agent = await IdentityAgent.create();",
+ "authenticateIdentityAgent": "await agent.start({ passphrase: 'default-passphrase' });",
+ "getDwnEndpoints": "// selects DWN endpoints that are provided by default during the Web5 tech preview period\nconst serviceEndpointNodes = await getTechPreviewDwnEndpoints();\n\n// generates key pairs used for authorization and encryption when interfacing with DWNs\nconst didOptions = await DidIonMethod.generateDwnOptions({ serviceEndpointNodes });",
+ "createSocialMediaAndCareerIdentity": "const socialMediaIdentity = await agent.identityManager.create({\n name: 'SocialMedia',\n didMethod: 'ion',\n didOptions,\n kms: 'local'\n });\n\n const careerIdentity = await agent.identityManager.create({\n name: 'Career',\n didMethod: 'ion',\n didOptions,\n kms: 'local'\n });",
+ "connectIdentityToWeb5": "const { web5 } = await Web5.connect({\n connectedDid: socialMediaIdentity.did,\n agent,\n });",
+ "connectToWeb5": "const { web5 } = await Web5.connect({\n connectedDid: socialIdentity.did,\n agent,\n });",
"createTextRecord": "const { record } = await web5.dwn.records.create({\n data: 'Hello, Web5!',\n message: {\n dataFormat: 'text/plain',\n },\n });",
"createJsonRecord": "// Create a JSON record\nconst { record } = await web5.dwn.records.create({\n data: {\n content: \"Hello Web5\",\n description: \"Keep Building!\"\n },\n message: {\n dataFormat: 'application/json'\n }\n});",
"uploadImage": "// Create a blob record\n async function upload(event) {\n const blob = new Blob(event.currentTarget.files, { type: \"image/png\" });\n const { record } = await web5.dwn.records.create({\n data: blob,\n message: {\n dataFormat: \"image/png\"\n }\n });\n \n }",