Skip to content

Commit 105fc37

Browse files
authored
Merge pull request #133 from TimoGlastra/fix/some-fixes
fix: scope and par fixes
2 parents 006d953 + 71e72aa commit 105fc37

3 files changed

Lines changed: 15 additions & 58 deletions

File tree

packages/client/lib/AuthorizationCodeClient.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,16 @@ export const createAuthorizationRequestUrl = async ({
113113
const { redirectUri, requestObjectOpts = { requestObjectMode: CreateRequestObjectMode.NONE } } = authorizationRequest;
114114
const client_id = clientId ?? authorizationRequest.clientId;
115115

116-
let { scope, authorizationDetails } = authorizationRequest;
117-
const parMode = endpointMetadata?.credentialIssuerMetadata?.require_pushed_authorization_requests
116+
// Authorization server metadata takes precedence
117+
const authorizationMetadata = endpointMetadata.authorizationServerMetadata ?? endpointMetadata.credentialIssuerMetadata
118+
119+
let { authorizationDetails } = authorizationRequest;
120+
const parMode = authorizationMetadata?.require_pushed_authorization_requests
118121
? PARMode.REQUIRE
119-
: authorizationRequest.parMode ?? (client_id ? PARMode.AUTO : PARMode.NEVER);
122+
: (authorizationRequest.parMode ?? (client_id ? PARMode.AUTO : PARMode.NEVER));
120123
// Scope and authorization_details can be used in the same authorization request
121124
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rar-23#name-relationship-to-scope-param
122-
if (!scope && !authorizationDetails) {
125+
if (!authorizationRequest.scope && !authorizationDetails) {
123126
if (!credentialOffer) {
124127
throw Error('Please provide a scope or authorization_details if no credential offer is present');
125128
}
@@ -177,12 +180,8 @@ export const createAuthorizationRequestUrl = async ({
177180
if (!endpointMetadata?.authorization_endpoint) {
178181
throw Error('Server metadata does not contain authorization endpoint');
179182
}
180-
const parEndpoint = endpointMetadata.credentialIssuerMetadata?.pushed_authorization_request_endpoint;
183+
const parEndpoint = authorizationMetadata?.pushed_authorization_request_endpoint;
181184

182-
// add 'openid' scope if not present
183-
if (!scope?.includes('openid')) {
184-
scope = ['openid', scope].filter((s) => !!s).join(' ');
185-
}
186185

187186
let queryObj: Record<string, any> | PushedAuthorizationResponse = {
188187
response_type: ResponseType.AUTH_CODE,
@@ -194,7 +193,7 @@ export const createAuthorizationRequestUrl = async ({
194193
...(redirectUri && { redirect_uri: redirectUri }),
195194
...(client_id && { client_id }),
196195
...(credentialOffer?.issuerState && { issuer_state: credentialOffer.issuerState }),
197-
scope,
196+
scope: authorizationRequest.scope,
198197
};
199198

200199
if (!parEndpoint && parMode === PARMode.REQUIRE) {
@@ -210,11 +209,11 @@ export const createAuthorizationRequestUrl = async ({
210209
{ contentType: 'application/x-www-form-urlencoded', accept: 'application/json' },
211210
);
212211
if (parResponse.errorBody || !parResponse.successBody) {
213-
console.log(JSON.stringify(parResponse.errorBody));
214-
console.log('Falling back to regular request URI, since PAR failed');
215212
if (parMode === PARMode.REQUIRE) {
216213
throw Error(`PAR error: ${parResponse.origResponse.statusText}`);
217214
}
215+
216+
debug('Falling back to regular request URI, since PAR failed', JSON.stringify(parResponse.errorBody));
218217
} else {
219218
debug(`PAR response: ${JSON.stringify(parResponse.successBody, null, 2)}`);
220219
queryObj = { /*response_type: ResponseType.AUTH_CODE,*/ client_id, request_uri: parResponse.successBody.request_uri };

packages/client/lib/__tests__/OpenID4VCIClient.spec.ts

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,6 @@ describe('OpenID4VCIClient should', () => {
5959
}),
6060
).rejects.toThrow(Error('Server metadata does not contain authorization endpoint'));
6161
});
62-
it("injects 'openid' as the first scope if not provided", async () => {
63-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
64-
// @ts-ignore
65-
client._state.endpointMetadata?.credentialIssuerMetadata.authorization_endpoint = `${MOCK_URL}v1/auth/authorize`;
66-
67-
const url = await client.createAuthorizationRequestUrl({
68-
pkce: {
69-
codeChallengeMethod: CodeChallengeMethod.S256,
70-
codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs',
71-
},
72-
authorizationRequest: {
73-
scope: 'TestCredential',
74-
redirectUri: 'http://localhost:8881/cb',
75-
},
76-
});
77-
78-
const urlSearchParams = new URLSearchParams(url.split('?')[1]);
79-
const scope = urlSearchParams.get('scope')?.split(' ');
80-
81-
expect(scope?.[0]).toBe('openid');
82-
});
8362
it('throw an error if no scope and no authorization_details is provided', async () => {
8463
nock(MOCK_URL).get(/.*/).reply(200, {});
8564
nock(MOCK_URL).get(WellKnownEndpoints.OAUTH_AS).reply(200, {});
@@ -149,7 +128,7 @@ describe('OpenID4VCIClient should', () => {
149128
},
150129
}),
151130
).resolves.toEqual(
152-
'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%2C%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22mso_mdoc%22%2C%22doctype%22%3A%22org%2Eiso%2E18013%2E5%2E1%2EmDL%22%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%5D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client&scope=openid',
131+
'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%2C%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22mso_mdoc%22%2C%22doctype%22%3A%22org%2Eiso%2E18013%2E5%2E1%2EmDL%22%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%5D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client',
153132
);
154133
});
155134
it('create an authorization request url with authorization_details object property', async () => {
@@ -176,7 +155,7 @@ describe('OpenID4VCIClient should', () => {
176155
},
177156
}),
178157
).resolves.toEqual(
179-
'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client&scope=openid',
158+
'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client',
180159
);
181160
});
182161

packages/client/lib/__tests__/OpenID4VCIClientV1_0_13.spec.ts

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -51,27 +51,6 @@ describe('OpenID4VCIClientV1_0_13 should', () => {
5151
}),
5252
).rejects.toThrow(Error('Server metadata does not contain authorization endpoint'));
5353
});
54-
it("injects 'openid' as the first scope if not provided", async () => {
55-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
56-
// @ts-ignore
57-
client._state.endpointMetadata?.credentialIssuerMetadata.authorization_endpoint = `${MOCK_URL}v1/auth/authorize`;
58-
59-
const url = await client.createAuthorizationRequestUrl({
60-
pkce: {
61-
codeChallengeMethod: CodeChallengeMethod.S256,
62-
codeChallenge: 'mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs',
63-
},
64-
authorizationRequest: {
65-
scope: 'TestCredential',
66-
redirectUri: 'http://localhost:8881/cb',
67-
},
68-
});
69-
70-
const urlSearchParams = new URLSearchParams(url.split('?')[1]);
71-
const scope = urlSearchParams.get('scope')?.split(' ');
72-
73-
expect(scope?.[0]).toBe('openid');
74-
});
7554
it('throw an error if no scope and no authorization_details is provided', async () => {
7655
nock(MOCK_URL).get(/.*/).reply(200, {});
7756
nock(MOCK_URL).get(WellKnownEndpoints.OAUTH_AS).reply(200, {});
@@ -141,7 +120,7 @@ describe('OpenID4VCIClientV1_0_13 should', () => {
141120
},
142121
}),
143122
).resolves.toEqual(
144-
'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%2C%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22mso_mdoc%22%2C%22doctype%22%3A%22org%2Eiso%2E18013%2E5%2E1%2EmDL%22%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%5D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client&scope=openid',
123+
'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%5B%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%2C%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22mso_mdoc%22%2C%22doctype%22%3A%22org%2Eiso%2E18013%2E5%2E1%2EmDL%22%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D%5D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client',
145124
);
146125
});
147126
it('create an authorization request url with authorization_details object property', async () => {
@@ -168,7 +147,7 @@ describe('OpenID4VCIClientV1_0_13 should', () => {
168147
},
169148
}),
170149
).resolves.toEqual(
171-
'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client&scope=openid',
150+
'https://server.example.com/v1/auth/authorize?response_type=code&code_challenge_method=S256&code_challenge=mE2kPHmIprOqtkaYmESWj35yz-PB5vzdiSu0tAZ8sqs&authorization_details=%7B%22type%22%3A%22openid_credential%22%2C%22format%22%3A%22ldp_vc%22%2C%22credential_definition%22%3A%7B%22%40context%22%3A%5B%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fv1%22%2C%22https%3A%2F%2Fwww%2Ew3%2Eorg%2F2018%2Fcredentials%2Fexamples%2Fv1%22%5D%2C%22types%22%3A%5B%22VerifiableCredential%22%2C%22UniversityDegreeCredential%22%5D%7D%2C%22locations%22%3A%5B%22https%3A%2F%2Fserver%2Eexample%2Ecom%22%5D%7D&redirect_uri=http%3A%2F%2Flocalhost%3A8881%2Fcb&client_id=test-client',
172151
);
173152
});
174153

0 commit comments

Comments
 (0)