diff --git a/.changeset/lemon-bees-yawn.md b/.changeset/lemon-bees-yawn.md new file mode 100644 index 000000000..cf7a444db --- /dev/null +++ b/.changeset/lemon-bees-yawn.md @@ -0,0 +1,5 @@ +--- +"@web5/agent": patch +--- + +Added parameter for app display name for dynamic rendering in the wallet during web5 connect flow diff --git a/.changeset/smooth-weeks-serve.md b/.changeset/smooth-weeks-serve.md new file mode 100644 index 000000000..68eb4483c --- /dev/null +++ b/.changeset/smooth-weeks-serve.md @@ -0,0 +1,5 @@ +--- +"@web5/api": patch +--- + +Added parameter for app display name for dynamic rendering in the wallet during web5 connect flow diff --git a/packages/agent/src/connect.ts b/packages/agent/src/connect.ts index 68aff74e9..9208d3f39 100644 --- a/packages/agent/src/connect.ts +++ b/packages/agent/src/connect.ts @@ -17,6 +17,7 @@ import { DwnInterfaceName, DwnMethodName } from '@tbd54566975/dwn-sdk-js'; * a did from a provider. */ async function initClient({ + displayName, connectServerUrl, walletUri, permissionRequests, @@ -44,10 +45,12 @@ async function initClient({ const request = await Oidc.createAuthRequest({ client_id : clientDid.uri, scope : 'openid did:jwk', + redirect_uri : callbackEndpoint, + // custom properties: // code_challenge : codeChallengeBase64Url, // code_challenge_method : 'S256', permissionRequests : permissionRequests, - redirect_uri : callbackEndpoint, + displayName, }); // Sign the Request Object using the Client DID's signing key. @@ -133,7 +136,10 @@ async function initClient({ * a did from a provider. */ export type WalletConnectOptions = { - /** The URL of the intermediary server which relays messages between the client and provider */ + /** The user friendly name of the client/app to be displayed when prompting end-user with permission requests. */ + displayName: string; + + /** The URL of the intermediary server which relays messages between the client and provider. */ connectServerUrl: string; /** diff --git a/packages/agent/src/oidc.ts b/packages/agent/src/oidc.ts index e56e9eb1f..dc40917c4 100644 --- a/packages/agent/src/oidc.ts +++ b/packages/agent/src/oidc.ts @@ -128,6 +128,9 @@ export type SIOPv2AuthRequest = { * The contents of this are inserted into a JWT inside of the {@link PushedAuthRequest}. */ export type Web5ConnectAuthRequest = { + /** The user friendly name of the client/app to be displayed when prompting end-user with permission requests. */ + displayName: string; + /** PermissionGrants that are to be sent to the provider */ permissionRequests: ConnectPermissionRequest[]; } & SIOPv2AuthRequest; @@ -242,7 +245,7 @@ async function generateCodeChallenge() { async function createAuthRequest( options: RequireOnly< Web5ConnectAuthRequest, - 'client_id' | 'scope' | 'redirect_uri' | 'permissionRequests' + 'client_id' | 'scope' | 'redirect_uri' | 'permissionRequests' | 'displayName' > ) { // Generate a random state value to associate the authorization request with the response. @@ -667,7 +670,6 @@ async function createPermissionGrants( }); const messages = await Promise.all(messagePromises); - return messages; } @@ -693,7 +695,6 @@ async function prepareProtocol( `Could not fetch protocol: ${queryMessage.reply.status.detail}` ); } else if (queryMessage.reply.entries === undefined || queryMessage.reply.entries.length === 0) { - // send the protocol definition to the remote DWN first, if it passes we can process it locally const { reply: sendReply, message: configureMessage } = await agent.sendDwnRequest({ author : selectedDid, @@ -716,7 +717,6 @@ async function prepareProtocol( }); } else { - // the protocol already exists, let's make sure it exists on the remote DWN as the requesting app will need it const configureMessage = queryMessage.reply.entries![0]; const { reply: sendReply } = await agent.sendDwnRequest({ diff --git a/packages/agent/tests/connect.spec.ts b/packages/agent/tests/connect.spec.ts index f6a1b87cb..9f34a8e10 100644 --- a/packages/agent/tests/connect.spec.ts +++ b/packages/agent/tests/connect.spec.ts @@ -224,6 +224,7 @@ describe('web5 connect', function () { }); const options = { + displayName : 'Sample App', client_id : clientEphemeralPortableDid.uri, scope : 'openid did:jwk', // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(), @@ -457,6 +458,7 @@ describe('web5 connect', function () { fetchStub.callThrough(); const results = await WalletConnect.initClient({ + displayName : 'Sample App', walletUri : 'http://localhost:3000/', connectServerUrl : 'http://localhost:3000/connect', permissionRequests : [ @@ -505,6 +507,7 @@ describe('web5 connect', function () { }); const options = { + displayName : 'Sample App', client_id : clientEphemeralPortableDid.uri, scope : 'openid did:jwk', // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(), @@ -560,6 +563,7 @@ describe('web5 connect', function () { }); const options = { + displayName : 'Sample App', client_id : clientEphemeralPortableDid.uri, scope : 'openid did:jwk', // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(), @@ -632,6 +636,7 @@ describe('web5 connect', function () { }); const options = { + displayName : 'Sample App', client_id : clientEphemeralPortableDid.uri, scope : 'openid did:jwk', // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(), @@ -679,6 +684,7 @@ describe('web5 connect', function () { }); const options = { + displayName : 'Sample App', client_id : clientEphemeralPortableDid.uri, scope : 'openid did:jwk', // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(), @@ -730,6 +736,7 @@ describe('web5 connect', function () { }); const options = { + displayName : 'Sample App', client_id : clientEphemeralPortableDid.uri, scope : 'openid did:jwk', // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(), @@ -781,6 +788,7 @@ describe('web5 connect', function () { mismatchedScopes[0].protocol = 'http://profile-protocol.xyz/other'; const options = { + displayName : 'Sample App', client_id : clientEphemeralPortableDid.uri, scope : 'openid did:jwk', // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(), diff --git a/packages/api/src/web5.ts b/packages/api/src/web5.ts index 6636026f5..bc5ee95bd 100644 --- a/packages/api/src/web5.ts +++ b/packages/api/src/web5.ts @@ -44,6 +44,7 @@ export type ConnectPermissionRequest = { * The protocol definition for the protocol being requested. */ protocolDefinition: DwnProtocolDefinition; + /** * The permissions being requested for the protocol. If none are provided, the default is to request all permissions. */ @@ -51,9 +52,14 @@ export type ConnectPermissionRequest = { } /** - * Options for connecting to a Web5 agent. This includes the ability to connect to an external wallet + * Options for connecting to a Web5 agent. This includes the ability to connect to an external wallet. + * + * NOTE: the returned `ConnectPermissionRequest` type is different to the `ConnectPermissionRequest` type in the `@web5/agent` package. */ export type ConnectOptions = Omit & { + /** The user friendly name of the client/app to be displayed when prompting end-user with permission requests. */ + displayName: string; + /** * The permissions that are being requested for the connected DID. * This is used to create the {@link ConnectPermissionRequest} for the wallet connect flow. diff --git a/packages/api/tests/web5.spec.ts b/packages/api/tests/web5.spec.ts index be0016963..4576989c4 100644 --- a/packages/api/tests/web5.spec.ts +++ b/packages/api/tests/web5.spec.ts @@ -455,6 +455,7 @@ describe('web5 api', () => { // connect to the app, the options don't matter because we're stubbing the initClient method const { web5, did, delegateDid } = await Web5.connect({ walletConnectOptions: { + displayName : 'Sample App', connectServerUrl : 'https://connect.example.com', walletUri : 'https://wallet.example.com', validatePin : async () => { return '1234'; }, @@ -675,6 +676,7 @@ describe('web5 api', () => { // connect to the app, the options don't matter because we're stubbing the initClient method await Web5.connect({ walletConnectOptions: { + displayName : 'Sample App', connectServerUrl : 'https://connect.example.com', walletUri : 'https://wallet.example.com', validatePin : async () => { return '1234'; }, @@ -735,6 +737,7 @@ describe('web5 api', () => { await Web5.connect({ sync : 'off', walletConnectOptions : { + displayName : 'Sample App', connectServerUrl : 'https://connect.example.com', walletUri : 'https://wallet.example.com', validatePin : async () => { return '1234'; }, @@ -779,6 +782,7 @@ describe('web5 api', () => { await Web5.connect({ sync : '1m', walletConnectOptions : { + displayName : 'Sample App', connectServerUrl : 'https://connect.example.com', walletUri : 'https://wallet.example.com', validatePin : async () => { return '1234'; }, @@ -822,6 +826,7 @@ describe('web5 api', () => { await Web5.connect({ walletConnectOptions: { + displayName : 'Sample App', connectServerUrl : 'https://connect.example.com', walletUri : 'https://wallet.example.com', validatePin : async () => { return '1234'; }, @@ -893,6 +898,7 @@ describe('web5 api', () => { await Web5.connect({ walletConnectOptions: { + displayName : 'Sample App', connectServerUrl : 'https://connect.example.com', walletUri : 'https://wallet.example.com', validatePin : async () => { return '1234'; }, diff --git a/packages/common/package.json b/packages/common/package.json index b7449eb47..8250fcb68 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -99,4 +99,4 @@ "rimraf": "5.0.7", "typescript": "5.5.3" } -} +} \ No newline at end of file