diff --git a/examples/wallet-connect.html b/examples/wallet-connect.html
index ccaa699e7..f6f2e0cf8 100644
--- a/examples/wallet-connect.html
+++ b/examples/wallet-connect.html
@@ -121,19 +121,34 @@
Success
$actions: [
{
who: "anyone",
- can: ["create", "update"],
+ can: ["read"],
},
],
},
},
};
+ const fooProtocol = {
+ protocol: "http://foo-protocol.xyz",
+ published: true,
+ types: {
+ foo: {
+ schema: "http://foo-protocol.xyz/schema/foo",
+ dataFormats: ["application/json"],
+ },
+ },
+ structure: {
+ foo: {},
+ },
+ };
+
try {
- const { delegateDid } = await Web5.connect({
+
+ const { delegateDid, web5 } = await Web5.connect({
walletConnectOptions: {
walletUri: "web5://connect",
connectServerUrl: "http://localhost:3000/connect",
- permissionRequests: [{ protocolDefinition: profileProtocol }],
+ permissionRequests: [{ protocolDefinition: profileProtocol }, { protocolDefinition: fooProtocol }],
onWalletUriReady: generateQRCode,
validatePin: async () => {
goToPinScreen();
@@ -144,7 +159,18 @@ Success
},
});
- goToEndScreen(delegateDid);
+ // attempt to write to the foo protocol
+ const { record, status } = await web5.dwn.records.create({
+ data: { fooData: 'Some Foo Data' },
+ message: {
+ protocol: fooProtocol.protocol,
+ protocolPath: 'foo',
+ schema: fooProtocol.types.foo.schema,
+ dataFormat: fooProtocol.types.foo.dataFormats[0],
+ }
+ });
+
+ goToEndScreen(delegateDid, record, status);
} catch (e) {
document.getElementById(
"errorMessage"
@@ -187,12 +213,12 @@ Success
document.getElementById("pinScreen").style.display = "block";
}
- function goToEndScreen(delegateDid) {
+ function goToEndScreen(delegateDid, record, status) {
document.getElementById(
"didInformation"
).innerText = `delegateDid\n:${JSON.stringify(
delegateDid
- )}`;
+ )}\n\n\nRecordsWrite Status:${JSON.stringify(status)}\nRecord:${JSON.stringify(record, null, 2)}`;
document.getElementById("pinScreen").style.display = "none";
document.getElementById("endScreen").style.display = "block";
diff --git a/packages/agent/src/connect.ts b/packages/agent/src/connect.ts
index fdaa35362..24baf15cc 100644
--- a/packages/agent/src/connect.ts
+++ b/packages/agent/src/connect.ts
@@ -1,6 +1,6 @@
import type { PushedAuthResponse } from './oidc.js';
-import type { DwnPermissionScope, DwnProtocolDefinition, Web5ConnectAuthResponse } from './index.js';
+import type { DwnPermissionScope, DwnProtocolDefinition, Web5Agent, Web5ConnectAuthResponse } from './index.js';
import {
Oidc,
diff --git a/packages/agent/src/oidc.ts b/packages/agent/src/oidc.ts
index a05873393..3443aabe5 100644
--- a/packages/agent/src/oidc.ts
+++ b/packages/agent/src/oidc.ts
@@ -12,13 +12,10 @@ import { concatenateUrl } from './utils.js';
import { xchacha20poly1305 } from '@noble/ciphers/chacha';
import type { ConnectPermissionRequest } from './connect.js';
import { DidDocument, DidJwk, PortableDid, type BearerDid } from '@web5/dids';
-import type {
- PermissionScope,
- RecordsWriteMessage,
-} from '@tbd54566975/dwn-sdk-js';
-import { DwnInterface, DwnProtocolDefinition } from './types/dwn.js';
+import { DwnDataEncodedRecordsWriteMessage, DwnInterface, DwnPermissionScope, DwnProtocolDefinition } from './types/dwn.js';
import { AgentPermissionsApi } from './permissions-api.js';
import type { Web5Agent } from './types/agent.js';
+import { isRecordPermissionScope } from './dwn-api.js';
/**
* Sent to an OIDC server to authorize a client. Allows clients
@@ -161,14 +158,10 @@ export type SIOPv2AuthResponse = {
/** An auth response that is compatible with both Web5 Connect and (hopefully, WIP) OIDC SIOPv2 */
export type Web5ConnectAuthResponse = {
- delegateGrants: DelegateGrant[];
+ delegateGrants: DwnDataEncodedRecordsWriteMessage[];
delegatePortableDid: PortableDid;
} & SIOPv2AuthResponse;
-export type DelegateGrant = (RecordsWriteMessage & {
- encodedData: string;
-})
-
/** Represents the different OIDC endpoint types.
* 1. `pushedAuthorizationRequest`: client sends {@link PushedAuthRequest} receives {@link PushedAuthResponse}
* 2. `authorize`: provider gets the {@link Web5ConnectAuthRequest} JWT that was stored by the PAR
@@ -615,22 +608,26 @@ async function createPermissionGrants(
selectedDid: string,
delegateBearerDid: BearerDid,
agent: Web5Agent,
- scopes: PermissionScope[],
+ scopes: DwnPermissionScope[],
) {
-
const permissionsApi = new AgentPermissionsApi({ agent });
// TODO: cleanup all grants if one fails by deleting them from the DWN: https://github.com/TBD54566975/web5-js/issues/849
const permissionGrants = await Promise.all(
- scopes.map((scope) =>
- permissionsApi.createGrant({
+ scopes.map((scope) => {
+
+ // check if the scope is a records permission scope, if so it is a delegated permission
+ const delegated = isRecordPermissionScope(scope);
+ return permissionsApi.createGrant({
+ delegated,
store : true,
grantedTo : delegateBearerDid.uri,
scope,
- dateExpires : '2040-06-25T16:09:16.693356Z',
+ dateExpires : '2040-06-25T16:09:16.693356Z', // TODO: make dateExpires optional
author : selectedDid,
- })
- )
+ });
+
+ })
);
const messagePromises = permissionGrants.map(async (grant) => {
@@ -638,7 +635,7 @@ async function createPermissionGrants(
const { encodedData, ...rawMessage } = grant.message;
const data = Convert.base64Url(encodedData).toUint8Array();
- const { reply } = await agent.sendDwnRequest({
+ const { reply } = await agent.sendDwnRequest({
author : selectedDid,
target : selectedDid,
messageType : DwnInterface.RecordsWrite,
@@ -662,14 +659,14 @@ async function createPermissionGrants(
}
/**
-* Installs the protocols required by the Client on the Provider
-* if they don't already exist.
-*/
-async function prepareProtocols(
+ * Installs the protocol required by the Client on the Provider if it doesn't already exist.
+ */
+async function prepareProtocol(
selectedDid: string,
agent: Web5Agent,
protocolDefinition: DwnProtocolDefinition
-) {
+): Promise {
+
const queryMessage = await agent.processDwnRequest({
author : selectedDid,
messageType : DwnInterface.ProtocolsQuery,
@@ -677,32 +674,48 @@ async function prepareProtocols(
messageParams : { filter: { protocol: protocolDefinition.protocol } },
});
- if (queryMessage.reply.status.code === 404) {
- const configureMessage = await agent.processDwnRequest({
+ if ( queryMessage.reply.status.code !== 200) {
+ // if the query failed, throw an error
+ throw new Error(
+ `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,
- messageType : DwnInterface.ProtocolsConfigure,
target : selectedDid,
+ messageType : DwnInterface.ProtocolsConfigure,
messageParams : { definition: protocolDefinition },
});
- if (configureMessage.reply.status.code !== 202) {
- throw new Error(`Could not install protocol: ${configureMessage.reply.status.detail}`);
+ // check if the message was sent successfully, if the remote returns 409 the message may have come through already via sync
+ if (sendReply.status.code !== 202 && sendReply.status.code !== 409) {
+ throw new Error(`Could not send protocol: ${sendReply.status.detail}`);
}
- // send the configure message to the remote DWN so that the APP can immediately use it without waiting for a sync cycle from the wallet
+ // process the protocol locally, we don't have to check if it exists as this is just a convenience over waiting for sync.
+ await agent.processDwnRequest({
+ author : selectedDid,
+ target : selectedDid,
+ messageType : DwnInterface.ProtocolsConfigure,
+ rawMessage : configureMessage
+ });
+
+ } 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({
author : selectedDid,
target : selectedDid,
messageType : DwnInterface.ProtocolsConfigure,
- rawMessage : configureMessage.message,
+ rawMessage : configureMessage,
});
- // check if the message was sent successfully, if the remote returns 409 the message may have come through already via sync
if (sendReply.status.code !== 202 && sendReply.status.code !== 409) {
throw new Error(`Could not send protocol: ${sendReply.status.detail}`);
}
- } else if (queryMessage.reply.status.code !== 200) {
- throw new Error(`Could not fetch protcol: ${queryMessage.reply.status.detail}`);
}
}
@@ -719,20 +732,34 @@ async function submitAuthResponse(
selectedDid: string,
authRequest: Web5ConnectAuthRequest,
randomPin: string,
- agent: Web5Agent,
+ agent: Web5Agent
) {
const delegateBearerDid = await DidJwk.create();
const delegatePortableDid = await delegateBearerDid.export();
- const delegateGrantPromises = authRequest.permissionRequests.map(async (permissionRequest) => {
- // TODO: validate to make sure the scopes and definition are assigned to the same protocol
- const { protocolDefinition, permissionScopes } = permissionRequest;
+ // TODO: roll back permissions and protocol configurations if an error occurs. Need a way to delete protocols to achieve this.
+ const delegateGrantPromises = authRequest.permissionRequests.map(
+ async (permissionRequest) => {
+ const { protocolDefinition, permissionScopes } = permissionRequest;
- await prepareProtocols(selectedDid, agent, protocolDefinition);
- const permissionGrants = await Oidc.createPermissionGrants(selectedDid, delegateBearerDid, agent, permissionScopes);
+ // We validate that all permission scopes match the protocol uri of the protocol definition they are provided with.
+ const grantsMatchProtocolUri = permissionScopes.every(scope => 'protocol' in scope && scope.protocol === protocolDefinition.protocol);
+ if (!grantsMatchProtocolUri) {
+ throw new Error('All permission scopes must match the protocol uri they are provided with.');
+ }
- return permissionGrants;
- });
+ await prepareProtocol(selectedDid, agent, protocolDefinition);
+
+ const permissionGrants = await Oidc.createPermissionGrants(
+ selectedDid,
+ delegateBearerDid,
+ agent,
+ permissionScopes
+ );
+
+ return permissionGrants;
+ }
+ );
const delegateGrants = (await Promise.all(delegateGrantPromises)).flat();
diff --git a/packages/agent/tests/connect.spec.ts b/packages/agent/tests/connect.spec.ts
index 441f80bdd..c56dc8720 100644
--- a/packages/agent/tests/connect.spec.ts
+++ b/packages/agent/tests/connect.spec.ts
@@ -11,7 +11,7 @@ import {
import { PlatformAgentTestHarness } from '../src/test-harness.js';
import { TestAgent } from './utils/test-agent.js';
import { testDwnUrl } from './utils/test-config.js';
-import { BearerIdentity, DwnProtocolDefinition, WalletConnect } from '../src/index.js';
+import { BearerIdentity, DwnInterface, DwnMessage, DwnProtocolDefinition, WalletConnect } from '../src/index.js';
import { RecordsPermissionScope } from '@tbd54566975/dwn-sdk-js';
import { DwnInterfaceName, DwnMethodName } from '@tbd54566975/dwn-sdk-js';
@@ -489,6 +489,323 @@ describe('web5 connect', function () {
});
});
+ describe('submitAuthResponse', () => {
+ it('should not attempt to configure the protocol if it already exists', async () => {
+ // scenario: the wallet gets a request for a protocol that it already has configured
+ // the wallet should not attempt to re-configure, but instead ensure that the protocol is
+ // sent to the remote DWN for the requesting client to be able to sync it down later
+
+ sinon.stub(Oidc, 'createPermissionGrants').resolves(permissionGrants as any);
+ sinon.stub(CryptoUtils, 'randomBytes').returns(encryptionNonce);
+ sinon.stub(DidJwk, 'create').resolves(delegateBearerDid);
+
+ const callbackUrl = Oidc.buildOidcUrl({
+ baseURL : 'http://localhost:3000',
+ endpoint : 'callback',
+ });
+
+ const options = {
+ client_id : clientEphemeralPortableDid.uri,
+ scope : 'openid did:jwk',
+ // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(),
+ // code_challenge_method : 'S256' as const,
+ permissionRequests : [{ protocolDefinition, permissionScopes }],
+ redirect_uri : callbackUrl,
+ };
+ authRequest = await Oidc.createAuthRequest(options);
+
+ // stub the processDwnRequest method to return a protocol entry
+ const protocolMessage = {} as DwnMessage[DwnInterface.ProtocolsConfigure];
+
+ // spy send request
+ const sendRequestSpy = sinon.stub(testHarness.agent, 'sendDwnRequest').resolves({
+ messageCid : '',
+ reply : { status: { code: 202, detail: 'OK' } }
+ });
+
+ const processDwnRequestStub = sinon
+ .stub(testHarness.agent, 'processDwnRequest')
+ .resolves({ messageCid: '', reply: { status: { code: 200, detail: 'OK' }, entries: [ protocolMessage ]} });
+
+ // call submitAuthResponse
+ await Oidc.submitAuthResponse(
+ providerIdentity.did.uri,
+ authRequest,
+ randomPin,
+ testHarness.agent
+ );
+
+ // expect the process request to only be called once for ProtocolsQuery
+ expect(processDwnRequestStub.callCount).to.equal(1);
+ expect(processDwnRequestStub.firstCall.args[0].messageType).to.equal(DwnInterface.ProtocolsQuery);
+
+ // send request should be called once as a ProtocolsConfigure
+ expect(sendRequestSpy.callCount).to.equal(1);
+ expect(sendRequestSpy.firstCall.args[0].messageType).to.equal(DwnInterface.ProtocolsConfigure);
+ });
+
+ it('should configure the protocol if it does not exist', async () => {
+ // scenario: the wallet gets a request for a protocol that it does not have configured
+ // the wallet should attempt to configure the protocol and then send the protocol to the remote DWN
+
+ // looks for a response of 404, empty entries array or missing entries array
+
+ sinon.stub(Oidc, 'createPermissionGrants').resolves(permissionGrants as any);
+ sinon.stub(CryptoUtils, 'randomBytes').returns(encryptionNonce);
+ sinon.stub(DidJwk, 'create').resolves(delegateBearerDid);
+
+ const callbackUrl = Oidc.buildOidcUrl({
+ baseURL : 'http://localhost:3000',
+ endpoint : 'callback',
+ });
+
+ const options = {
+ client_id : clientEphemeralPortableDid.uri,
+ scope : 'openid did:jwk',
+ // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(),
+ // code_challenge_method : 'S256' as const,
+ permissionRequests : [{ protocolDefinition, permissionScopes }],
+ redirect_uri : callbackUrl,
+ };
+ authRequest = await Oidc.createAuthRequest(options);
+
+ // spy send request
+ const sendRequestSpy = sinon.stub(testHarness.agent, 'sendDwnRequest').resolves({
+ messageCid : '',
+ reply : { status: { code: 202, detail: 'OK' } }
+ });
+
+ const processDwnRequestStub = sinon
+ .stub(testHarness.agent, 'processDwnRequest')
+ .resolves({ messageCid: '', reply: { status: { code: 200, detail: 'OK' }, entries: [ ] } });
+
+ // call submitAuthResponse
+ await Oidc.submitAuthResponse(
+ providerIdentity.did.uri,
+ authRequest,
+ randomPin,
+ testHarness.agent
+ );
+
+ // expect the process request to be called for query and configure
+ expect(processDwnRequestStub.callCount).to.equal(2);
+ expect(processDwnRequestStub.firstCall.args[0].messageType).to.equal(DwnInterface.ProtocolsQuery);
+ expect(processDwnRequestStub.secondCall.args[0].messageType).to.equal(DwnInterface.ProtocolsConfigure);
+
+ // send request should be called once as a ProtocolsConfigure
+ expect(sendRequestSpy.callCount).to.equal(1);
+ expect(sendRequestSpy.firstCall.args[0].messageType).to.equal(DwnInterface.ProtocolsConfigure);
+
+ // reset the spys
+ processDwnRequestStub.resetHistory();
+ sendRequestSpy.resetHistory();
+
+ // processDwnRequestStub should resolve a 200 with no entires
+ processDwnRequestStub.resolves({ messageCid: '', reply: { status: { code: 200, detail: 'OK' } } });
+
+ // call submitAuthResponse
+ await Oidc.submitAuthResponse(
+ providerIdentity.did.uri,
+ authRequest,
+ randomPin,
+ testHarness.agent
+ );
+
+ // expect the process request to be called for query and configure
+ expect(processDwnRequestStub.callCount).to.equal(2);
+ expect(processDwnRequestStub.firstCall.args[0].messageType).to.equal(DwnInterface.ProtocolsQuery);
+ expect(processDwnRequestStub.secondCall.args[0].messageType).to.equal(DwnInterface.ProtocolsConfigure);
+
+ // send request should be called once as a ProtocolsConfigure
+ expect(sendRequestSpy.callCount).to.equal(1);
+ expect(sendRequestSpy.firstCall.args[0].messageType).to.equal(DwnInterface.ProtocolsConfigure);
+ });
+
+ it('should fail if the send request fails for newly configured protocol', async () => {
+ sinon.stub(Oidc, 'createPermissionGrants').resolves(permissionGrants as any);
+ sinon.stub(CryptoUtils, 'randomBytes').returns(encryptionNonce);
+ sinon.stub(DidJwk, 'create').resolves(delegateBearerDid);
+
+ const callbackUrl = Oidc.buildOidcUrl({
+ baseURL : 'http://localhost:3000',
+ endpoint : 'callback',
+ });
+
+ const options = {
+ client_id : clientEphemeralPortableDid.uri,
+ scope : 'openid did:jwk',
+ // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(),
+ // code_challenge_method : 'S256' as const,
+ permissionRequests : [{ protocolDefinition, permissionScopes }],
+ redirect_uri : callbackUrl,
+ };
+ authRequest = await Oidc.createAuthRequest(options);
+
+ // spy send request
+ const sendRequestSpy = sinon.stub(testHarness.agent, 'sendDwnRequest').resolves({
+ reply : { status: { code: 500, detail: 'Internal Server Error' } },
+ messageCid : ''
+ });
+
+ // return without any entries
+ const processDwnRequestStub = sinon
+ .stub(testHarness.agent, 'processDwnRequest')
+ .resolves({ messageCid: '', reply: { status: { code: 200, detail: 'OK' } } });
+
+ try {
+ // call submitAuthResponse
+ await Oidc.submitAuthResponse(
+ providerIdentity.did.uri,
+ authRequest,
+ randomPin,
+ testHarness.agent
+ );
+
+ expect.fail('should have thrown an error');
+ } catch (error: any) {
+ expect(error.message).to.equal('Could not send protocol: Internal Server Error');
+ expect(sendRequestSpy.callCount).to.equal(1);
+ }
+ });
+
+ it('should fail if the send request fails for existing protocol', async () => {
+ sinon.stub(Oidc, 'createPermissionGrants').resolves(permissionGrants as any);
+ sinon.stub(CryptoUtils, 'randomBytes').returns(encryptionNonce);
+ sinon.stub(DidJwk, 'create').resolves(delegateBearerDid);
+
+ const callbackUrl = Oidc.buildOidcUrl({
+ baseURL : 'http://localhost:3000',
+ endpoint : 'callback',
+ });
+
+ const options = {
+ client_id : clientEphemeralPortableDid.uri,
+ scope : 'openid did:jwk',
+ // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(),
+ // code_challenge_method : 'S256' as const,
+ permissionRequests : [{ protocolDefinition, permissionScopes }],
+ redirect_uri : callbackUrl,
+ };
+ authRequest = await Oidc.createAuthRequest(options);
+
+ // stub the processDwnRequest method to return a protocol entry
+ const protocolMessage = {} as DwnMessage[DwnInterface.ProtocolsConfigure];
+
+ // spy send request
+ const sendRequestSpy = sinon.stub(testHarness.agent, 'sendDwnRequest').resolves({
+ reply : { status: { code: 500, detail: 'Internal Server Error' } },
+ messageCid : ''
+ });
+
+ // mock returning the protocol entry
+ const processDwnRequestStub = sinon
+ .stub(testHarness.agent, 'processDwnRequest')
+ .resolves({ messageCid: '', reply: { status: { code: 200, detail: 'OK' }, entries: [ protocolMessage ] } });
+
+ try {
+ // call submitAuthResponse
+ await Oidc.submitAuthResponse(
+ providerIdentity.did.uri,
+ authRequest,
+ randomPin,
+ testHarness.agent
+ );
+
+ expect.fail('should have thrown an error');
+ } catch (error: any) {
+ expect(error.message).to.equal('Could not send protocol: Internal Server Error');
+ expect(processDwnRequestStub.callCount).to.equal(1);
+ expect(sendRequestSpy.callCount).to.equal(1);
+ }
+ });
+
+ it('should throw if protocol could not be fetched at all', async () => {
+ sinon.stub(Oidc, 'createPermissionGrants').resolves(permissionGrants as any);
+ sinon.stub(CryptoUtils, 'randomBytes').returns(encryptionNonce);
+ sinon.stub(DidJwk, 'create').resolves(delegateBearerDid);
+
+ const callbackUrl = Oidc.buildOidcUrl({
+ baseURL : 'http://localhost:3000',
+ endpoint : 'callback',
+ });
+
+ const options = {
+ client_id : clientEphemeralPortableDid.uri,
+ scope : 'openid did:jwk',
+ // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(),
+ // code_challenge_method : 'S256' as const,
+ permissionRequests : [{ protocolDefinition, permissionScopes }],
+ redirect_uri : callbackUrl,
+ };
+ authRequest = await Oidc.createAuthRequest(options);
+
+ // spy send request
+ const sendRequestSpy = sinon.stub(testHarness.agent, 'sendDwnRequest').resolves({
+ reply : { status: { code: 500, detail: 'Internal Server Error' } },
+ messageCid : ''
+ });
+
+ // mock returning the protocol entry
+ const processDwnRequestStub = sinon
+ .stub(testHarness.agent, 'processDwnRequest')
+ .resolves({ messageCid: '', reply: { status: { code: 500, detail: 'Some Error'}, } });
+
+ try {
+ // call submitAuthResponse
+ await Oidc.submitAuthResponse(
+ providerIdentity.did.uri,
+ authRequest,
+ randomPin,
+ testHarness.agent
+ );
+
+ expect.fail('should have thrown an error');
+ } catch (error: any) {
+ expect(error.message).to.equal('Could not fetch protocol: Some Error');
+ expect(processDwnRequestStub.callCount).to.equal(1);
+ expect(sendRequestSpy.callCount).to.equal(0);
+ }
+ });
+
+ it('should throw if a grant that is included in the request does not match the protocol definition', async () => {
+ sinon.stub(Oidc, 'createPermissionGrants').resolves(permissionGrants as any);
+ sinon.stub(CryptoUtils, 'randomBytes').returns(encryptionNonce);
+ sinon.stub(DidJwk, 'create').resolves(delegateBearerDid);
+
+ const callbackUrl = Oidc.buildOidcUrl({
+ baseURL : 'http://localhost:3000',
+ endpoint : 'callback',
+ });
+
+ const mismatchedScopes = [...permissionScopes];
+ mismatchedScopes[0].protocol = 'http://profile-protocol.xyz/other';
+
+ const options = {
+ client_id : clientEphemeralPortableDid.uri,
+ scope : 'openid did:jwk',
+ // code_challenge : Convert.uint8Array(codeChallenge).toBase64Url(),
+ // code_challenge_method : 'S256' as const,
+ permissionRequests : [{ protocolDefinition, permissionScopes }],
+ redirect_uri : callbackUrl,
+ };
+ authRequest = await Oidc.createAuthRequest(options);
+
+ try {
+ // call submitAuthResponse
+ await Oidc.submitAuthResponse(
+ providerIdentity.did.uri,
+ authRequest,
+ randomPin,
+ testHarness.agent
+ );
+
+ expect.fail('should have thrown an error');
+ } catch (error: any) {
+ expect(error.message).to.equal('All permission scopes must match the protocol uri they are provided with.');
+ }
+ });
+ });
+
describe('createPermissionRequestForProtocol', () => {
it('should add sync permissions to all requests', async () => {
const protocol:DwnProtocolDefinition = {
diff --git a/packages/api/src/web5.ts b/packages/api/src/web5.ts
index 6aba6ecef..75468f6d6 100644
--- a/packages/api/src/web5.ts
+++ b/packages/api/src/web5.ts
@@ -6,7 +6,6 @@
import type {
BearerIdentity,
- DelegateGrant,
DwnDataEncodedRecordsWriteMessage,
DwnMessagesPermissionScope,
DwnProtocolDefinition,
@@ -242,7 +241,6 @@ export class Web5 {
walletConnectOptions,
}: Web5ConnectOptions = {}): Promise {
let delegateDid: string | undefined;
- let delegateGrants: DelegateGrant[];
if (agent === undefined) {
let registerSync = false;
// A custom Web5Agent implementation was not specified, so use default managed user agent.
@@ -292,11 +290,10 @@ export class Web5 {
'read', 'write', 'delete', 'query', 'subscribe'
]));
- const { delegatePortableDid, connectedDid, delegateGrants: returnedGrants } = await WalletConnect.initClient({
+ const { delegatePortableDid, connectedDid, delegateGrants } = await WalletConnect.initClient({
...connectOptions,
permissionRequests: walletPermissionRequests,
});
- delegateGrants = returnedGrants;
// Import the delegated DID as an Identity in the User Agent.
// Setting the connectedDID in the metadata applies a relationship between the signer identity and the one it is impersonating.