Skip to content

Commit

Permalink
chore: update logic for response_uri and redirect_uri from options/ar…
Browse files Browse the repository at this point in the history
…guments. Create Mattr E2E test (wip)
  • Loading branch information
nklomp committed Oct 4, 2023
1 parent 00c650b commit f11cb39
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 77 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
"dependencies": {
"@sphereon/did-uni-client": "^0.6.0",
"@sphereon/pex": "2.1.3-unstable.1",
"@sphereon/pex": "2.1.3-unstable.6",
"@sphereon/pex-models": "^2.1.1",
"@sphereon/ssi-types": "^0.17.5",
"@sphereon/wellknown-dids-client": "^0.1.3",
Expand Down
22 changes: 10 additions & 12 deletions src/authorization-request/AuthorizationRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,18 @@ import {
PassBy,
RequestObjectJwt,
RequestObjectPayload,
RequestStateInfo, ResponseURIType,
RequestStateInfo,
ResponseURIType,
RPRegistrationMetadataPayload,
Schema,
SIOPErrors,
SupportedVersion,
VerifiedAuthorizationRequest,
VerifiedJWT
VerifiedJWT,
} from '../types';

import { assertValidAuthorizationRequestOpts, assertValidVerifyAuthorizationRequestOpts } from './Opts';
import {
assertValidRPRegistrationMedataPayload,
checkWellknownDIDFromRequest,
createAuthorizationRequestPayload
} from './Payload';
import { assertValidRPRegistrationMedataPayload, checkWellknownDIDFromRequest, createAuthorizationRequestPayload } from './Payload';
import { URI } from './URI';
import { CreateAuthorizationRequestOpts, VerifyAuthorizationRequestOpts } from './types';

Expand Down Expand Up @@ -60,6 +57,7 @@ export class AuthorizationRequest {
}

public static async fromOpts(opts: CreateAuthorizationRequestOpts, requestObject?: RequestObject): Promise<AuthorizationRequest> {
// todo: response_uri/redirect_uri is not hooked up from opts!
if (!opts || !opts.requestObject) {
throw Error(SIOPErrors.BAD_PARAMS);
}
Expand Down Expand Up @@ -127,7 +125,7 @@ export class AuthorizationRequest {
const options: JWTVerifyOptions = {
...opts.verification?.resolveOpts?.jwtVerifyOpts,
resolver,
audience: getAudience(jwt)
audience: getAudience(jwt),
};

verifiedJwt = await verifyDidJWT(jwt, resolver, options);
Expand Down Expand Up @@ -170,7 +168,7 @@ export class AuthorizationRequest {
} else if (mergedPayload.redirect_uri) {
responseURIType = 'redirect_uri';
responseURI = mergedPayload.redirect_uri;
} else if (mergedPayload.redirect_uri) {
} else if (mergedPayload.response_uri) {
responseURIType = 'response_uri';
responseURI = mergedPayload.response_uri;
} else if (mergedPayload.client_id_scheme === 'redirect_uri' && mergedPayload.client_id) {
Expand Down Expand Up @@ -198,7 +196,7 @@ export class AuthorizationRequest {
registrationMetadataPayload,
requestObject: this.requestObject,
authorizationRequestPayload: this.payload,
versions: await this.getSupportedVersionsFromPayload()
versions: await this.getSupportedVersionsFromPayload(),
};
}

Expand Down Expand Up @@ -238,7 +236,7 @@ export class AuthorizationRequest {
client_id: this.options.clientMetadata.client_id,
iat: requestObject.iat ?? this.payload.iat,
nonce: requestObject.nonce ?? this.payload.nonce,
state: this.payload.state
state: this.payload.state,
};
}

Expand All @@ -253,7 +251,7 @@ export class AuthorizationRequest {
}

public async mergedPayloads(): Promise<RequestObjectPayload> {
return { ...this.payload, ...(await this.requestObject.getPayload()) };
return { ...this.payload, ...(this.requestObject && await this.requestObject.getPayload()) };
}

public async getPresentationDefinitions(version?: SupportedVersion): Promise<PresentationDefinitionWithLocation[] | undefined> {
Expand Down
2 changes: 2 additions & 0 deletions src/authorization-response/PresentationExchange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@ export class PresentationExchange {
const signOptions: VerifiablePresentationFromOpts = {
...options,
proofOptions: {
...options.proofOptions,
proofPurpose: options?.proofOptions?.proofPurpose ?? IProofPurpose.authentication,
type: options?.proofOptions?.type ?? IProofType.EcdsaSecp256k1Signature2019,
challenge: options?.proofOptions?.challenge,
domain: options?.proofOptions?.domain,
},
signatureOptions: {
...options.signatureOptions,
verificationMethod: options?.signatureOptions?.verificationMethod,
keyEncoding: options?.signatureOptions?.keyEncoding ?? KeyEncoding.Hex,
},
Expand Down
6 changes: 4 additions & 2 deletions src/authorization-response/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
NoSignature,
ResponseMode,
ResponseRegistrationOpts,
ResponseURIType,
SuppliedSignature,
SupportedVersion,
VerifiablePresentationWithFormat,
Expand All @@ -19,8 +20,9 @@ import {
import { AuthorizationResponse } from './AuthorizationResponse';

export interface AuthorizationResponseOpts {
redirectUri?: string; // It's typically comes from the request opts as a measure to prevent hijacking.
responseUri?: string; // Alternative to the redirectUri, used when response_mode is `direct_post`
// redirectUri?: string; // It's typically comes from the request opts as a measure to prevent hijacking.
responseURI?: string; // This is either the redirect URI or response URI. See also responseURIType. response URI is used when response_mode is `direct_post`
responseURIType?: ResponseURIType;
registration?: ResponseRegistrationOpts;
checkLinkedDomain?: CheckLinkedDomain;

Expand Down
7 changes: 5 additions & 2 deletions src/op/OP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export class OP {

const payload = response.payload;
const idToken = await response.idToken?.payload();
const responseUri = authorizationResponse.responseURI || idToken?.aud;
const responseUri = authorizationResponse.responseURI ?? idToken?.aud;
if (!responseUri) {
throw Error('No response URI present');
}
Expand Down Expand Up @@ -233,6 +233,7 @@ export class OP {
}
// We are taking the whole presentationExchange object from a certain location
const presentationExchange = opts.presentationExchange ?? this._createResponseOptions.presentationExchange;
const responseURI = opts.audience ?? this._createResponseOptions.responseURI;
return {
...this._createResponseOptions,
...opts,
Expand All @@ -242,7 +243,9 @@ export class OP {
},
...(presentationExchange && { presentationExchange }),
registration: { ...this._createResponseOptions?.registration, issuer },
redirectUri: opts.audience ?? this._createResponseOptions.redirectUri,
responseURI,
responseURIType:
this._createResponseOptions.responseURIType ?? (version < SupportedVersion.SIOPv2_D12_OID4VP_D18 && responseURI ? 'redirect_uri' : undefined),
};
}

Expand Down
4 changes: 3 additions & 1 deletion src/rp/RP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
InternalVerification,
PassBy,
RegisterEventListener,
ResponseURIType,
SIOPErrors,
SupportedVersion,
VerifiedAuthorizationResponse,
Expand Down Expand Up @@ -70,7 +71,8 @@ export class RP {
claims?: ClaimPayloadCommonOpts | RequestPropertyWithTargets<ClaimPayloadCommonOpts>;
version?: SupportedVersion;
requestByReferenceURI?: string;
redirectURI?: string;
redirectURI_TODO_NOT_IMPLEMENTED?: string; // todo: response_uri/redirect_uri is not hooked up from opts!
responseURIType_TODO_NOT_IMEPLEMENTED?: ResponseURIType; // todo: response_uri/redirect_uri is not hooked up from opts!
}): Promise<AuthorizationRequest> {
const authorizationRequestOpts = this.newAuthorizationRequestOpts(opts);
return AuthorizationRequest.fromOpts(authorizationRequestOpts)
Expand Down
13 changes: 10 additions & 3 deletions src/schemas/AuthorizationResponseOpts.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ export const AuthorizationResponseOptsSchemaObj = {
"AuthorizationResponseOpts": {
"type": "object",
"properties": {
"redirectUri": {
"responseURI": {
"type": "string"
},
"responseUri": {
"type": "string"
"responseURIType": {
"$ref": "#/definitions/ResponseURIType"
},
"registration": {
"$ref": "#/definitions/ResponseRegistrationOpts"
Expand Down Expand Up @@ -61,6 +61,13 @@ export const AuthorizationResponseOptsSchemaObj = {
},
"additionalProperties": false
},
"ResponseURIType": {
"type": "string",
"enum": [
"response_uri",
"redirect_uri"
]
},
"ResponseRegistrationOpts": {
"anyOf": [
{
Expand Down
6 changes: 3 additions & 3 deletions src/types/SIOP.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export interface RequestObjectPayload extends RequestCommonPayload, JWTPayload {
scope: string; // REQUIRED. As specified in Section 3.1.2 of [OpenID.Core].
response_type: ResponseType | string; // REQUIRED. Constant string value id_token.
client_id: string; // REQUIRED. RP's identifier at the Self-Issued OP.
client_id_scheme?: ClientIdScheme // The client_id_scheme enables deployments of this specification to use different mechanisms to obtain and validate metadata of the Verifier beyond the scope of [RFC6749]. The term client_id_scheme is used since the Verifier is acting as an OAuth 2.0 Client.
client_id_scheme?: ClientIdScheme; // The client_id_scheme enables deployments of this specification to use different mechanisms to obtain and validate metadata of the Verifier beyond the scope of [RFC6749]. The term client_id_scheme is used since the Verifier is acting as an OAuth 2.0 Client.
redirect_uri?: string; // REQUIRED before OID4VP v18, now optional because of response_uri. URI to which the Self-Issued OP Response will be sent
response_uri?: string; // New since OID4VP18 OPTIONAL. The Response URI to which the Wallet MUST send the Authorization Response using an HTTPS POST request as defined by the Response Mode direct_post. The Response URI receives all Authorization Response parameters as defined by the respective Response Type. When the response_uri parameter is present, the redirect_uri Authorization Request parameter MUST NOT be present. If the redirect_uri Authorization Request parameter is present when the Response Mode is direct_post, the Wallet MUST return an invalid_request Authorization Response error.
nonce: string;
Expand Down Expand Up @@ -111,10 +111,10 @@ export interface RequestRegistrationPayloadProperties {
registration_uri?: string; // OPTIONAL. This parameter is used by the RP to provide information about itself to a Self-Issued OP that would normally be provided to an OP during Dynamic RP Registration, as specified in 2.2.1.
}

export type ResponseURIType = 'response_uri' | 'redirect_uri'
export type ResponseURIType = 'response_uri' | 'redirect_uri';

export interface VerifiedAuthorizationRequest extends Partial<VerifiedJWT> {
responseURIType: ResponseURIType
responseURIType: ResponseURIType;
responseURI?: string;
clientIdScheme?: string;
correlationId: string;
Expand Down
26 changes: 0 additions & 26 deletions test/AuthenticationRequest.verify.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,29 +442,3 @@ describe('OP and RP communication should', () => {
expect(() => metadata.verify()).toThrowError(SIOPErrors.CREDENTIALS_FORMATS_NOT_PROVIDED);
});
});

describe('Mattr OID4VP v18 credential offer', () => {
test('should verify', async () => {
const authorizationRequest = await AuthorizationRequest.fromUriOrJwt(
'openid4vp://authorize?client_id=https%3A%2F%2Flaunchpad.mattrlabs.com%2Fapi%2Fvp%2Fcallback&client_id_scheme=redirect_uri&response_uri=https%3A%2F%2Flaunchpad.mattrlabs.com%2Fapi%2Fvp%2Fcallback&response_type=vp_token&response_mode=direct_post&presentation_definition_uri=https%3A%2F%2Flaunchpad.mattrlabs.com%2Fapi%2Fvp%2Frequest%3Fstate%3DfzoNJFAU3UeXQuLAsFAyWw&nonce=F-9MSA0Lb0-_MbW4bCzZiA&state=fzoNJFAU3UeXQuLAsFAyWw'
);
console.log(JSON.stringify(authorizationRequest.payload, null, 2));
console.log(JSON.stringify(await authorizationRequest.getSupportedVersionsFromPayload()));

const verification = await authorizationRequest.verify({
correlationId: 'test',
verification: {
mode: VerificationMode.INTERNAL,
resolveOpts: {},
},
});

console.log(JSON.stringify(verification));
expect(verification).toBeDefined();
expect(verification.versions).toEqual([SupportedVersion.SIOPv2_D12_OID4VP_D18]);

/**
* pd value: {"id":"dae5d9b6-8145-4297-99b2-b8fcc5abb5ad","input_descriptors":[{"id":"OpenBadgeCredential","format":{"jwt_vc_json":{"alg":["EdDSA"]},"jwt_vc":{"alg":["EdDSA"]}},"constraints":{"fields":[{"path":["$.vc.type"],"filter":{"type":"array","items":{"type":"string"},"contains":{"const":"OpenBadgeCredential"}}}]}}]}
*/
});
});
15 changes: 10 additions & 5 deletions test/AuthenticationResponse.response.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ const EXAMPLE_REDIRECT_URL = 'https://acme.com/hello';
describe('create JWT from Request JWT should', () => {
const responseOpts: AuthorizationResponseOpts = {
checkLinkedDomain: CheckLinkedDomain.NEVER,
redirectUri: EXAMPLE_REDIRECT_URL,
responseURI: EXAMPLE_REDIRECT_URL,
responseURIType: 'redirect_uri',
responseMode: ResponseMode.POST,
registration: {
authorizationEndpoint: 'www.myauthorizationendpoint.com',
Expand Down Expand Up @@ -163,7 +164,8 @@ describe('create JWT from Request JWT should', () => {
};
const responseOpts: AuthorizationResponseOpts = {
checkLinkedDomain: CheckLinkedDomain.NEVER,
redirectUri: EXAMPLE_REDIRECT_URL,
responseURI: EXAMPLE_REDIRECT_URL,
responseURIType: 'redirect_uri',
registration: {
authorizationEndpoint: 'www.myauthorizationendpoint.com',
idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256],
Expand Down Expand Up @@ -252,7 +254,8 @@ describe('create JWT from Request JWT should', () => {
};
const responseOpts: AuthorizationResponseOpts = {
checkLinkedDomain: CheckLinkedDomain.NEVER,
redirectUri: EXAMPLE_REDIRECT_URL,
responseURI: EXAMPLE_REDIRECT_URL,
responseURIType: 'redirect_uri',
registration: {
authorizationEndpoint: 'www.myauthorizationendpoint.com',
idTokenSigningAlgValuesSupported: [SigningAlgo.EDDSA, SigningAlgo.ES256],
Expand Down Expand Up @@ -413,7 +416,8 @@ describe('create JWT from Request JWT should', () => {
);
const responseOpts: AuthorizationResponseOpts = {
checkLinkedDomain: CheckLinkedDomain.NEVER,
redirectUri: EXAMPLE_REDIRECT_URL,
responseURI: EXAMPLE_REDIRECT_URL,
responseURIType: 'redirect_uri',
registration: {
authorizationEndpoint: 'www.myauthorizationendpoint.com',
issuer: ResponseIss.SELF_ISSUED_V2,
Expand Down Expand Up @@ -586,7 +590,8 @@ describe('create JWT from Request JWT should', () => {
);
const responseOpts: AuthorizationResponseOpts = {
checkLinkedDomain: CheckLinkedDomain.NEVER,
redirectUri: EXAMPLE_REDIRECT_URL,
responseURI: EXAMPLE_REDIRECT_URL,
responseURIType: 'redirect_uri',
registration: {
authorizationEndpoint: 'www.myauthorizationendpoint.com',
issuer: ResponseIss.SELF_ISSUED_V2,
Expand Down
3 changes: 2 additions & 1 deletion test/OP.request.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ describe('OP OPBuilder should', () => {
describe('OP should', () => {
const responseOpts: AuthorizationResponseOpts = {
checkLinkedDomain: CheckLinkedDomain.NEVER,
redirectUri: EXAMPLE_REDIRECT_URL,
responseURI: EXAMPLE_REDIRECT_URL,
responseURIType: 'redirect_uri',
signature: {
hexPrivateKey: HEX_KEY,
did: DID,
Expand Down
Loading

0 comments on commit f11cb39

Please sign in to comment.