- {accesses?.length && !price && !costToUser && (
+ {(accesses?.length ?? 0 > 0) && !price && !costToUser && (
{thirdPartyName} is requesting grant for an unlimited amount
@@ -352,13 +352,19 @@ export default function ConsentScreen({ idpSecretParam }: ConsentScreenProps) {
outgoingPaymentAccess?.limits?.receiveAmount?.assetScale ??
null
)
+ if (outgoingPaymentAccess) {
+ returnUrlObject.searchParams.append(
+ 'amountType',
+ outgoingPaymentAccess.limits?.receiveAmount
+ ? AmountType.RECEIVE
+ : outgoingPaymentAccess.limits?.debitAmount
+ ? AmountType.DEBIT
+ : AmountType.UNLIMITED
+ )
+ }
returnUrlObject.searchParams.append(
- 'amountType',
- outgoingPaymentAccess?.limits?.receiveAmount
- ? AmountType.RECEIVE
- : outgoingPaymentAccess?.limits?.debitAmount
- ? AmountType.DEBIT
- : AmountType.UNLIMITED
+ 'subjectId',
+ response.payload.subject.sub_ids[0]?.id ?? null
)
setCtx({
...ctx,
diff --git a/localenv/mock-account-servicing-entity/app/routes/mock-idp.consent.tsx b/localenv/mock-account-servicing-entity/app/routes/mock-idp.consent.tsx
index 63e6f5e979..86670e2736 100644
--- a/localenv/mock-account-servicing-entity/app/routes/mock-idp.consent.tsx
+++ b/localenv/mock-account-servicing-entity/app/routes/mock-idp.consent.tsx
@@ -27,7 +27,8 @@ function AuthorizedView({
interactId,
nonce,
authServerDomain,
- amountType
+ amountType,
+ subjectId
}: {
thirdPartyName: string
currencyDisplayCode: string
@@ -36,21 +37,30 @@ function AuthorizedView({
nonce: string
authServerDomain: string
amountType: string
+ subjectId: string
}) {
- let message = `You gave ${thirdPartyName} permission to `
- switch (amountType) {
- case AmountType.RECEIVE:
- message += `receive ${currencyDisplayCode} ${amount.toFixed(2)} in your account.`
- break
- case AmountType.DEBIT:
- message += `send ${currencyDisplayCode} ${amount.toFixed(2)} out of your account.`
- break
- case AmountType.UNLIMITED:
- message += 'have unlimited access to your account.'
- break
- default:
- message = 'Type of authorization is missing'
+ let message = ''
+ if (amountType) {
+ message += `You gave ${thirdPartyName} permission to `
+ switch (amountType) {
+ case AmountType.RECEIVE:
+ message += `receive ${currencyDisplayCode} ${amount.toFixed(2)} in your account.`
+ break
+ case AmountType.DEBIT:
+ message += `send ${currencyDisplayCode} ${amount.toFixed(2)} out of your account.`
+ break
+ case AmountType.UNLIMITED:
+ message += 'have unlimited access to your account.'
+ break
+ default:
+ message = 'Type of authorization is missing'
+ }
+ }
+ if (subjectId) {
+ message += message.length > 0 ? ' Also, you ' : 'You '
+ message += `confirmed ${thirdPartyName} your ownership of ${subjectId}.`
}
+
return (
@@ -132,7 +142,8 @@ export default function Consent() {
amount:
Number(queryParams.get('amountValue')) /
Math.pow(10, Number(queryParams.get('amountScale'))),
- amountType: queryParams.get('amountType')
+ amountType: queryParams.get('amountType'),
+ subjectId: queryParams.get('subjectId')
})
useEffect(() => {
@@ -187,6 +198,7 @@ export default function Consent() {
nonce={ctx.nonce}
authServerDomain={authServerDomain}
amountType={ctx.amountType || ''}
+ subjectId={ctx.subjectId || ''}
/>
) : (
Date: Thu, 9 Oct 2025 12:41:20 -0700
Subject: [PATCH 5/5] fix: handle subject-only grants properly
---
.../Grant Request Outgoing Payment.bru | 8 ---
.../Continuation Request.bru | 33 +++++++++++
.../Get sender wallet address.bru | 58 +++++++++++++++++++
.../Grant Request for Subject Information.bru | 52 +++++++++++++++++
.../folder.bru | 4 ++
.../app/routes/mock-idp._index.tsx | 7 ++-
6 files changed, 152 insertions(+), 10 deletions(-)
create mode 100644 bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Continuation Request.bru
create mode 100644 bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Get sender wallet address.bru
create mode 100644 bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Grant Request for Subject Information.bru
create mode 100644 bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/folder.bru
diff --git a/bruno/collections/Rafiki/Examples/Open Payments/Grant Request Outgoing Payment.bru b/bruno/collections/Rafiki/Examples/Open Payments/Grant Request Outgoing Payment.bru
index ba48792c47..3c4b667956 100644
--- a/bruno/collections/Rafiki/Examples/Open Payments/Grant Request Outgoing Payment.bru
+++ b/bruno/collections/Rafiki/Examples/Open Payments/Grant Request Outgoing Payment.bru
@@ -26,14 +26,6 @@ body:json {
}
]
},
- "subject": {
- "sub_ids": [
- {
- "id": "{{senderWalletAddress}}",
- "format": "uri"
- }
- ]
- },
"client": "{{clientWalletAddress}}",
"interact": {
"start": [
diff --git a/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Continuation Request.bru b/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Continuation Request.bru
new file mode 100644
index 0000000000..9859237b18
--- /dev/null
+++ b/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Continuation Request.bru
@@ -0,0 +1,33 @@
+meta {
+ name: Continuation Request
+ type: http
+ seq: 8
+}
+
+post {
+ url: {{senderOpenPaymentsContinuationUri}}
+ body: json
+ auth: none
+}
+
+headers {
+ Authorization: GNAP {{continueToken}}
+}
+
+script:pre-request {
+ const scripts = require('./scripts');
+
+ await scripts.addSignatureHeaders();
+}
+
+script:post-response {
+ const scripts = require('./scripts');
+
+ scripts.storeTokenDetails();
+}
+
+tests {
+ test("Status code is 200", function() {
+ expect(res.getStatus()).to.equal(200);
+ });
+}
diff --git a/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Get sender wallet address.bru b/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Get sender wallet address.bru
new file mode 100644
index 0000000000..118456a8f7
--- /dev/null
+++ b/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Get sender wallet address.bru
@@ -0,0 +1,58 @@
+meta {
+ name: Get sender wallet address
+ type: http
+ seq: 1
+}
+
+get {
+ url: {{senderWalletAddress}}
+ body: none
+ auth: none
+}
+
+headers {
+ Accept: application/json
+}
+
+script:pre-request {
+ const scripts = require('./scripts');
+
+ scripts.addHostHeader("senderOpenPaymentsHost");
+}
+
+script:post-response {
+ const url = require('url')
+
+ if (res.getStatus() !== 200) {
+ return
+ }
+
+ const body = res.getBody()
+ bru.setEnvVar("senderAssetCode", body?.assetCode)
+ bru.setEnvVar("senderAssetScale", body?.assetScale)
+
+ const authUrl = url.parse(body?.authServer)
+ if (
+ authUrl.hostname.includes('cloud-nine-wallet') ||
+ authUrl.hostname.includes('happy-life-bank')
+ ){
+ const port = authUrl.hostname.includes('cloud-nine-wallet')? authUrl.port: Number(authUrl.port) + 1000
+ bru.setEnvVar("senderOpenPaymentsAuthHost", authUrl.protocol + '//localhost:' + port + authUrl.path);
+ } else {
+ bru.setEnvVar("senderOpenPaymentsAuthHost", body?.authServer);
+ }
+
+ const resourceUrl = url.parse(body?.resourceServer)
+ if (resourceUrl.hostname.includes('cloud-nine-wallet') || resourceUrl.hostname.includes('happy-life-bank')) {
+ const port = resourceUrl.hostname.includes('happy-life-bank') ? bru.getEnvVar('happyLifeOpenPaymentsPort') : bru.getEnvVar('cloudNineOpenPaymentsPort')
+ bru.setEnvVar("senderOpenPaymentsHost", 'http://localhost:' + port + resourceUrl.path);
+ } else {
+ bru.setEnvVar("senderOpenPaymentsHost", body?.resourceServer);
+ }
+}
+
+tests {
+ test("Status code is 200", function() {
+ expect(res.getStatus()).to.equal(200);
+ });
+}
diff --git a/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Grant Request for Subject Information.bru b/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Grant Request for Subject Information.bru
new file mode 100644
index 0000000000..a7bc2f19c2
--- /dev/null
+++ b/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/Grant Request for Subject Information.bru
@@ -0,0 +1,52 @@
+meta {
+ name: Grant Request for Subject Information
+ type: http
+ seq: 7
+}
+
+post {
+ url: {{senderOpenPaymentsAuthHost}}
+ body: json
+ auth: none
+}
+
+body:json {
+ {
+ "subject": {
+ "sub_ids": [
+ {
+ "id": "{{senderWalletAddress}}",
+ "format": "uri"
+ }
+ ]
+ },
+ "client": "{{clientWalletAddress}}",
+ "interact": {
+ "start": [
+ "redirect"
+ ]
+ }
+ }
+
+}
+
+script:pre-request {
+ const scripts = require('./scripts');
+
+ await scripts.addSignatureHeaders();
+}
+
+script:post-response {
+ const scripts = require('./scripts');
+
+ scripts.storeTokenDetails();
+
+ const body = res.getBody()
+ bru.setEnvVar("senderOpenPaymentsContinuationUri", body?.continue.uri)
+}
+
+tests {
+ test("Status code is 200", function() {
+ expect(res.getStatus()).to.equal(200);
+ });
+}
diff --git a/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/folder.bru b/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/folder.bru
new file mode 100644
index 0000000000..6520ef80ca
--- /dev/null
+++ b/bruno/collections/Rafiki/Examples/Vailidating Wallet Address Ownership with Open Payments/folder.bru
@@ -0,0 +1,4 @@
+meta {
+ name: Vailidating Wallet Address Ownership with Open Payments
+ seq: 6
+}
diff --git a/localenv/mock-account-servicing-entity/app/routes/mock-idp._index.tsx b/localenv/mock-account-servicing-entity/app/routes/mock-idp._index.tsx
index 9849ba2922..3a4fe62ace 100644
--- a/localenv/mock-account-servicing-entity/app/routes/mock-idp._index.tsx
+++ b/localenv/mock-account-servicing-entity/app/routes/mock-idp._index.tsx
@@ -109,11 +109,14 @@ function ConsentScreenBody({
- {(accesses?.length ?? 0 > 0) && !price && !costToUser && (
+ {accesses?.length &&
+ accesses.length > 0 &&
+ !price &&
+ !costToUser ? (
{thirdPartyName} is requesting grant for an unlimited amount
- )}
+ ) : undefined}