Skip to content

Commit 2d78b59

Browse files
authored
feat: new types for directed identity, improved grant (#24)
* feat: new types for directed identity, improved grant * chore: changeset
1 parent 72d1f73 commit 2d78b59

6 files changed

Lines changed: 69 additions & 11 deletions

File tree

.changeset/giant-dots-carry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@interledger/open-payments': minor
3+
---
4+
5+
New union client type to support directed identity. Exported grant type guards and added new, more explicit grant types.

packages/open-payments/src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ export {
1212
OutgoingPaymentGrantSpentAmounts,
1313
PendingGrant,
1414
Grant,
15+
GrantWithAccessToken,
16+
GrantWithSubject,
1517
isPendingGrant,
1618
isFinalizedGrant,
19+
isFinalizedGrantWithAccessToken,
20+
isFinalizedGrantWithSubject,
1721
JWK,
1822
JWKS,
1923
PaginationArgs,
@@ -22,7 +26,8 @@ export {
2226
AccessAction,
2327
AccessToken,
2428
AccessItem,
25-
Subject
29+
Subject,
30+
Client
2631
} from './types'
2732

2833
export {

packages/open-payments/src/openapi/generated/auth-server-types.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,15 +167,31 @@ export interface components {
167167
};
168168
/**
169169
* client
170-
* @description Wallet address of the client instance that is making this request.
170+
* @description Client identification for grant requests.
171171
*
172172
* When sending a non-continuation request to the AS, the client instance MUST identify itself by including the client field of the request and by signing the request.
173173
*
174+
* Can be either:
175+
* - A wallet address string (backwards compatible format)
176+
* - An object with either `jwk` (for directed identity) or `walletAddress` (mutually exclusive)
177+
*
178+
* When using a wallet address string or the `walletAddress` property:
174179
* A JSON Web Key Set document, including the public key that the client instance will use to protect this request and any continuation requests at the AS and any user-facing information about the client instance used in interactions, MUST be available at the wallet address + `/jwks.json` url.
175180
*
181+
* When using the `jwk` property (directed identity approach):
182+
* The client instance provides its public key directly in the request, eliminating the need for the AS to fetch it from a wallet address. This approach enhances privacy by not requiring the client to expose a persistent wallet address identifier. The `jwk` property can only be used for non-interactive grant requests (i.e.: incoming payments).
183+
*
176184
* If sending a grant initiation request that requires RO interaction, the wallet address MUST serve necessary client display information.
177185
*/
178-
client: string;
186+
client: string | {
187+
/**
188+
* Format: uri
189+
* @description Wallet address of the client instance that is making this request.
190+
*/
191+
walletAddress: string;
192+
} | {
193+
jwk: components["schemas"]["json-web-key"];
194+
};
179195
/**
180196
* continue
181197
* @description If the AS determines that the request can be continued with additional requests, it responds with the continue field.
@@ -307,6 +323,29 @@ export interface components {
307323
format: "uri";
308324
}[];
309325
};
326+
/**
327+
* Ed25519 Public Key
328+
* @description A JWK representation of an Ed25519 Public Key
329+
*/
330+
"json-web-key": {
331+
kid: string;
332+
/**
333+
* @description The cryptographic algorithm family used with the key. The only allowed value is `EdDSA`.
334+
* @enum {string}
335+
*/
336+
alg: "EdDSA";
337+
/** @enum {string} */
338+
use?: "sig";
339+
/** @enum {string} */
340+
kty: "OKP";
341+
/**
342+
* @description The cryptographic curve used with the key. This parameter identifies the elliptic curve (for EC keys) or the Edwards curve (for OKP keys). The only allowed value is `Ed25519`.
343+
* @enum {string}
344+
*/
345+
crv: "Ed25519";
346+
/** @description The base64 url-encoded public key. */
347+
x: string;
348+
};
310349
};
311350
responses: never;
312351
parameters: never;

packages/open-payments/src/openapi/generated/resource-server-types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -894,8 +894,8 @@ export interface operations {
894894
};
895895
content: {
896896
"application/json": {
897-
spentReceiveAmount?: components["schemas"]["amount"];
898-
spentDebitAmount?: components["schemas"]["amount"];
897+
spentReceiveAmount: components["schemas"]["amount"] | null;
898+
spentDebitAmount: components["schemas"]["amount"] | null;
899899
};
900900
};
901901
};

packages/open-payments/src/types.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,18 @@ export const getASPath = <P extends keyof ASPaths>(path: P): string =>
8585
path as string
8686

8787
export type Subject = ASComponents['schemas']['subject']
88+
export type Client =
89+
| string
90+
| { walletAddress: string; jwk?: never }
91+
| { jwk: JWK; walletAddress?: never }
8892

8993
export type NonInteractiveGrantRequest = {
9094
access_token: ASOperations['post-request']['requestBody']['content']['application/json']['access_token']
91-
client: ASOperations['post-request']['requestBody']['content']['application/json']['client']
95+
client: Client
9296
}
9397

9498
type BaseGrantRequest = {
95-
client: ASOperations['post-request']['requestBody']['content']['application/json']['client']
99+
client: Client
96100
interact?: ASOperations['post-request']['requestBody']['content']['application/json']['interact']
97101
}
98102

@@ -113,6 +117,12 @@ export type Grant = {
113117
continue: ASComponents['schemas']['continue']
114118
subject?: Subject
115119
}
120+
export type GrantWithAccessToken = Grant & {
121+
access_token: NonNullable<Grant['access_token']>
122+
}
123+
export type GrantWithSubject = Grant & {
124+
subject: NonNullable<Grant['subject']>
125+
}
116126
export type GrantContinuation = {
117127
continue: ASComponents['schemas']['continue']
118128
}
@@ -145,12 +155,11 @@ export const isFinalizedGrant = (
145155

146156
export const isFinalizedGrantWithAccessToken = (
147157
grant: GrantContinuation | Grant
148-
): grant is Grant & { access_token: ASComponents['schemas']['access_token'] } =>
149-
!!(grant as Grant).access_token
158+
): grant is GrantWithAccessToken => !!(grant as Grant).access_token
150159

151160
export const isFinalizedGrantWithSubject = (
152161
grant: GrantContinuation | Grant
153-
): grant is Grant & { subject: Subject } => !!(grant as Grant).subject
162+
): grant is GrantWithSubject => !!(grant as Grant).subject
154163

155164
export type AccessIncomingActions =
156165
ASComponents['schemas']['access-incoming']['actions']

0 commit comments

Comments
 (0)