Skip to content
This repository has been archived by the owner on Oct 2, 2024. It is now read-only.

Commit

Permalink
fix: Fix getting client_id from registration object if present. fixes #…
Browse files Browse the repository at this point in the history
  • Loading branch information
nklomp committed May 17, 2023
1 parent b679950 commit c08e4a0
Show file tree
Hide file tree
Showing 10 changed files with 122 additions and 32 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
The DID Auth SIOP typescript library is still in an alpha state at this point. Please note that the interfaces might
still change a bit as the software still is in active development.

## v0.3.1 - 2023-05-17
Bugfix release, fixing RPBuilder export and a client_id bug when not explicitly provided to the RP.

- Fixed:
- Changed RPBuilder default export to a named export
- Fix #54. The client_id took the whole registration object, instead of the client_id in case it was not provided explicitly
- Updated:
- SSI-types have been updated to the latest version.


## v0.3.0 - 2023-04-30

This release contains many breaking changes. Sorry for these, but this library still is in active development, as
Expand Down
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,9 @@ This is either a top-level vp_token or it becomes part of the id_token.
````typescript

// The relying party (web) private key and DID and DID key (public key)
import { SigningAlgo } from './SIOP.types';
import { SigningAlgo } from '@sphereon/did-auth-siop';

const EXAMPLE_REDIRECT_URL = 'https://acme.com/hello';
const rpKeys = {
hexPrivateKey: 'a1458fac9ea502099f40be363ad3144d6d509aa5aa3d17158a9e6c3b67eb0397',
did: 'did:ethr:ropsten:0x028360fb95417724cb7dd2ff217b15d6f17fc45e0ffc1b3dce6c2b8dd1e704fa98',
Expand Down Expand Up @@ -337,7 +338,7 @@ of the payload (by value).

````typescript
// The OpenID Provider (client) private key and DID and DID key (public key)
import { SigningAlgo } from './SIOP.types';
import { SigningAlgo } from '@sphereon/did-auth-siop';

const opKeys = {
hexPrivateKey: '88a62d50de38dc22f5b4e7cc80d68a0f421ea489dda0e3bd5c165f08ce46e666',
Expand Down Expand Up @@ -383,15 +384,16 @@ already configured the RP itself to have a Presentation Definition, so we can om
class will take care of that on every Auth Request creation.

````typescript
const reqURI = await rp.createAuthorizationRequest({
nonce: "qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg",
state: "b32f0087fc9816eb813fd11f"
const authRequest = await rp.createAuthorizationRequest({
correlationId: '1',
nonce: 'qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg',
state: 'b32f0087fc9816eb813fd11f',
});

console.log(`nonce: ${reqURI.requestOpts.nonce}, state: ${reqURI.requestOpts.state}`);
console.log(`nonce: ${authRequest.requestOpts.nonce}, state: ${authRequest.requestOpts.state}`);
// nonce: qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg, state: b32f0087fc9816eb813fd11f

console.log(reqURI.encodedUri)
console.log(await authRequest.uri().then(uri => uri.encodedUri))
// openid://?response_type=id_token&scope=openid&client_id=did.......&jwt=ey..........
````

Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sphereon/did-auth-siop",
"version": "0.3.1-unstable.0",
"version": "0.3.1-unstable.1",
"source": "src/index.ts",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -31,9 +31,9 @@
"@sphereon/did-uni-client": "^0.6.0",
"@sphereon/pex": "^2.0.1",
"@sphereon/pex-models": "^2.0.2",
"@sphereon/ssi-types": "^0.10.0",
"@sphereon/ssi-types": "^0.11.0",
"@sphereon/wellknown-dids-client": "^0.1.3",
"cross-fetch": "^3.1.5",
"cross-fetch": "^3.1.6",
"did-jwt": "^6.11.6",
"did-resolver": "^4.1.0",
"events": "^3.3.0",
Expand All @@ -52,6 +52,7 @@
"@digitalcredentials/ed25519-signature-2020": "^3.0.2",
"@digitalcredentials/jsonld-signatures": "^9.3.1",
"@digitalcredentials/vc": "^5.0.0",
"@types/uuid": "^9.0.1",
"@types/jest": "^29.4.0",
"@types/language-tags": "^1.0.1",
"@typescript-eslint/eslint-plugin": "^5.52.0",
Expand Down
18 changes: 4 additions & 14 deletions src/authorization-request/Payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,13 @@ export const createAuthorizationRequestPayload = async (
requestObject?: RequestObject
): Promise<AuthorizationRequestPayload> => {
const payload = opts.payload;
// const mergedPayload = { ...opts.payload, ...opts?.requestObject?.payload };
const state = payload?.state ?? undefined;
const nonce = payload?.nonce ? getNonce(state, payload.nonce) : undefined;
// TODO: if opts['registration] throw Error to get rid of test code using that key
const clientMetadata = opts['registration'] ? opts['registration'] : (opts.clientMetadata as ClientMetadataOpts);
const registration = await createRequestRegistration(clientMetadata, opts);
const claims =
opts.version >= SupportedVersion.SIOPv2_ID1 ? opts.payload.claims : createPresentationDefinitionClaimsProperties(opts.payload.claims);
// let clientId = mergedPayload.client_id;
//
// const metadataKey = opts.version >= SupportedVersion.SIOPv2_D11.valueOf() ? 'client_metadata' : 'registration';
/*if (!clientId) {
clientId = registration.payload[metadataKey].client_id;
}*/
const isRequestTarget = isTargetOrNoTargets(PropertyTarget.AUTHORIZATION_REQUEST, opts.requestObject.targets);
const isRequestByValue = opts.requestObject.passBy === PassBy.VALUE;

Expand All @@ -73,15 +66,12 @@ export const createAuthorizationRequestPayload = async (
...payload,
//TODO implement /.well-known/openid-federation support in the OP side to resolve the client_id (URL) and retrieve the metadata
...(isRequestTarget && opts.requestObject.passBy === PassBy.REFERENCE ? { request_uri: opts.requestObject.reference_uri } : {}),
...(isRequestTarget && isRequestByValue ? { request } : {}),
...(nonce ? { nonce } : {}),
...(state ? { state } : {}),
...(isRequestTarget && isRequestByValue && { request }),
...(nonce && { nonce }),
...(state && { state }),
...(registration.payload && isTarget(PropertyTarget.AUTHORIZATION_REQUEST, registration.clientMetadataOpts.targets) ? registration.payload : {}),
...(claims ? { claims } : {}),
...(claims && { claims }),
};
/*if ((payload.registration || payload.client_metadata) && registration.payload) {
authRequestPayload[metadataKey] = { ...registration.payload };
}*/

return removeNullUndefined(authRequestPayload);
};
Expand Down
13 changes: 8 additions & 5 deletions src/request-object/Payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ export const createRequestObjectPayload = async (opts: CreateAuthorizationReques

const metadataKey = opts.version >= SupportedVersion.SIOPv2_D11.valueOf() ? 'client_metadata' : 'registration';
if (!clientId) {
clientId = registration.payload[metadataKey];
clientId = registration.payload[metadataKey]?.client_id;
}
if (!clientId && !opts.requestObject.signature.did) {
throw Error('Please provide a clientId for the RP');
}

const now = Math.round(new Date().getTime() / 1000);
Expand All @@ -38,11 +41,11 @@ export const createRequestObjectPayload = async (opts: CreateAuthorizationReques
response_type: payload.response_type ?? ResponseType.ID_TOKEN,
scope: payload.scope ?? Scope.OPENID,
//TODO implement /.well-known/openid-federation support in the OP side to resolve the client_id (URL) and retrieve the metadata
client_id: clientId ? clientId : opts.requestObject.signature.did,
client_id: clientId ?? opts.requestObject.signature.did,
redirect_uri: payload.redirect_uri,
response_mode: payload.response_mode || ResponseMode.POST,
...(payload.id_token_hint ? { id_token_hint: payload.id_token_hint } : {}),
registration_uri: registration.clientMetadataOpts.reference_uri, //requestObjectOpts['registrationUri'],
response_mode: payload.response_mode ?? ResponseMode.POST,
...(payload.id_token_hint && { id_token_hint: payload.id_token_hint }),
registration_uri: registration.clientMetadataOpts.reference_uri,
nonce: getNonce(state, payload.nonce),
state,
...registration.payload,
Expand Down
2 changes: 1 addition & 1 deletion src/rp/Opts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { getResolverUnion, mergeAllDidMethods } from '../did';
// import { CreateAuthorizationRequestOptsSchema } from '../schemas';
import { ClientMetadataOpts, InternalVerification, RequestObjectPayload, SIOPErrors, VerificationMode } from '../types';

import RPBuilder from './RPBuilder';
import { RPBuilder } from './RPBuilder';

export const createRequestOptsFromBuilderOrExistingOpts = (opts: { builder?: RPBuilder; createRequestOpts?: CreateAuthorizationRequestOpts }) => {
const version = opts.builder ? opts.builder.getSupportedRequestVersion() : opts.createRequestOpts.version;
Expand Down
2 changes: 1 addition & 1 deletion src/rp/RP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
} from '../types';

import { createRequestOptsFromBuilderOrExistingOpts, createVerifyResponseOptsFromBuilderOrExistingOpts, isTargetOrNoTargets } from './Opts';
import RPBuilder from './RPBuilder';
import { RPBuilder } from './RPBuilder';
import { IRPSessionManager } from './types';

export class RP {
Expand Down
2 changes: 1 addition & 1 deletion src/rp/RPBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { assignIfAuth, assignIfRequestObject, isTarget, isTargetOrNoTargets } fr
import { RP } from './RP';
import { IRPSessionManager } from './types';

export default class RPBuilder {
export class RPBuilder {
resolvers: Map<string, Resolvable> = new Map<string, Resolvable>();
customResolver?: Resolvable;
requestObjectBy: ObjectBy;
Expand Down
58 changes: 58 additions & 0 deletions test/regressions/ClientIdIsObject.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { PassBy, ResponseType, RevocationVerification, RP, Scope, SigningAlgo, SubjectType, SupportedVersion } from '../../src';

const EXAMPLE_REDIRECT_URL = 'https://acme.com/hello';
// const EXAMPLE_REFERENCE_URL = 'https://rp.acme.com/siop/jwts';
const HEX_KEY = 'f857544a9d1097e242ff0b287a7e6e90f19cf973efe2317f2a4678739664420f';
const DID = 'did:ethr:0x0106a2e985b1E1De9B5ddb4aF6dC9e928F4e99D0';
const KID = 'did:ethr:0x0106a2e985b1E1De9B5ddb4aF6dC9e928F4e99D0#keys-1';

const rp = RP.builder()
// .withClientId('test')
.withRedirectUri(EXAMPLE_REDIRECT_URL)
.withRequestByValue()
.withRevocationVerification(RevocationVerification.NEVER)
.withInternalSignature(HEX_KEY, DID, KID, SigningAlgo.ES256K)
.addDidMethod('ethr')
.addDidMethod('key')
.withSupportedVersions([SupportedVersion.JWT_VC_PRESENTATION_PROFILE_v1])
.withClientMetadata({
idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA],
passBy: PassBy.VALUE,
requestObjectSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256],
responseTypesSupported: [ResponseType.ID_TOKEN],
vpFormatsSupported: { jwt_vc: { alg: [SigningAlgo.EDDSA] } },
scopesSupported: [Scope.OPENID_DIDAUTHN, Scope.OPENID],
subjectTypesSupported: [SubjectType.PAIRWISE],
subject_syntax_types_supported: ['did:ethr:', 'did:key:', 'did'],
})
.withPresentationDefinition({
definition: {
id: '1234-1234-1234-1234',
input_descriptors: [
{
id: 'ExampleInputDescriptor',
schema: [
{
uri: 'https://did.itsourweb.org:3000/smartcredential/Ontario-Health-Insurance-Plan',
},
],
},
],
},
})
.build();

describe('Creating an AuthRequest with an RP from builder', () => {
it('should have a client_id that is a string when not explicitly provided', async () => {
// see: https://github.com/Sphereon-Opensource/SIOP-OID4VP/issues/54
// When not supplying a clientId to the builder, the request object creates an object of the clientId
const authRequest = await rp.createAuthorizationRequest({
correlationId: '1',
nonce: 'qBrR7mqnY3Qr49dAZycPF8FzgE83m6H0c2l0bzP4xSg',
state: 'b32f0087fc9816eb813fd11f',
});

const requestObjectPayload = await authRequest.requestObject.getPayload();
await expect(requestObjectPayload.client_id).toEqual(DID);
});
});
26 changes: 26 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,13 @@
dependencies:
jwt-decode "^3.1.2"

"@sphereon/ssi-types@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@sphereon/ssi-types/-/ssi-types-0.11.0.tgz#ab997fe885acdc4388aff606de16ee5c10b8e53b"
integrity sha512-0ZV/X6J8k7UWmrRE2wo4ZIBq9TFYRd1GLT9nWWqDYnkzdaLUjD3mL0qs5wcTjqupxITCgwQqGrZ5YP9bm8feSA==
dependencies:
jwt-decode "^3.1.2"

"@sphereon/ssi-types@^0.9.0":
version "0.9.0"
resolved "https://registry.yarnpkg.com/@sphereon/ssi-types/-/ssi-types-0.9.0.tgz#d140eb6abd77381926d0da7ac51b3c4b96a31b4b"
Expand Down Expand Up @@ -1444,6 +1451,11 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==

"@types/uuid@^9.0.1":
version "9.0.1"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.1.tgz#98586dc36aee8dacc98cc396dbca8d0429647aa6"
integrity sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==

"@types/yargs-parser@*":
version "21.0.0"
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b"
Expand Down Expand Up @@ -2174,6 +2186,13 @@ cross-fetch@^3.1.5:
dependencies:
node-fetch "2.6.7"

cross-fetch@^3.1.6:
version "3.1.6"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.6.tgz#bae05aa31a4da760969756318feeee6e70f15d6c"
integrity sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==
dependencies:
node-fetch "^2.6.11"

cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
Expand Down Expand Up @@ -4419,6 +4438,13 @@ node-fetch@^2.6.1, node-fetch@^2.6.9:
dependencies:
whatwg-url "^5.0.0"

node-fetch@^2.6.11:
version "2.6.11"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25"
integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==
dependencies:
whatwg-url "^5.0.0"

node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
Expand Down

0 comments on commit c08e4a0

Please sign in to comment.